Releases: JohnVerheij/JsonAssertions.TUnit
Releases · JohnVerheij/JsonAssertions.TUnit
Release list
v0.6.1
[0.6.1] - 2026-07-12: document the 0.6.0 traps
Patch release. Documentation only; no API or behavioral change. Everything here comes from migrating a real suite onto 0.6.0, where the two new features landed cleanly but three shapes in the surface misled a reader who was pattern-matching from the rest of the package.
Changed
ContainsJsondocumentation now carries an explicit warning against folding a volatile value into the expected subset.ContainsJsonasserts equality for every field placed in it: "subset" constrains which fields are checked, not how strictly they are compared. Pinning a duration reading, a server-generated identifier, or a legitimately-varying status therefore asserts more than the contract does, and the test fails on the first run that differs. This is the failure mode a migration onto 0.6.0 walks into, because collapsing a block of per-property checks feels mechanical enough to sweep a volatile field in with the stable ones, turning a presence check into an equality check.GetJsonValue<T>/GetJsonString/GetJsonElementare now documented as extending the receiver rather than the assertion chain, and as living in theJsonAssertionsnamespace, so they needusing JsonAssertions;. Every other feature auto-imports throughTUnit.Assertions.Extensions, which trains a reader to reach forAssert.That(response).GetJsonValueAsync<T>(...)first: that does not compile, and the resultingCS1061never names the missing namespace. The namespace table, the entry-point list, and the cookbook pattern now all show the receiver form.HasJsonArrayLengthand the other shape and value assertions now document that only theHttpResponseMessageforms take aCancellationToken(it flows to the body read; astringorJsonElementsource has nothing to cancel). Passing one on aJsonElementreportsCS1929namingHttpResponseMessageas the required receiver, which points at the receiver when the fix is to drop the token.HasJsonTypeInfoFor<T>is now documented as the one assertion in the package that guards a failure class the rest of a suite can miss: a type absent from theJsonSerializerContextis not a compile error, and with a reflection fallback in the resolver chain a JIT test run serializes it happily while the published Native-AOT binary throws at runtime.MatchesProblemDetailsnow documents that it asserts the media type as well as the fields, so a separate content-type test becomes redundant on migration (which a strict analyzer set will flag as duplicate method bodies).
v0.6.0
[0.6.0] - 2026-07-11: JSON subset matching and typed extraction
Minor release. Adds subset (contains) assertions and typed value extraction. Purely additive.
Added
Assert.That(actual).ContainsJson(expectedSubset)asserts that a JSON document contains an expected subset: every property in the expected document must be present in the actual document with an equivalent value (recursively), while the actual document may carry additional properties. This is the subset counterpart ofIsEquivalentJsonTo(full equality), for the common case where a response carries fields a test does not want to pin. A JSONstring, aJsonElement, and anHttpResponseMessage(body read with a flowedCancellationToken) are accepted as the actual value; the expected subset is a JSONstring. Matching is independent of object-property order and number form. An expected array asserts a positional prefix (the actual array may be longer);IgnoreArrayOrder()matches expected elements against the actual array as a multiset subset, andIgnorePath(...)excludes a path, both through the configure overload. On failure the message lists every missing or mismatched path in one report, each with its category and a rendered view of both sides, so a single run enumerates every field that is wrong.JsonEquivalence.ContainsAll(expected, actual, options)(framework-agnostic core) exposes the subset comparison directly over JSON strings orJsonElements, returning everyJsonDifferencefound (empty when the actual document contains the subset).JsonFailureMessage.ContainsMismatch(differences)renders the multi-difference failure text.GetJsonValue<T>(path),GetJsonString(path), andGetJsonElement(path)read a typed value out of a JSON document at a path and return it, for a test that needs the value (pulling an id to drive the next request, reading a count to cross-check an array length) rather than an assertion.GetJsonValue<T>parses the value as anyIParsable<T>(int/long/bool/Guid/DateTimeOffset, ...) from a JSON string or a JSON number literal, usingCultureInfo.InvariantCulture;GetJsonElementreturns a detached copy that stays valid after the source document is disposed. Each is available over a JSONstring, aJsonElement, and (asGetJsonValueAsync/GetJsonStringAsync/GetJsonElementAsync) anHttpResponseMessage. A failure to resolve the path, convert the value, or parse the source throwsJsonExtractionExceptionwith the same path-context message the assertions render, replacing a hand-rolledJsonDocument.Parse(...).GetProperty(...).GetInt32()chain and its bare BCL exceptions.
v0.5.0
[0.5.0] - 2026-06-14: structural JSON equivalence
Minor release. Adds whole-document structural equivalence assertions. Purely additive.
Added
Assert.That(actual).IsEquivalentJsonTo(expected)asserts that two JSON documents carry the same values at the same paths. Equivalence ignores object-property order and the lexical form of numbers, so1,1.0, and1e0are equal. Both a JSONstringand aJsonElementare accepted as the actual value; the expected document is a JSONstring. A configure overload sets options:IgnorePath("items[*].timestamp")excludes a path from the comparison (the same path grammar as the other assertions, including the[*]wildcard), andIgnoreArrayOrder()compares arrays as multisets rather than position by position. On failure the message names the first diverging path, the category of difference, and a rendered view of each side, with container values shown as truncated raw JSON.JsonEquivalence(framework-agnostic core) exposes the comparison directly:Compare(expected, actual, options)over JSON strings orJsonElements returns the firstJsonDifference, ornullwhen the documents are equivalent.JsonEquivalenceOptions,JsonDifference, andJsonDifferenceKindare public so the engine is usable outside the assertion path.
v0.4.2
[0.4.2] - 2026-06-05: documentation refresh
Documentation and release-tooling release. No API or behavior change.
Changed
- Refreshed the README (plain-ASCII punctuation) and rewrote the shared
CONVENTIONS.md: removed the version-history preamble so it reads as a conventions document, not a changelog. - Documented the JSON path syntax (dot-separated with
[n]indices plus the[*]wildcard) and why it is a navigable subset rather than JSONPath/JMESPath. - The release workflow now publishes the matching
CHANGELOG.mdsection as the GitHub release body (body_path), so release notes carry the full hand-written detail instead of GitHub's auto-generated commit summary.
v0.4.1
What's Changed
- deps(nuget): update tunit to v1.49.0 by @renovate[bot] in #43
- docs: note [*] wildcard empty-array footgun and index-scoped caveat by @JohnVerheij in #42
Full Changelog: v0.4.0...v0.4.1
v0.4.0
What's Changed
- feat: int/uint/long/ulong JSON value overloads match a number or numeric string by @JohnVerheij in #41
Full Changelog: v0.2.0...v0.4.0
v0.3.0
What's Changed
- chore: split CoC and security reporting channels by @JohnVerheij in #6
- feat(v0.3.0): AOT-context regression + HTTP-response JSON by @JohnVerheij in #7
Full Changelog: v0.2.0...v0.3.0
v0.2.0
What's Changed
- docs: CONVENTIONS.md v0.4 - add JsonAssertions.TUnit to the family roster by @JohnVerheij in #2
- chore: auto-populate PackageReleaseNotes from CHANGELOG at pack time by @JohnVerheij in #3
- feat: v0.2.0 - array-indexed paths, root-self, boolean/non-empty-string/matching/one-of/parsable-as assertions by @JohnVerheij in #4
- docs: bring README / SECURITY / bug-report to the v0.2.0 surface by @JohnVerheij in #5
Full Changelog: v0.1.0...v0.2.0
v0.1.0
What's Changed
- feat: v0.1.0 - value-at-path, shape, and HTTP assertions by @JohnVerheij in #1
New Contributors
- @JohnVerheij made their first contribution in #1
Full Changelog: v0.0.1...v0.1.0