JustDummies

Just dummies — but seriously powerful ones.

Documentation sections

JD011: GeneratorWhereValueExpected

PropertyValue
CategoryUsage (JustDummies.Usage)
Severity🟠 Warning
Enabled by defaultNo — opt-in

Generators are reference types, so an object, dynamic or params object[] position accepts one with no conversion at all. This is the residue ADR-0006 opens in a new tab could not close by removing the implicit conversions: there was nothing to remove here.

The recipe then survives as an opaque object:

  • an assertion helper taking object inspects the recipe — Assert.NotNull(Any.String()) is green for ever and asserts nothing;
  • a theory row built as object[] feeds the generator itself to the code under test;
  • gen.Equals(value) resolves to object.Equals, which is reference equality against an unrelated object: false for every run and every seed.

Enabling it

dotnet_diagnostic.JD011.severity = warning

Noncompliant

Assert.NotNull(Any.String().NonEmpty());          // JD011: asserts the recipe is non-null. It always is.
object[] row = { Any.Int32().Positive(), 1 };     // JD011: the row carries a recipe
bool same = Any.String().NonEmpty().Equals(expected);   // JD011: false, always

Compliant

Assert.NotNull(Any.String().NonEmpty().Generate());
object[] row = { Any.Int32().Positive().Generate(), 1 };
bool same = Any.String().NonEmpty().Generate().Equals(expected);

Why it ships opt-in

ADR-0038 opens in a new tab required this rule’s default to be decided on measurement rather than intuition. Dogfooded across this repository’s suites it produced no true positive and two false ones, both in a convention test that collects generators into a List<object> on purpose — a shape indistinguishable from the theory-row mistake the rule exists to catch, and therefore impossible to narrow away.

That is weak evidence for enabling it everywhere, and good evidence that it belongs in a consumer’s suite, where object-typed assertion helpers are common and reflection over generator instances is not. Enable it there.

What it does not flag

  • A comparison between two generators — ReferenceEquals(original, narrowed) and first.Equals(second). Comparing recipes by identity is how an immutability test proves a constraint returned a new generator; Generate() there would destroy the property under test.
  • Assert.Throws<T>(() => Any.String().WithLength(3)), which binds to Func<object> rather than Action and so produces a real generator-to-object conversion. That shape exists at 88+ sites in this repository alone.
  • A generated value, which is the point.

Read the source, or correct it there opens in a new tab· Mirrored from lib-v1.0.0-preview.6