Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/oracles.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,21 @@ query, nullable query, route value or form field, answers 200 with `null` for th
shape alike. It is registered as one candidate per range type, scoped by the line's `variant minimal TryParse`
prefix so the JSON-body and MVC cells of the same variants stay held.

Route B's step 3 is `LiteralCorpusProbeTests` (integration project, #123): literal corpus × entry point × type,
judged by PostgreSQL's own text input on the same text. The corpus is generated per element kind from the
families `axes.md` lists; the authority is `pg_input_is_valid($1, type)` and the canonical text, asked
for every literal of a type in one statement; the entry points are `Parse` and `TryParse` over a string
and a span, JSON, the `TypeConverter` and the EF Core JSON document reader, plus the EF Core write-back
as a SQL constant and a JSON document, compared on the server as typed values. Its first run turned the
pair's two known cells (#114, #115) into 120 rows over 23 types, reached #117 on the literal path
(`[x,infinity)` loses the last day), and found eight more defects (#126–#133): a
sub-microsecond literal is a different value on each side, integer and array forms PostgreSQL 16 reads
are refused, `GuidSet` follows `Guid.Parse` instead of `uuid_in`, `LocalDateTime` refuses an offset,
`DateTimeOffset` refuses offsets beyond ±14:00, `(,max]` is an undocumented boundary row, and a NUL
character reaches a `text` element. A row the documents name as a refusal (J06, J07), a value outside the
CLR type's domain, and an extreme the store spells `±infinity` are counted, not reported, so the
classification is part of what the class asserts and lives in its `DocumentedRefusal`.

## How to use it

**Run the oracles.** They are ordinary tests; `dotnet test` runs them all. The registered classes are
Expand Down
2 changes: 2 additions & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ Coverage of the arities *as a family* lives in the conventions suite, because it

The literal grammars themselves follow PostgreSQL's `range_in` and `array_in`. `RangeLiteralGrammarContractTests` (conventions) sweeps every range type: only an absent bound is infinite (a quoted `""` or a whitespace-only bound is refused), quotes and backslash escapes work anywhere in a bound, and only ASCII whitespace is skipped. `SetParseFormatTests` pins the array grammar case by case (escapes in unquoted elements, nested braces and stray quotes refused) plus a round-trip sweep over every structural character. `LiteralGrammarParityTests` (integration) hands the same text to PostgreSQL and requires the same answer — refused by both, or the same value. `WrapperGrammarContractTests` (conventions) holds every wrapper arity, closed over a deliberately lenient element and over its representative one, to its primitive sibling's element grammar through every entry point.

`LiteralCorpusProbeTests` (integration, route B's third probe) widens that parity sweep to a corpus and to every entry point. Per element kind it generates the structural families of each grammar (bounds, equal and inverted bounds per bracket pair, `empty` in every case, quoting, escapes, trailing junk, Unicode whitespace, array dimensions and NULLs, multirange canonicalization) and the texts the element input function reads differently (sign, leading zeros, exponents, `NaN`, non-decimal integers, more than 28 digits, `infinity` spellings, `epoch`/`now`/`today`, non-ISO dates, `24:00:00`, offsets, sub-microsecond digits, uuid spellings, NUL), about 100 literals for each of the 48 range, multirange and value set types. The server answers each with `pg_input_is_valid` and its canonical text in one batched statement per type; `Parse(string)`, `Parse(span)`, both `TryParse` overloads, JSON, the `TypeConverter` and the EF Core JSON document reader must all agree with each other and with it, and a value the library reads is written back through EF Core as a SQL constant and as a JSON document and compared with the original on the server as a typed value — which is what sees a precision the parser dropped. A refusal of a value outside the CLR domain, or of a form `docs/serialization.md` names (strict ISO 8601, J07; the `numeric` grammar, J06), is counted rather than reported. The whole sweep takes about five seconds; its known disagreements are candidates keyed `{type} {family} `.

`test/CodoMetis.ValueRanges.AspNetCore.Tests/` runs the host-level behaviour with no ValueRanges registration at all: configuration binding through the `TypeConverter`, a `TestServer` host with MVC and minimal-API endpoints (query binding, JSON bodies both ways), and the OpenAPI document generated with and without the documented `ValueRangesSchemaTransformer` — whose patterns are checked to accept every literal form the parsers accept, and whose source is held verbatim against `docs/serialization.md`.

`HostCultureProbeTests` there is the host half of route B's second probe sweep (#124): one `TestServer` with a minimal-API route group and a closed `ProbeController<T>` per declared type (every union, each of its five variants, every `RangeSet` and every set type, 107 in all), each bound from a query, a nullable query, a route value, a form field and a JSON body, under four request cultures set by `UseRequestLocalization` from `Accept-Language`. A valid value must come back with 200, the right runtime type and the same JSON value; a malformed literal, or a literal of another shape for a variant, must get 400. Each handler echoes the culture it ran under, so a row whose culture never arrived fails rather than passing vacuously. It links `RangeProbes`, `SetProbes`, `WrapperElements` and `Reflect` from the conventions project instead of copying them, and runs about 12,400 requests in about three seconds.
Expand Down
Loading
Loading