Here's what's happening under the hood when you run tests for the core crate:
- Cargo compiles the
corecrate as a regular library. - Cargo compiles the
testutilscrate as a library, using thecorelibrary from step 1 as a dependency. - Cargo compiles the
corecrate again withrustc --test(which produces an executable binary) using thetestutilslibrary from step 2 as a dependency. - Cargo runs the
coretest binary from step 3.
Notice that the core crate is compiled twice (in steps 1 and 3), and the unit test binary uses both copies of the generated code. This is why Cargo is complaining that you have two different traits endbasic_core::exec::BuiltinCommand and exec::BuiltinCommand.
Some possible solutions, depending on your needs:
-
Change these unit tests into integration tests. Then they will link to the
corelibrary from step 1, just like thetestutilscrate does, so both of them will use the same copy of theBuiltinCommandtrait. (However, integration tests can't directly test private code from thecorelibrary.) -
Instead of a separate crate, include the
testutilscode as a module within both thecorecrate and theclicrate. Then thetestutilscode will be compiled twice, but it will not introduce any circular dependencies. -
Rewrite the
testutilscrate so it does not depend oncore. Move code likeimpl core::BuiltinCommand { ... }into one or both of thecoreorclicrates. However, this might require duplicating a lot of code.