JustDummies

Just dummies — but seriously powerful ones.

Documentation sections

Errors and conflicts

JustDummies would rather refuse loudly than return a value nobody can explain. This page is about what it refuses, what the exceptions mean, and how to read a message that names both sides of a contradiction.

The exception hierarchy

The library’s exception hierarchyDummyException is abstract and derives from Exception. Three concrete types derive from it. AnyGenerationException, when a draw could not be completed. ConflictingAnyConstraintException, when the constraints admit no value. UnsupportedRegexException, when the pattern falls outside the regular subset.ExceptionDummyExceptionabstract the library’s rootAnyGenerationExceptiona draw could not becompletedConflictingAnyConstraintExceptionthe constraints admit novalueUnsupportedRegexExceptionthe pattern is outside theregular subset

DummyException is abstract, so catching it catches everything this library throws and nothing else:

try {
    int impossible = Any.Int32().Between(1, 10).MultipleOf(50).Generate();
} catch (DummyException exception) {
    Console.Error.WriteLine(exception.Message);
}

Ordinary argument mistakes are not in that hierarchy. Passing null where a generator is required, or a negative length, throws the usual ArgumentNullException / ArgumentException — those are bugs in the calling code, not statements about a constraint set.

ConflictingAnyConstraintException: the constraints admit no value

This is the one you will meet most, and it is a feature rather than a defect. Because values are built to satisfy the whole specification rather than drawn and filtered, a specification satisfying nothing is detected instead of looped over:

// No integer is both above 100 and below 10.
int impossible = Any.Int32().GreaterThan(100).LessThan(10).Generate();

The message names both sides of the conflict. That is a product guarantee, not an accident of how the exception happened to be worded: a message saying only “no value is possible” would leave you re-reading a twelve-call chain to find which two calls disagree.

Conflicts come in a few recognisable shapes:

ShapeExample
bounds that cross.GreaterThan(100).LessThan(10)
a lattice with no point in range.Between(1, 10).MultipleOf(50)
exclusions that empty the domainAny.Boolean().Except(true, false)
a length that cannot hold the fragments.StartingWith("ORDER-").WithLength(3)
a count no element pool can fill100 distinct values from a pool of three

Caught at compile time instead

Many of those chains are decidable from constants the compiler can already see, and the analyzers shipped in the package report them before the test ever runs. That is the difference between a red build and a red test at 3 a.m.:

RuleCatches
JD014a constant argument the generator’s own guard refuses
JD015a string chain that throws: fragments too long, or a value set a constraint empties
JD016collection counts that cannot all hold
JD017an enum constraint stepping outside the declared members
JD023an integer chain narrowed to nothing
JD024a constraint that narrows nothing at all

The run-time checks stay in place regardless: they cover every argument an analyzer cannot see — anything computed, read from a field, or passed in as a parameter.

AnyGenerationException: a draw that could not be completed

A few constraints cannot be honoured by construction. Excluding values from a continuous range, matching a regular expression, and filling a collection with distinct elements all end in the same place: draw a candidate, check it, and try again if it does not fit.

Left unbounded, that is a loop that may never end. JustDummies bounds it — a fixed number of attempts, then a refusal:

// Two decimal places between 0 and 1 leave 101 candidates; excluding 100 of them leaves one.
decimal[] excluded = Enumerable.Range(0, 100).Select(index => index / 100m).ToArray();

try {
    decimal awkward = Any.Decimal().Between(0m, 1m).WithScale(2).Except(excluded).Generate();
} catch (AnyGenerationException exception) {
    // exception.Seed carries the seed of the run, when one was pinned — so the failure replays.
    Console.Error.WriteLine($"{exception.Message} (seed: {exception.Seed})");
}

AnyGenerationException carries a nullable Seed. When the draw happened inside a reproducible scope, the seed that produced it is on the exception, so a bounded-redraw failure is as replayable as any other failure.

Meeting one usually means the specification is tighter than intended rather than that the library gave up early. Widen the interval, drop an exclusion, or ask for fewer distinct elements.

UnsupportedRegexException: outside the regular subset

Any.StringMatching builds a value from the pattern rather than testing candidates against it, which is why it can guarantee a match. Building requires the pattern to be regular, and the library says so rather than guessing:

try {
    // A back-reference is not a regular construct: no finite automaton can carry it.
    string impossible = Any.StringMatching(@"(\w+)\s\1").Generate();
} catch (UnsupportedRegexException exception) {
    Console.Error.WriteLine(exception.Message);
}

The supported constructs — and the refused ones — are listed in Strings and patterns. The decision to parse a regular subset with the library’s own parser, rather than taking a regex-automaton dependency to widen coverage, is ADR-0008 opens in a new tab.

Symptom, cause, fix

SymptomLikely causeFix
ConflictingAnyConstraintException at the arrange linetwo constraints disagreeread the message — it names both — and drop the one that is not a domain invariant
AnyGenerationException after a pausea bounded redraw exhausted its attemptswiden the domain, or ask for fewer distinct values
UnsupportedRegexExceptionthe pattern uses a non-regular constructrewrite it within the regular subset, or build the string with Any.String() constraints
a value your factory rejectsthe constraints are looser than the factorytighten the constraints until they imply the factory’s contract
a test that passes on rerunthe failing values are gonewrap the body in Any.Reproducibly so the next failure names its seed
a build warning JD0NNa mistake decidable at compile timeopen the rule page linked from the diagnostic

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