Here's what's happening under the hood when you run tests for the core
crate:
- Cargo compiles the
core
crate as a regular library. - Cargo compiles the
testutils
crate as a library, using thecore
library from step 1 as a dependency. - Cargo compiles the
core
crate again withrustc --test
(which produces an executable binary) using thetestutils
library from step 2 as a dependency. - Cargo runs the
core
test 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
core
library from step 1, just like thetestutils
crate does, so both of them will use the same copy of theBuiltinCommand
trait. (However, integration tests can't directly test private code from thecore
library.) -
Instead of a separate crate, include the
testutils
code as a module within both thecore
crate and thecli
crate. Then thetestutils
code will be compiled twice, but it will not introduce any circular dependencies. -
Rewrite the
testutils
crate so it does not depend oncore
. Move code likeimpl core::BuiltinCommand { ... }
into one or both of thecore
orcli
crates. However, this might require duplicating a lot of code.