Code Monkey home page Code Monkey logo

mocktopus's People

Contributors

artemii235 avatar asomers avatar bgluth avatar clinedome avatar codesandwich avatar czipperz avatar gregdhill avatar lnicola avatar n-pochet avatar rye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mocktopus's Issues

Can't return unique objects from closures

Mocktopus closures are FnMuts, from which nothing can be moved out. That makes the following code impossible:

#[derive(Debug, Eq, PartialEq)]
pub struct UniquelyOwned(u32);
#[mockable]
fn foo() -> UniquelyOwned {UniquelyOwned(0)}

let uo = UniquelyOwned(42);
foo.mock_safe(move || {
    MockResult::Return(uo)
});
assert_eq!(UniquelyOwned(42), foo());

There's no way to return a UniquelyOwned object since it's not Clone. Mockers solves this problem by providing a different method to return owned values. Mocktopus could do it do, with a method like mock_once that takes an FnOnce argument instead of an FnMut.

Update docs

  • Warn users about mod foo; injection not working
  • Add tricks: Box::leak, Option::unwrap, Vec::remove(0)

Not able to mock unsafe function

Trying to mock an unsafe function results in an error. Is there any particular reason my unsafe function cannot be mocked?

Minimal test:

    unsafe fn count() -> i32 {
        1
    }

    #[test]
    fn unsafe_test() {
            unsafe {
                count.mock_raw(|| MockResult::Return(0));
                assert_eq!(0, count());
            }

    }

Output:

error[E0599]: no method named `mock_raw` found for type `unsafe fn() -> i32 {test::count}` in the current scope
   --> src\example.rs:10:23
    |
    |                 count.mock_raw(|| MockResult::Return(0));
    |                       ^^^^^^^^
    |
    = note: count is a function, perhaps you wish to call it
    = note: the method `mock_raw` exists but the following trait bounds were not satisfied:
            `unsafe fn() -> i32 {test::count} : mocktopus::mocking::Mockable<_, _>`

Mock `std` functions?

Is it possible to mock standard library functions?

I tried doing something like this but it didn't seem to work:

#[test]
fn mock_current_dir() {
    env::current_dir.mock_safe(|| MockResult::Return(Ok(PathBuf::from("/foo/bar"))));

    let dir = env::current_dir().unwrap();
    assert_eq!(dir, PathBuf::from("/foo/bar"));
}

Can't mock universal types

Take the following example:

#[mockable]
fn call_with_closure(
    num: u32,
    math_op: impl FnOnce(u32) -> u32,
) -> u32 {
    math_op(num)
}

This fails with the following compilation error:

error[E0641]: cannot cast to a pointer of an unknown kind
  --> src/main.rs:21:10
   |
21 |   ) -> u32 {
   |  __________^
22 | |     math_op(num)
23 | | }
   | |_^ needs more type information

cargo test --release SIGILL with newest toolchain.

Toolchain info

nightly-x86_64-unknown-linux-gnu (default)
rustc 1.40.0-nightly (421bd77f4 2019-10-06)

How to reproduce a bug

Run cargo test --release.

Expected result

all tests pass

Actual result:

running 67 tests
test injecting_fn_with_arg_requiring_drop::when_not_mocked_then_runs_normally ... ok
test injecting_fn_with_arg_requiring_drop::when_mocked_then_returns_mock ... ok
test injecting_fn_with_generic_return_type::when_return_type_has_destructor::and_mocked_then_returns_mock ... ok
test injecting_fn_with_generic_return_type::when_return_type_has_destructor::and_not_mocked_then_runs_normally ... error: process didn't exit successfully: `/home/artem/dev/mock/Mocktopus/target/release/deps/injecting-6b1dde59d7e99d97` (signal: 4, SIGILL: illegal instruction)

The SIGILL here is caused by mem::zeroed usage which is UB when used with references:

let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!

Remove lifetime remover

Goal

Remove lifetime remover

Motivation

Lifetime remover is a big boilerplate and actually a dirty hack.

Why is there lifetime remover anyway?

The lifetime remover is needed in cases, where Rust can't reason well enough about lifetimes of generics.

Example:

trait Trait<T> {
    fn method() -> &'static str {
        "method"
    }
    
    fn another() -> &'static str;
}

struct Struct();

impl<'a, T> Trait<&'a T> for Struct {
    fn another() -> &'static str {
        //<Self as Trait<&'a T>>::method()  // FAILS TO COMPILE
        <Self as Trait<&T>>::method()       // COMPILES FINE
    }
}

This is exactly the behavior that is needed in code generated in Mocktopus. It builds full UFC call to trait method of struct with exactly same generics params. Right now copying trait name from impl header Trait<&'a T> and putting it in <Self as Trait<&'a T>>::method() confuses the compiler, it can't find out, that &'a T implies T: 'a and complains, that T may not live as long as 'a. The workaround is to remove lifetimes from generic parameters and make it <Self as Trait<&T>>::method(). It works, because lifetimes are actually dropped during monomorphisation and Rust can prove this statement to be safe.

Solution

If I understand correctly, rust-lang/rust#44493 solves exactly the hole in Rust's lifetime reasoning, which forces Mocktopus to use lifetime remover

Mutable mock closures can cause UB when called recursively

Mutable mock closure can cause UB when it calls recursively the mocked function. Such call makes the same mutable closure being run at the same time with mutable access to its variables. That's enough to cause an UB:

  1. Call mocked function
  2. Inside mock closure take a reference to a closure's variable
  3. Recursively call mocked function
  4. Inside mock closure take a mutable reference to a closure's variable, modify it and return
  5. Reference taken in step 2. now points to invalid data

Mocks closures respect no lifetime constraints

This code compiles causing conversion of &str to &'static str:

#[mockable]
fn terrible(_: &str) -> &'static str {
    "a"
}

#[test]
fn terrible_test() {
    // This closure has type `for <'a> fn(&'a str) -> MockResult<(&'a str,), &'a str>`
    terrible.mock_safe(|a| MockResult::Return(a));
    let x = "abc".to_string();
    let y = x.as_str();
    let z: &'static str = terrible(y);
    assert_eq!("abc", z);
}

Mock closures can have relaxed lifetime constraints

Example:

#[mockable]
fn function(_: &String) -> &'static str {
    "not mocked"
}

#[test]
fn horrible_things() {
    let input = "mocked".to_string();
    function.mock_safe(|i| MockResult::Return(i.as_str()));

    let result: &'static str = function(&input);

    assert_eq!("mocked", result);
}

API change ideas for elegant mocking

Hey,
what do you think of adding a completly new API to improve readability of mockings. I would suggest something like this:

when(namespace::function)
    .expected(times(3))
    .called_with(
        is(equal_to(5)),
        is(none())
    )
    .returns(7);

A call to expected would be optional and defaulting to times(1). Other parameter values could be at(2), al_least(3) etc.

called_with would be a method accepting a hamcrest2 matcher for each parameter. Internal we could simply test these with assert_that!(expected_value, <matcher>). This method call would also be optional, defaulting to empty parameter list.

returns will simply specify, what the function returns. Alternatively runs_original() will delegate the call to the original implementation.

The only thing what I need to call this a full mocking library would be the ability to mock the behavior for struct instances, like:

struct Struct(u8);

#[mockable]
impl Struct {
    fn get(&self) -> u8 {
        self.0
    }
}

fn test() {
    let a = Struct(1);
    let b = Struct(2);

    when(Struct::get).on(&a).returns(10);

    assert_that!(a.get(), is(equal_to(10)));
    assert_that!(b.get(), is(equal_to(2)));
}

It would be a nice feature to be able to configure (via parameter, function call, etc) if calls not specified in expected raise an error and let the test fail, like:

#[mockable]
fn function(a: u32) -> u32 {
    a
}

#[test]
fn test() {
    // order of mocks matter: at first call param is 1, at second param is 2
    when(function)
        .called_with(is(equal_to(1)))
        .returns(5);
    when(function)
        .called_with(is(equal_to(2)))
        .returns(7);
        
    // something like this, to specify mock type
    fail_on_unmocked_calls(function);

    assert_that!(function(1), is(equal_to(5)));
    assert_that!(function(2), is(equal_to(7)));
    
    // following call should let the tast fail
    assert_that!(function(3), is(equal_to(3)));
}

For struct instances, you could specify with anything like the following, where the test would fail on any call to a method of that struct instance.

let a = Struct(1);
fail_on_unmocked_calls(&a);

These are just some ideas inspired by Mockito, PHPUnit and similar mocking libraries. What do you think of it? Would it be something you want to add in this crate?

I would love to help and contribute to your project if so.

Errors in mock injected code are correctly pointed by compiler

Currently when compiler finds an error in mock injected code, it prints a message pointing to the injection annotation:

error[E0106]: missing lifetime specifier
 --> tests/mocking_regular_functions.rs:6:1
  |
6 | #[inject_mocks]
  | ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
  = help: consider giving it a 'static lifetime

Expected behavior of compiler is pointing to place, where the error actually occurs.

Blocked until Syn 0.12: dtolnay/syn#178

Documentation

In-code Rust docs, explanatory comments, readme.md

Tools for managing mock state

Add tools for convenient storage and verification of mock state, e.g. call count, list of responses or last call arguments

Consider renaming mock_safe to mock

Generally speaking, safe operations have no suffix, while their unsafe counterparts have _unchecked, _unsafe, or _raw like mock_raw does. So, I think it would be more ergonomic to switch all mock_safe to mock for the next breaking version bump.

Not able to mock impl Future function

Hi! I'm new to Mocktopus.
I found that I can't mock impl Future functions due to type mismatch.

My code:

#[cfg(test)]
use mocktopus::macros::*;
use mocktopus::mocking::*;

use futures::prelude::*;
use futures::{future, Future};
use futures::executor::{block_on};

fn main() {
    println!("Hello, world!");
}

#[mockable]
pub fn future() -> impl Future<Output=i32> {
    future::ready(1)
}

#[test]
fn mock_test() {
    future.mock_safe(|| MockResult::Return(future::ready(2)));
    assert_eq!(2, block_on(future()));
}

dependencies in Cargo.toml:

[dependencies]
futures = "0.3"

[dev-dependencies]
mocktopus = "0.7.0"

toolchain:

nightly-x86_64-apple-darwin unchanged - rustc 1.41.0-nightly (797fd9262 2019-11-26)

error:

error[E0308]: mismatched types
  --> src/main.rs:20:44
   |
20 |     future.mock_safe(|| MockResult::Return(future::ready(2)));
   |                                            ^^^^^^^^^^^^^^^^ expected opaque type, found struct `futures_util::future::ready::Ready`
   |
   = note: expected opaque type `impl core::future::future::Future`
                   found struct `futures_util::future::ready::Ready<{integer}>`

error: aborting due to previous error

Any ideas?

Async method taking a reference as first parameter fails

Similar to #61, but when the reference parameter is the first parameter I see the same complier error when running tests.

Adding a lifetime works when there is only one reference parameter, but not when there are multiple.

Examples:

// Fails when mockable - error[E0621]: explicit lifetime required in the type of `p1`
// #[cfg_attr(test, mockable)]
pub async fn ref_first(p1: &str) {}

#[cfg_attr(test, mockable)]
pub async fn ref_first_with_lifetime<'a>(p1: &'a str) {}

#[cfg_attr(test, mockable)]
pub async fn ref_second(p1: String, p2: &str)  {}

// Fails when mockable - error: custom attribute panicked
// #[cfg_attr(test, mockable)]
pub async fn multi_ref_first_with_lifetime<'a>(p1: &'a str, p2: &'a str) {}

#[cfg_attr(test, mockable)]
pub async fn multi_ref_second(p1: String, p2: &str, p3: &str) {}

Using mocktopus = "0.7.10"

Async method taking a reference argument fails to compile

I have this minimal example:

#[cfg(test)]
use mocktopus::macros::*;
pub struct Foo { }
#[cfg_attr(test, mockable)]
impl Foo {
    pub async fn read(&mut self, buf: &mut[u8]) {
        let _ = buf;
    }
}

It builds fine without tests, but fails with tests enabled with:

error[E0621]: explicit lifetime required in the type of `buf`
  --> src/main.rs:13:5
   |
12 |       pub async fn read(&mut self, buf: &mut[u8]) -> ()
   |                                         -------- help: add explicit lifetime `'mocktopus` to the type of `buf`: `&'mocktopus mut [u8]`
13 | /     {
14 | |         let _ = buf;
15 | |     }
   | |_____^ lifetime `'mocktopus` required

Using pub async fn read<'a>(&mut self, buf: &'a mut[u8]) instead silences the error. I have no idea if it's a good workaround.

investigate multithreaded mocks

Mocks taking effect in every thread during test runtime. Probably should block other test runs, preferably only multithreaded

Link half-broken

/// Note: methods have any effect only if called on functions [annotated as mockable](https://docs.rs/mocktopus_macros).

This link leads to a page with a banner "mocktopus_macros-0.7.5 doesn't have any documentation." Probably is was meant to point to something else.

Compilation failure with latest nightly

There seems to be a regression with latest nightly.

$> cargo test
[...]
   Compiling mocktopus v0.7.11
error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
   --> /home/tobhap/.cargo/registry/src/github.com-1ecc6299db9ec823/mocktopus-0.7.11/src/mocking.rs:100:25
    |
100 | impl<T, O, F: FnOnce<T, Output = O>> Mockable<T, O> for F {
    |                         ^^^^^^^^^^ the trait `Tuple` is not implemented for `T`
    |
note: required by a bound in `FnOnce`
help: consider restricting type parameter `T`
    |
100 | impl<T: std::marker::Tuple, O, F: FnOnce<T, Output = O>> Mockable<T, O> for F {
    |       ++++++++++++++++++++

error[E0059]: type parameter to bare `FnMut` trait must be a tuple
   --> /home/tobhap/.cargo/registry/src/github.com-1ecc6299db9ec823/mocktopus-0.7.11/src/mocking.rs:192:12
    |
192 |         M: FnMut<I, Output = MockResult<I, O>> + 'a,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `I`
    |
note: required by a bound in `FnMut`
help: consider further restricting type parameter `I`
    |
192 |         M: FnMut<I, Output = MockResult<I, O>> + 'a, I: std::marker::Tuple
    |                                                    ~~~~~~~~~~~~~~~~~~~~~~~

error[E0059]: type parameter to bare `FnMut` trait must be a tuple
   --> /home/tobhap/.cargo/registry/src/github.com-1ecc6299db9ec823/mocktopus-0.7.11/src/mocking.rs:204:12
    |
204 |         M: FnMut<I, Output = MockResult<I, O>>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `I`
    |
note: required by a bound in `FnMut`
help: consider further restricting type parameter `I`
    |
204 |         M: FnMut<I, Output = MockResult<I, O>>, I: std::marker::Tuple
    |                                               ~~~~~~~~~~~~~~~~~~~~~~~

error[E0059]: type parameter to bare `FnMut` trait must be a tuple
  --> /home/tobhap/.cargo/registry/src/github.com-1ecc6299db9ec823/mocktopus-0.7.11/src/mocking.rs:45:27
   |
45 |     unsafe fn mock_raw<M: FnMut<T, Output = MockResult<T, O>>>(&self, mock: M);
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `T`
   |
note: required by a bound in `FnMut`
help: consider restricting type parameter `T`
   |
11 | pub trait Mockable<T: std::marker::Tuple, O> {
   |                     ++++++++++++++++++++

error[E0059]: type parameter to bare `FnMut` trait must be a tuple
  --> /home/tobhap/.cargo/registry/src/github.com-1ecc6299db9ec823/mocktopus-0.7.11/src/mocking.rs:65:21
   |
65 |     fn mock_safe<M: FnMut<T, Output = MockResult<T, O>> + 'static>(&self, mock: M);
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `T`
   |
note: required by a bound in `FnMut`
help: consider restricting type parameter `T`
   |
11 | pub trait Mockable<T: std::marker::Tuple, O> {
   |                     ++++++++++++++++++++

For more information about this error, try `rustc --explain E0059`.
error: could not compile `mocktopus` due to 5 previous errors
warning: build failed, waiting for other jobs to finish...

$> rustc --version
rustc 1.67.0-nightly (7eef946fc 2022-11-06)

Mock traits

Mocktopus is very handy for mocking free functions. But when mocking structs, it requires a real copy of the struct to be instantiated. That's not always easy or possible in test environments. That's why most mocking libraries work in terms of traits instead. It would be great if Mocktopus could provide a macro that would instantiate a trait and mock all of its methods. Something like this:

#[mockable]
pub trait A {
    fn foo(&self) -> u32;
}
mock!{AMock, A}

The mock macro could expand to this:

#[derive(Default)]
pub struct AMock {}
#[mockable]
impl AMock {
    fn foo(&self) -> u32 {
        unimplemented!()
    }
}

Add support for generators

It seems that taking generators instead of regular functions could be a vast improvement for mocking flexibility and ergonomics. The user could easily create complex sequences of values by yielding them. The problem is that this API is highly experimental so probably it should be feature-gated, at least for now.

Can't compile after updating to 0.7.11 from 0.7.5

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2089:50
     |
2089 |                 let mut existing_history = match self.load_history_from_file(ctx).compat().await {
     |                                                  ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2094:47
     |
2094 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2107:64
     |
2107 |                 let total_amount = u256_to_big_decimal(amount, self.decimals).unwrap();
     |                                                                ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2114:33
     |
2114 |                 if from_addr == self.my_address {
     |                                 ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2118:31
     |
2118 |                 if to_addr == self.my_address {
     |                               ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2123:31
     |
2123 |                     "coin" => self.ticker.clone(), "client" => "ethereum", "method" => "tx_detail_by_hash");
     |                               ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2125:37
     |
2125 |                 let web3_tx = match self
     |                                     ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2136:47
     |
2136 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2148:31
     |
2148 |                     "coin" => self.ticker.clone(), "client" => "ethereum", "method" => "tx_detail_by_hash");
     |                               ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2155:47
     |
2155 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2162:37
     |
2162 |                 let receipt = match self
     |                                     ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2173:47
     |
2173 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2183:39
     |
2183 |                 let fee_coin = match &self.coin_type {
     |                                       ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2184:41
     |
2184 |                     EthCoinType::Eth => self.ticker(),
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2195:35
     |
2195 |                 let block = match self
     |                                   ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2206:47
     |
2206 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2214:47
     |
2214 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2229:27
     |
2229 |                     coin: self.ticker.clone(),
     |                           ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2249:33
     |
2249 |                 if let Err(e) = self.save_history_to_file(ctx, existing_history).compat().await {
     |                                 ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2252:43
     |
2252 |                         &[&"tx_history", &self.ticker],
     |                                           ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2481:83
     |
2481 |                 mm_counter!(ctx.metrics, "tx.history.request.count", 1, "coin" => self.ticker.clone(), "method" => "tx_detail_by_hash");
     |                                                                                   ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2483:37
     |
2483 |                 let web3_tx = match self
     |                                     ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2494:47
     |
2494 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2509:47
     |
2509 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2516:84
     |
2516 |                 mm_counter!(ctx.metrics, "tx.history.response.count", 1, "coin" => self.ticker.clone(), "method" => "tx_detail_by_hash");
     |                                                                                    ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2518:37
     |
2518 |                 let receipt = match self
     |                                     ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2529:47
     |
2529 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2539:39
     |
2539 |                 let fee_coin = match &self.coin_type {
     |                                       ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2540:41
     |
2540 |                     EthCoinType::Eth => self.ticker(),
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2555:38
     |
2555 |                 if call_data.from == self.my_address {
     |                                      ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2565:36
     |
2565 |                 if call_data.to == self.my_address {
     |                                    ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2573:35
     |
2573 |                 let block = match self
     |                                   ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2584:47
     |
2584 | ...                   &[&"tx_history", &self.ticker],
     |                                         ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2598:27
     |
2598 |                     coin: self.ticker.clone(),
     |                           ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2619:33
     |
2619 |                 if let Err(e) = self.save_history_to_file(ctx, existing_history.clone()).compat().await {
     |                                 ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0434]: can't capture dynamic environment in a fn item
    --> mm2src/coins/eth.rs:2622:43
     |
2622 |                         &[&"tx_history", &self.ticker],
     |                                           ^^^^
     |
     = help: use the `|| { ... }` closure form instead

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:1964:76
     |
1964 |                         BlockNumber::Number((saved_events.earliest_block - 1).into()),
     |                                                                            ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:1977:25
     |
1977 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:1988:76
     |
1988 |                         BlockNumber::Number((saved_events.earliest_block - 1).into()),
     |                                                                            ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:2001:25
     |
2001 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:2026:74
     |
2026 |                         BlockNumber::Number((saved_events.latest_block + 1).into()),
     |                                                                          ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:2040:25
     |
2040 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:2050:74
     |
2050 |                         BlockNumber::Number((saved_events.latest_block + 1).into()),
     |                                                                          ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:2064:25
     |
2064 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:2414:74
     |
2414 |                         BlockNumber::Number((saved_traces.latest_block + 1).into()),
     |                                                                          ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:2428:25
     |
2428 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
    --> mm2src/coins/eth.rs:2437:74
     |
2437 |                         BlockNumber::Number((saved_traces.latest_block + 1).into()),
     |                                                                          ^ cannot infer type for type `{integer}`
     |
note: the type is part of the `async fn` body because of this `await`
    --> mm2src/coins/eth.rs:2451:25
     |
2451 |                         Timer::sleep(10.).await;
     |                         ^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 42 previous errors

Some errors have detailed explanations: E0434, E0698.
For more information about an error, try `rustc --explain E0434`.
error: could not compile `coins`

To learn more, run the command again with --verbose.

The new version seems to break every existing implementation - furthermore, it's force user to change existing code to suits the mockable behaviour, this is wrong IMHO.

code change: Capture d’écran 2021-10-18 à 14 16 01

(If I move those 2 function into another impl block that doesn't have the macros mockable that make everything compile, but I thought you would like to know that for some complex block there is some problem)

Add way to verify all mocks were called

I do not believe there is a way to verify that all mocks were actually called. Currently the maximum bound is automatically enforced, but the minimum bound is not possible.

Does mocktopus support mocking on method in different crate?

I have 2 creates in my project, base and service, and service crate based on base.
And the code is something like this:

crate base {
   db.rs 
   #[mockable]
  fun get_users()
}

crate service {
  import db;
   fun get_users() -> vec<Users>{
     let db_users = db.get_users();
    if db_users.len() > 0 {
      return db_users;
    } else {
      let users = vec!['a', 'b', 'c']
     return users;
   }
 }
 mod test {
    import db:get_users()
   #[test]
    fun test_get_user{
     let results = Vec::new();
     db.get_users.mock_safe( || MockResult::Return(Ok(results)));
      assert_eq(get_users(),  vec!['a', 'b', 'c']);
    }
   }
}


I expect db.get_users() is not called, but mock result returns, but it actually didn't respect the mock and goes to expect the real db.get_users() code.
Does mocktopus support mocking on method in different crate or I made mistakes?

Thanks a lot

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.