NCrunch seems to be preventing the garbage collection of objects that only have weak references.
Code:
[TestMethod]
public void WeakReferencesCanBeCollected() {
var r = new object();
var w = new WeakReference<object>(r);
r = null;
GC.Collect();
Assert.IsFalse(w.TryGetTarget(out r)); // NCrunch says fails here, but MSTest passes it
}
This also happens when debugging. If I use NCrunch's "Debug covering test" it throws, but if I use visual studio's "Debug test" then it passes.
My best guess is that I'm relying on undefined behavior. The language semantics might not require the garbage collector to clean up everything, despite being asked for a full collection. I'm pretty sure that the debugger prolongs the life of local variables (technically they can be collected after last use, but the debugger keeps them around until the end of their scope [see: GC.KeepAlive]), and maybe something similar is happening.
The reason I want this sort of test is to test for particular runtime optimizations. For example, list.Skip(2).Skip(2) should be optimized into list.Skip(4) and this can be detected from the outside by the collection of the intermediate list. There's a few of these tests in
https://github.com/Strilanc/LinqToCollections .