Skip to content

Fix JsonNodeAssertions.HaveProperty/NotHaveProperty for properties with explicit null values - #3282

Merged
dennisdoomen merged 2 commits into
mainfrom
copilot/fix-jsonnodeassertions-null-check
Aug 1, 2026
Merged

dennisdoomen merged 2 commits into
mainfrom
copilot/fix-jsonnodeassertions-null-check

Conversation

Copilot AI commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

JsonNodeAssertions<T>.HaveProperty/NotHaveProperty relied on Subject?[code] returning null to infer a missing property. Since JsonObject's indexer returns null both for an absent key and for a key explicitly set to JSON null, these assertions couldn't tell the two cases apart:

JsonNode json = JsonNode.Parse("""{ "id": 1, "name": null }""")!;

json.Should().NotHaveProperty("name"); // passed, even though "name" is present with a null value
json.Should().HaveProperty("name");    // failed, even though "name" exists

Changes

  • HaveProperty/NotHaveProperty now check presence via JsonObject.TryGetPropertyValue instead of the indexer, which distinguishes "key absent" from "key present with a null value"
  • Added spec coverage for a property with an explicit null value for both HaveProperty and NotHaveProperty
  • Documented the fix in docs/_pages/releases.md

Copilot AI review requested due to automatic review settings July 28, 2026 09:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because there is no eligible user to bill. To allow Copilot reviews on bot-authored pull requests, enable direct organization billing in your organization's Copilot settings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because there is no eligible user to bill. To allow Copilot reviews on bot-authored pull requests, enable direct organization billing in your organization's Copilot settings.

Copilot AI changed the title [WIP] Fix JsonNodeAssertions to distinguish absent properties from null values Fix JsonNodeAssertions.HaveProperty/NotHaveProperty for properties with explicit null values Jul 28, 2026
Copilot AI requested a review from dennisdoomen July 28, 2026 09:10
@dennisdoomen dennisdoomen added this to the 8.11 milestone Jul 28, 2026
@dennisdoomen
dennisdoomen marked this pull request as ready for review July 28, 2026 09:26
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Test Results

    37 files  ± 0      37 suites  ±0   2m 35s ⏱️ +5s
 6 390 tests + 2   6 389 ✅ + 2  1 💤 ±0  0 ❌ ±0 
39 686 runs  +12  39 680 ✅ +12  6 💤 ±0  0 ❌ ±0 

Results for commit e73901b. ± Comparison against base commit 8a7ddde.

This pull request removes 10 and adds 10 tests. Note that renamed tests count towards both.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HaveLength ‑ When_a_throwing_stream_should_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HaveLength ‑ When_a_throwing_stream_should_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HavePosition ‑ When_a_throwing_stream_should_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HavePosition ‑ When_a_throwing_stream_should_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHaveLength ‑ When_a_throwing_stream_should_not_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHaveLength ‑ When_a_throwing_stream_should_not_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHavePosition ‑ When_a_throwing_stream_should_not_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHavePosition ‑ When_a_throwing_stream_should_not_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetLengthExceptionMessage'.)
Object name: 'GetPositionExceptionMessage'.)
FluentAssertions.Specs.Specialized.JsonNodeSpecs+HaveProperty ‑ A_property_with_an_explicit_null_value_is_considered_present
FluentAssertions.Specs.Specialized.JsonNodeSpecs+HaveProperty ‑ A_property_with_an_explicit_null_value_is_not_considered_absent
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HaveLength ‑ When_a_throwing_stream_should_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetLengthExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HaveLength ‑ When_a_throwing_stream_should_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetLengthExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HavePosition ‑ When_a_throwing_stream_should_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetPositionExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+HavePosition ‑ When_a_throwing_stream_should_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetPositionExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHaveLength ‑ When_a_throwing_stream_should_not_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetLengthExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHaveLength ‑ When_a_throwing_stream_should_not_have_a_length_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetLengthExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHavePosition ‑ When_a_throwing_stream_should_not_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetPositionExceptionMessage'.)
FluentAssertions.Specs.Streams.StreamAssertionSpecs+NotHavePosition ‑ When_a_throwing_stream_should_not_have_a_position_it_should_fail(exception: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'GetPositionExceptionMessage'.)

♻️ This comment has been updated with latest results.

Comment thread Src/FluentAssertions/Specialized/JsonNodeAssertions.cs
dennisdoomen added a commit that referenced this pull request Jul 28, 2026
…ing (#3283)

Build/_build.csproj transitively pulled in System.Security.Cryptography.Xml
10.0.6, which has several known high-severity DoS vulnerabilities. Since
Directory.Build.props sets TreatWarningsAsErrors, NuGet's audit warning
(NU1903) is escalated to a build error, breaking restore for the Build
project on every PR/branch (including #3282), unrelated to any code change.

Pin a direct PackageReference to the patched 10.0.10 version to override
the vulnerable transitive dependency.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Qodana for .NET

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked
☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

Copilot AI review requested due to automatic review settings July 28, 2026 12:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because there is no eligible user to bill. To allow Copilot reviews on bot-authored pull requests, enable direct organization billing in your organization's Copilot settings.

Copilot AI review requested due to automatic review settings July 28, 2026 12:36
@dennisdoomen
dennisdoomen force-pushed the copilot/fix-jsonnodeassertions-null-check branch from 50867f0 to abbfdcb Compare July 28, 2026 12:36
@dennisdoomen
dennisdoomen requested a review from jnyrup July 28, 2026 12:37
This was referenced Oct 20, 2026

This branch was previously deployed

1 inactive deployment
qodana-pr — e73901b7 Deployed Jul 28, 2026 by dennisdoomen via Qodana Scan #34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JsonNodeAssertions.HaveProperty/NotHaveProperty cannot distinguish an absent property from one with an explicit null value

5 participants