Skip to content

Harden the public API, fix Invoke constant arguments, add Use.From - #9

Merged
holonsoftFounder merged 4 commits into
mainfrom
feature/hardening
Sep 11, 2026
Merged

holonsoftFounder merged 4 commits into
mainfrom
feature/hardening

Conversation

@holonsoftFounder

Copy link
Copy Markdown
Member

Summary

  • Argument validation over the public configuration and generation API: ArgumentNullException for null setups, types, expressions, providers, factories and evaluators; ArgumentOutOfRangeException for negative counts in List, Collection, First, Random, Next; ArgumentException with the offending name for unknown properties, fields and methods, non-source types in Use(Type) and non-convention types in Register(Type).
  • All 22 bare throw new InvalidOperationException() carry a message with the type and member they failed at.
  • Bug fix: Invoke(c => c.Method("literal")) in the configuration stored the ConstantExpression itself as the argument. Untested so far, only the generation-time Invoke compiled the lambda. Constants arrive as their value now, captured variables are evaluated once, null is allowed.
  • Use.From(() => value) and Use.From(ctx => ...) as Invoke argument markers, computed per object. Any other method call in the argument list is rejected with a message naming the options.
  • Lambdas receiving the generation context (From, Source, Use.From) take a non-nullable IGenerationContext, so no more ctx!. A FuncSource built from such a lambda throws a clear InvalidOperationException when used outside a session.
  • The never implemented Ctor(...) stub on the generic type builder is removed.
  • GenerateDocumentationFile on, CS1591 suppressed, unresolved cref references fixed. .gitattributes with * text=auto.
  • CI flake fixed: the shared stable sequence helper compared two short random-seed samples for equality of their multiset; for MyTestEnum with ten values and four draws this collides often enough to fail on Windows net9 on main after PR Add generic NumberSource<T> and NullableNumberSource<T> with min/max #5. Bools and enums skip that comparison now.
  • ShouldNotBeEmpty() in front of ShouldAllBe on collections derived from filtering.
  • Not done, on purpose: a non-nullable IGenerationContext in the IDataSource contract itself. Standalone use of a source has no context and the test suite calls Next(null) a few hundred times. The nullable parameter is the honest contract there; the ergonomic pain was in the lambdas, which are fixed.

Test plan

  • 19 new tests: constant, captured variable, null, Use.From per object, Use.From with context, mixed with Use.Source, rejection messages; null and range checks across container, builders, conventions, session, generator, collection and selection; FuncSource without context; error messages carry member names
  • dotnet build -c Release zero warnings with the documentation file on
  • 832 tests green per framework on net8, net9, net10 (Windows)
  • Manual run of a file based app: lambda per object, context lambda, rejection message, null setup

🤖 Generated with Claude Code

christian.vogt@hiquaro.com and others added 4 commits September 9, 2026 14:25
Argument validation over the configuration and generation API
(ArgumentNullException, ArgumentOutOfRangeException for negative counts,
ArgumentException for unknown members, non-source and non-convention types).
Every bare InvalidOperationException carries the type and member it failed at.
Invoke(c => c.Method(...)) in the configuration: constants arrive as their
value (they arrived as the ConstantExpression before, untested), captured
variables are evaluated, null is allowed, Use.From(lambda) and
Use.From(ctx => ...) compute an argument per object, other method calls are
rejected with a message naming the options. Context lambdas (From, Source,
Use.From) get a non-nullable IGenerationContext; a FuncSource built from one
throws a clear message outside of a session. The dead Ctor(...) stub is gone.
GenerateDocumentationFile on with CS1591 suppressed, cref references fixed.
.gitattributes with text=auto. Tests: the shared stable sequence helper skips
the random seed comparison for bools and enums (four draws from ten enum
values reproduced the same multiset on CI), ShouldNotBeEmpty guards in front
of ShouldAllBe on derived collections, 19 new tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
IntegerSource, LongSource, RandomNumberSource and their nullable variants
treated max as exclusive, so new IntegerSource(1, 3) never produced 3 while
NumberSource<T> and the date sources are inclusive on both ends. Int128Source
was worse: it built a value from two non-negative draws and clamped it to the
range, so the default source never produced a negative value and a restricted
range piled up on its bounds.

The uniform inclusive pick of NumberSourceBase moves to
Random.NextInclusive in Util, unchanged, and all four sources share it now.
NumberSource keeps its sequences, the long and Int128 sequences changed, the
integer ones did not (the rejection bound only differs when the top value is
drawn). All four throw ArgumentOutOfRangeException when max is below min.

Also: LongSourceBase.SetMinMax takes long instead of int, it could not reach
the range of its own source before, and Int128IdSource.SetStartValue takes
Int128 instead of long. Both are source compatible.

README gets a breaking changes block at the top of the 6.0 section.

845 tests per framework.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Several sources still have an exclusive user facing maximum (ColorSource,
RandomTextSource, RandomUtfTextSource, and the continuous Decimal/Double/Float
sources), so the README says "every integer and date source" instead of "all
ranges in AutoPoco".

The restricted range test for Int128Source now also asserts that no value takes
half the draws, which is what the old clamping implementation did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The breaking change reads as if the own random generator caused it. It did not:
the per-member seeds did, and StableRandom is insurance against a future .NET
changing the algorithm behind a seeded Random, not a reaction to a bug. A
seeded System.Random is not operating system dependent, that was never the
reason. The one real operating system dependency this library had was the
culture list behind the old CountrySource, fixed in 4.1.3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@holonsoftFounder
holonsoftFounder merged commit b2a0ff0 into main Sep 11, 2026
2 checks passed
@holonsoftFounder
holonsoftFounder deleted the feature/hardening branch September 11, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant