extern crate mocktopus;
mod mocking_fns;
mod mocking_methods;
mod mocking_methods_async;
mod mocking_trait_defaults;
mod mocking_traits;
use mocktopus::macros::*;
use mocktopus::mocking::*;
use mocktopus::mocking_utils::*;
use std::fmt::Display;
mod mock_safe {
use super::*;
#[mockable]
pub fn no_args_returns_str() -> &'static str {
"not mocked"
}
#[test]
fn when_not_mocked_then_returns_not_mocked() {
assert_eq!("not mocked", no_args_returns_str());
}
#[test]
fn when_mocked_then_returns_mocked() {
no_args_returns_str.mock_safe(|| MockResult::Return("mocked"));
assert_eq!("mocked", no_args_returns_str());
}
}
mod mocks_do_not_leak_between_tests {
use super::*;
#[mockable]
pub fn no_args_returns_str() -> &'static str {
"not mocked"
}
macro_rules! generate_tests {
($($fn_name:ident),+) => {
$(
#[test]
fn $fn_name() {
assert_eq!("not mocked", no_args_returns_str(), "function was mocked before mocking");
unsafe {
no_args_returns_str.mock_raw(|| MockResult::Return(stringify!($fn_name)));
}
assert_eq!(stringify!($fn_name), no_args_returns_str(), "mocking failed");
}
)+
}
}
generate_tests!(t00, t01, t02, t03, t04, t05, t06, t07, t08, t09);
generate_tests!(t10, t11, t12, t13, t14, t15, t16, t17, t18, t19);
generate_tests!(t20, t21, t22, t23, t24, t25, t26, t27, t28, t29);
generate_tests!(t30, t31, t32, t33, t34, t35, t36, t37, t38, t39);
generate_tests!(t40, t41, t42, t43, t44, t45, t46, t47, t48, t49);
generate_tests!(t50, t51, t52, t53, t54, t55, t56, t57, t58, t59);
generate_tests!(t60, t61, t62, t63, t64, t65, t66, t67, t68, t69);
generate_tests!(t70, t71, t72, t73, t74, t75, t76, t77, t78, t79);
generate_tests!(t80, t81, t82, t83, t84, t85, t86, t87, t88, t89);
generate_tests!(t90, t91, t92, t93, t94, t95, t96, t97, t98, t99);
}
mod panicking_inside_mock_is_safe {
use super::*;
#[mockable]
fn function(_has_drop: String) {}
#[test]
#[should_panic]
fn uninitialised_string_is_not_dropped() {
function.mock_safe(|_| panic!("inside mock"));
function("initialised".to_string());
}
}
mod mocking_generic_over_a_type_with_lifetime_mocks_all_lifetime_variants {
use super::*;
use std::fmt::Display;
#[mockable]
fn function<T: Display>(generic: T) -> String {
format!("not mocked {}", generic)
}
static STATIC_CHAR: char = 'S';
#[test]
fn all_lifetime_variants_get_mocked() {
unsafe {
function::<&char>.mock_raw(|c| MockResult::Return(format!("mocked {}", c)));
}
let local_char = 'L';
assert_eq!("mocked L", function(&local_char));
assert_eq!("mocked S", function(&STATIC_CHAR));
assert_eq!("not mocked 3", function(&3));
}
}
mod mocking_generic_over_a_reference_does_not_mock_opposite_mutability_variant {
use super::*;
use std::fmt::Display;
#[mockable]
fn function<T: Display>(generic: T) -> String {
format!("not mocked {}", generic)
}
#[test]
fn mocking_for_ref_does_not_mock_for_mut_ref() {
unsafe {
function::<&char>.mock_raw(|c| MockResult::Return(format!("mocked {}", c)));
}
assert_eq!("mocked R", function(&'R'));
assert_eq!("not mocked M", function(&mut 'M'));
}
#[test]
fn mocking_for_mut_ref_does_not_mock_for_ref() {
unsafe {
function::<&mut char>.mock_raw(|c| MockResult::Return(format!("mocked {}", c)));
}
assert_eq!("not mocked R", function(&'R'));
assert_eq!("mocked M", function(&mut 'M'));
}
}
mod mocking_trait_default_for_struct_does_not_mock_same_default_for_another_struct {
use super::*;
#[mockable]
trait Trait {
fn function() -> &'static str {
"not mocked"
}
}
struct Struct1;
impl Trait for Struct1 {}
struct Struct2;
impl Trait for Struct2 {}
#[test]
fn when_not_mocked_then_both_run_normally() {
assert_eq!("not mocked", Struct1::function());
assert_eq!("not mocked", Struct2::function());
}
#[test]
fn when_mocked_for_one_then_runs_mock_for_it_and_runs_normally_for_other() {
unsafe { Struct1::function.mock_raw(|| MockResult::Return("mocked")) }
assert_eq!("mocked", Struct1::function());
assert_eq!("not mocked", Struct2::function());
}
}
mod mock_closures_can_mutate_their_state {
use super::*;
#[mockable]
fn function() -> &'static str {
"not mocked"
}
#[test]
fn when_not_mocked_then_runs_normally() {
assert_eq!("not mocked", function());
}
#[test]
fn when_mocked_then_runs_mocks_with_state() {
let mut x = 0;
function.mock_safe(move || {
x += 1;
match x {
1 => MockResult::Return("first mock"),
_ => MockResult::Return("other mock"),
}
});
assert_eq!("first mock", function());
assert_eq!("other mock", function());
}
}
mod calling_mocked_function_inside_mock_closure {
use super::*;
#[mockable]
fn mockable_1() -> String {
"not mocked 1".to_string()
}
#[mockable]
fn mockable_2() -> String {
"not mocked 2".to_string()
}
fn not_mockable() -> String {
"not mockable".to_string()
}
#[test]
fn when_calling_itself_then_does_not_run_mock() {
let mut first_call = true;
mockable_1.mock_safe(move || match first_call {
true => {
first_call = false;
MockResult::Return(format!("mocked 1 {}", mockable_1()))
}
false => panic!("Mock called second time"),
});
assert_eq!("mocked 1 not mocked 1", mockable_1());
}
#[test]
fn when_calling_not_mocked_function_then_runs_it_normally() {
mockable_1.mock_safe(|| MockResult::Return(format!("mocked 1 {}", mockable_2())));
assert_eq!("mocked 1 not mocked 2", mockable_1());
}
#[test]
fn when_calling_mocked_function_then_runs_its_mock() {
mockable_1.mock_safe(|| MockResult::Return(format!("mocked 1 {}", mockable_2())));
mockable_2.mock_safe(|| MockResult::Return("mocked 2".to_string()));
assert_eq!("mocked 1 mocked 2", mockable_1());
}
#[test]
fn when_calling_not_mockable_function_then_runs_it_normally() {
mockable_1.mock_safe(|| MockResult::Return(format!("mocked 1 {}", not_mockable())));
assert_eq!("mocked 1 not mockable", mockable_1());
}
}
mod creating_mock_inside_mock_closure {
use super::*;
#[mockable]
fn mockable_1() -> String {
"not mocked 1".to_string()
}
#[mockable]
fn mockable_2() -> String {
"not mocked 2".to_string()
}
#[test]
fn when_creating_mock_of_itself_then_registers_mock() {
mockable_1.mock_safe(|| {
mockable_1.mock_safe(|| MockResult::Return("mocked 1B".to_string()));
MockResult::Return("mocked 1A".to_string())
});
assert_eq!("mocked 1A", mockable_1());
assert_eq!("mocked 1B", mockable_1());
}
#[test]
fn when_creating_mock_of_itself_and_calling_itself_then_runs_new_mock() {
mockable_1.mock_safe(|| {
mockable_1.mock_safe(|| MockResult::Return("mocked 1B".to_string()));
MockResult::Return(format!("mocked 1A {}", mockable_1()))
});
assert_eq!("mocked 1A mocked 1B", mockable_1());
}
#[test]
fn when_creating_mock_of_other_function_then_registers_mock() {
mockable_1.mock_safe(|| {
mockable_2.mock_safe(|| MockResult::Return("mocked 2".to_string()));
MockResult::Return("mocked 1".to_string())
});
assert_eq!("not mocked 2", mockable_2());
assert_eq!("mocked 1", mockable_1());
assert_eq!("mocked 2", mockable_2());
}
#[test]
fn when_creating_mock_of_other_function_and_calling_it_then_runs_new_mock() {
mockable_1.mock_safe(|| {
mockable_2.mock_safe(|| MockResult::Return("mocked 2".to_string()));
MockResult::Return(format!("mocked 1 {}", mockable_2()))
});
assert_eq!("mocked 1 mocked 2", mockable_1());
}
}
mod clear_mocks {
use super::*;
#[mockable]
fn mockable_1() -> &'static str {
"not mocked 1"
}
#[mockable]
fn mockable_2() -> &'static str {
"not mocked 2"
}
#[test]
fn when_clearing_mocks_original_function_operations_return() {
mockable_1.mock_safe(|| MockResult::Return("mocked 1"));
assert_eq!("mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
clear_mocks();
assert_eq!("not mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
}
#[test]
fn clearing_mocks_inside_context_clears_all_mocks() {
assert_eq!("not mocked 1", mockable_1());
mockable_1.mock_safe(|| MockResult::Return("mocked 1"));
assert_eq!("mocked 1", mockable_1());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 context"))
.run(|| {
assert_eq!("mocked 1 context", mockable_1());
clear_mocks();
assert_eq!("not mocked 1", mockable_1());
});
assert_eq!("not mocked 1", mockable_1());
}
#[test]
fn clearing_mocks_inside_context_does_not_disrupt_context_cleanup() {
assert_eq!("not mocked 1", mockable_1());
mockable_1.mock_safe(|| MockResult::Return("mocked 1 pre"));
assert_eq!("mocked 1 pre", mockable_1());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 context"))
.run(|| {
assert_eq!("mocked 1 context", mockable_1());
clear_mocks();
assert_eq!("not mocked 1", mockable_1());
mockable_1.mock_safe(|| MockResult::Return("mocked 1 post"));
assert_eq!("mocked 1 post", mockable_1());
});
assert_eq!("mocked 1 post", mockable_1());
}
}
mod clear_mock {
use super::*;
#[mockable]
fn mockable_1() -> &'static str {
"not mocked 1"
}
#[mockable]
fn mockable_2() -> &'static str {
"not mocked 2"
}
#[test]
fn clearing_mocked_deregisters_the_mock() {
mockable_1.mock_safe(|| MockResult::Return("mocked 1"));
mockable_2.mock_safe(|| MockResult::Return("mocked 2"));
assert_eq!("mocked 1", mockable_1());
assert_eq!("mocked 2", mockable_2());
mockable_1.clear_mock();
assert_eq!("not mocked 1", mockable_1());
assert_eq!("mocked 2", mockable_2());
}
#[test]
fn clearing_not_mocked_does_nothing() {
mockable_2.mock_safe(|| MockResult::Return("mocked 2"));
assert_eq!("not mocked 1", mockable_1());
assert_eq!("mocked 2", mockable_2());
mockable_1.clear_mock();
assert_eq!("not mocked 1", mockable_1());
assert_eq!("mocked 2", mockable_2());
}
#[test]
fn clearing_mocks_inside_context_clears_mocks_in_all_contexts() {
assert_eq!("not mocked 1", mockable_1());
mockable_1.mock_safe(|| MockResult::Return("mocked 1"));
assert_eq!("mocked 1", mockable_1());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 context"))
.run(|| {
assert_eq!("mocked 1 context", mockable_1());
mockable_1.clear_mock();
assert_eq!("not mocked 1", mockable_1());
});
assert_eq!("not mocked 1", mockable_1());
}
}
mod mock_context {
use super::*;
#[mockable]
fn mockable_1() -> &'static str {
"not mocked 1"
}
#[mockable]
fn mockable_2() -> &'static str {
"not mocked 2"
}
#[mockable]
fn mockable_string() -> String {
"not mocked".to_string()
}
#[test]
fn context_mocks_mock_only_inside_run_closure() {
assert_eq!("not mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1"))
.run(|| {
assert_eq!("mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
});
assert_eq!("not mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
}
#[test]
fn context_mocks_with_no_mocks_have_no_effect() {
assert_eq!("not mocked 1", mockable_1());
MockContext::new().run(|| {
assert_eq!("not mocked 1", mockable_1());
});
assert_eq!("not mocked 1", mockable_1());
}
#[test]
fn context_mocks_with_multiple_mocks_of_the_same_function_use_only_last_mock() {
assert_eq!("not mocked 1", mockable_1());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 A"))
.mock_safe(mockable_1, || MockResult::Return("mocked 1 B"))
.mock_safe(mockable_1, || MockResult::Return("mocked 1 C"))
.run(|| {
assert_eq!("mocked 1 C", mockable_1());
});
assert_eq!("not mocked 1", mockable_1());
}
#[test]
fn nested_context_mocks_shadow_outside_mocks_only_inside_run_closure() {
assert_eq!("not mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
mockable_1.mock_safe(|| MockResult::Return("mocked 1"));
assert_eq!("mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 context 1"))
.mock_safe(mockable_2, || MockResult::Return("mocked 2 context 1"))
.run(|| {
assert_eq!("mocked 1 context 1", mockable_1());
assert_eq!("mocked 2 context 1", mockable_2());
MockContext::new()
.mock_safe(mockable_1, || MockResult::Return("mocked 1 context 2"))
.run(|| {
assert_eq!("mocked 1 context 2", mockable_1());
assert_eq!("mocked 2 context 1", mockable_2());
});
assert_eq!("mocked 1 context 1", mockable_1());
assert_eq!("mocked 2 context 1", mockable_2());
});
assert_eq!("mocked 1", mockable_1());
assert_eq!("not mocked 2", mockable_2());
}
#[test]
fn calling_function_with_shadowed_mock_from_inside_mock_closure_calls_shadowed_mock() {
assert_eq!("not mocked", mockable_string());
mockable_string.mock_safe(|| MockResult::Return(format!("{}, mocked", mockable_string())));
assert_eq!("not mocked, mocked", mockable_string());
MockContext::new()
.mock_safe(mockable_string, || {
MockResult::Return(format!("{}, mocked context", mockable_string()))
})
.run(|| {
assert_eq!("not mocked, mocked, mocked context", mockable_string());
});
assert_eq!("not mocked, mocked", mockable_string());
}
}