Skip to content

honour date facet bounds in xsd2inst samples - #133

Merged
pjfanning merged 2 commits into
apache:trunkfrom
pjfanning:sample-date-facets
Oct 5, 2026
Merged

pjfanning merged 2 commits into
apache:trunkfrom
pjfanning:sample-date-facets

Conversation

@pjfanning

Copy link
Copy Markdown
Member

SampleXmlUtil.formatDate ignored min/max facets on every date type except dateTime, and didn't respect them properly on dateTime either.

Why

  • The random seed is a full dateTime. It was compared against the bounds before setBuiltinTypeCode cut it down to the facet's type. For date, time, gYear, gYearMonth, gMonth, gMonthDay and gDay, compareToGDate therefore always returned 2 (incomparable). The min check (>= 0) never matched, so the min branch never ran, and the max check (<= 0) let everything through.
  • When a reset did fire, it added or subtracted 1–8 hours from the random date, not from the bound. So minInclusive 2100-01-01T00:00:00Z produced values like 2014-01-05T11:16:42.000+00:00.
  • The min/max checks also treated an incomparable result (2) inconsistently. The same issue in the validator's min checks is handled in fail min facets on incomparable date and duration values #132.

Fix

  • Cut the seed down to the type and decide its timezone first.
  • Check the seed against all four facets the way validation does, counting an incomparable result as out of range.
  • If the seed misses, try the bound itself (which suits the inclusive facets), then the bound stepped inwards by the smallest unit the type shows (P1Y, P1M, P1D, then PT1H down to PT0.001S for the time types).
  • For partial types (gDay, gMonthDay etc.), fill in the missing fields before doing the arithmetic, then drop them again.

This also replaces the eight near-identical per-type blocks with one facet lookup.

formatDuration clamps field by field and has similar issues, but this PR leaves it alone.

Tests
Xsd2InstTest.testDateSamplesSatisfyTheirBounds generates samples for 12 facet/type combinations and validates each one against its schema. On trunk it fails on the first case. With the fix it passes, and it also passed locally with 2000 iterations per case. ./gradlew test is green.

🤖 Generated with Claude Code

formatDate compared its random seed, a full dateTime, against the bounds
before cutting it down to the facet's type, so for date, time and the
g* types every comparison came back as incomparable and the bounds were
ignored. Where a reset did fire, it moved the random date by a few hours
instead of moving it next to the bound.

Cut the seed down to the type and pick its timezone first, then check it
against all four facets the way validation does, treating an
incomparable result as out of range. If it misses, try the bound itself
and then the bound stepped inwards by the smallest unit the type shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assert the expected cvc-*-valid code rather than only that validation
failed, and compile the schema once for the class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pjfanning
pjfanning merged commit 871c346 into apache:trunk Oct 5, 2026
3 of 5 checks passed
@pjfanning
pjfanning deleted the sample-date-facets branch October 5, 2026 21:28
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