Switching *implementation* on cfg(test)

My attention has just been drawn to this:

impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
    fn clone(&self) -> Self {
    fn clone(&self) -> Self {
        crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter()

which I interpret to mean that the implementation of a fundamental standard feature of the language changes depending on whether it is being used in a test or not. (Please tell me that I've misunderstood!)

Ba ... wha ... errr .... WT actual F ‽

Apologies, words fail me right now.

How can I believe that the tests I write bear any relation to my code's behaviour in production, when implementations (even deep down in the language's infrastructure) get switched between tests and production in this manner?

With my pulse racing a bit less, I can come up with the following rationalization

  • I have to trust that the author of any unsafe code did the right thing
  • Such trust is more justified in standard library code than it is for unsafe code in random crates
  • This particular code is in the standard library, so ...
  • ... this is not entirely unlike trusting unsafe code in the standard library.

[But wow ... given some of the programmers I have had the 'pleasure' of working with, imagining them being aware of this 'technique' fills me with absolute terror!]

The two implementations look like they do exactly the same thing. Here's the reasoning – it's due to a technical detail.


Oh, absolutely. The problem is that painful experience has taught be that two implementations looking like they do the same thing, and actually doing the same thing are not the same thing!

... and one way of increasing confidence is to use automated testing ... but if the automated tests actually (sneakily, behind the scenes) test different things ...

Then they are still better than no tests at all. From what I understand the version that's used outside of tests couldn't be used in #[cfg(test)] mode.

And it's better to have tests for everything else rather then not having an implementation of such fundamental function in #[cfg(test)] mode.

What you wrote is not clear enough to know, unfortunately. Note that, as usual, #[cfg(test)] only affects the crate under discussion. Which means special definition of that clone function is only used for tests of the standard library, not for regular tests in other crates.

You can use cargo careful as explained in Ralf's blog post, but that's separate from regular testing.


One of the good things of using git is that you can blame any file content. Bad this is that it often leads to past myself, but luckily it's not the case here. Here's a rational of this weird splitting. The file OP mentioned was part of this file but was splitted into separate file, without linking to this line unfortunately.

Basically it's a hack to workaround various issues regarding some special cases in libstd, like that liballoc can define methods on typed declared on libcore which is not possible for notmal crates and the libtest is relying on the libstd which happens to prevent said specialty.

In short, slice.to_vec() is not available within liballoc's unit tests due to technical issues so they have to workaround it.

To be clear, the standard library is precompiled and as such couldn’t even in principle be affected by whether your crate is compiled with cfg(test) enabled or not. Neither does it affect the compilation of any of your dependencies.


That's reassuring.

But this applies only in the special case of pre-compiled libraries? Under default circumstances, this is limited to the standard library only?

No, as has been said, none of your dependencies are (re)compiled with cfg(test) when your crate is. Testing is not a separate profile, you don’t see test artifacts under target unlike eg. dev and release.


The only time cfg(test) is set is when compiling the unit-test binary for the crate in question. For tests of all other crates — and even in Cargo integration-tests of the same package — it is always unset. The compiler will not produce an artifact that is both a linkable library and has cfg(test) set.[1]

The standard library is not special in this regard.

  1. Unless you pass --cfg test explicitly, perhaps, but that is not how it's supposed to work and shouldn't be expected to have sensible results. So let's say more precisely: Neither Cargo nor the standard library build process will produce an artifact that is both a linkable library and has cfg(test) set. ↩︎


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.