feat(assertion): Add IsActualEqualToExpectedJsonValueComparer for JSON columns - #922
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Reviewer's GuideAdds a new JSON-aware ValueComparer implementation, wires it into documentation and change log, and tests its behavior across nulls, formatting differences, structural equality, and error cases when parsing JSON. Sequence diagram for JSON value comparison in IsActualEqualToExpectedJsonValueComparersequenceDiagram
participant Test as IsActualEqualToExpectedJsonValueComparerTest
participant Comparer as IsActualEqualToExpectedJsonValueComparer
participant DataType
participant ObjectMapper
Test->>Comparer: isExpected(expectedTable, actualTable, rowNum, columnName, dataType, expectedValue, actualValue)
alt [both values null]
Comparer-->>Test: true
else [one value null]
Comparer-->>Test: false
else [neither null]
Comparer->>Comparer: isJsonEqual(expectedValue, actualValue)
Comparer->>Comparer: parseJson("expected", expectedValue)
Comparer->>DataType: asString(expectedValue)
DataType-->>Comparer: jsonString
Comparer->>ObjectMapper: readTree(jsonString)
ObjectMapper-->>Comparer: expectedNode
Comparer->>Comparer: parseJson("actual", actualValue)
Comparer->>DataType: asString(actualValue)
DataType-->>Comparer: jsonString
Comparer->>ObjectMapper: readTree(jsonString)
ObjectMapper-->>Comparer: actualNode
Comparer-->>Test: actualNode.equals(expectedNode)
end
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Review limit reached
Next review available in: 34 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds ChangesJSON comparison
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- Consider making the
Loggerfieldprivate static finalinstead of an instance field to avoid redundant logger creation per comparer instance. - The
parseJsonerror message only differentiatesexpectedvsactual; consider including column/row context (e.g.,columnName,rowNum) in theDatabaseUnitExceptionto make JSON parse failures easier to diagnose during assertions.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider making the `Logger` field `private static final` instead of an instance field to avoid redundant logger creation per comparer instance.
- The `parseJson` error message only differentiates `expected` vs `actual`; consider including column/row context (e.g., `columnName`, `rowNum`) in the `DatabaseUnitException` to make JSON parse failures easier to diagnose during assertions.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/org/dbunit/assertion/comparer/value/IsActualEqualToExpectedJsonValueComparer.java`:
- Around line 97-104: Update the JSON parsing logic in the visible comparer
method to store the result of ObjectMapper.readTree, reject a null node by
throwing DatabaseUnitException for empty or whitespace-only input, and preserve
the existing IOException handling. Add tests covering both empty and
whitespace-only expected and actual values.
In
`@src/test/java/org/dbunit/assertion/comparer/value/IsActualEqualToExpectedJsonValueComparerTest.java`:
- Line 187: Rename testGetFailPhrase_returnsNonNullPhrase to include the default
comparer starting state, following the
test<MethodName>_<StartingStateConditions>_<AssertedOutcome> convention while
preserving the existing asserted outcome.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2d42d6f8-33ce-4f8d-926e-2e6c7481717e
📒 Files selected for processing (4)
src/changes/changes.xmlsrc/main/java/org/dbunit/assertion/comparer/value/IsActualEqualToExpectedJsonValueComparer.javasrc/site/asciidoc/datacomparisons/valuecomparer.adocsrc/test/java/org/dbunit/assertion/comparer/value/IsActualEqualToExpectedJsonValueComparerTest.java
…N columns Reviewed a Stack Overflow report of DbUnit failing to compare a MySQL JSON column (https://stackoverflow.com/a/55839637/2848514). MySQL Connector/J already reports native JSON columns as Types.LONGVARCHAR, which DbUnit's existing StringDataType handles for reads/writes with no DataTypeFactory change needed - but MySQL (like PostgreSQL jsonb and H2 JSON) reformats the text on storage, sorting object keys and stripping insignificant whitespace, so a literal string comparison against an expected dataset value spuriously fails even when the JSON is semantically identical. The SO thread's own suggested fix (a custom DataTypeFactory binding a driver-specific object such as PGobject) does not apply here and targets a different, write-path problem specific to PostgreSQL's stricter parameter binding. * Add IsActualEqualToExpectedJsonValueComparer, parsing both sides with Jackson and comparing the resulting document trees: object member order is ignored while array element order stays significant, matching JSON's own equality semantics. Database-agnostic - applies to any column that round-trips as text, not only MySQL. * Deliberately not exposed as a ValueComparers constant, since that class eagerly instantiates every constant it declares and would force the optional jackson-databind dependency onto every consumer, not only those comparing JSON columns. * Add unit coverage: null handling, identical text, whitespace-only and object-key-order differences, equivalent nested objects/arrays, array-order sensitivity, differing values, and malformed-JSON failures on both sides. * Document the new comparer in valuecomparer.adoc, noting why it is absent from ValueComparers and pointing readers there directly. Refs: 921 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016E3LGxvPZgjZjK1GHrcZpJ
18ccbd2 to
da25f10
Compare
|
Replying to Sourcery's two overall comments (da25f10):
|
Summary
JSONcolumn (https://stackoverflow.com/a/55839637/2848514). MySQL Connector/J already reports nativeJSONcolumns asTypes.LONGVARCHAR, which DbUnit's existingStringDataTypealready handles for reads/writes - noDataTypeFactorychange needed there, unlike the SO thread's own Postgres/H2 answers.jsonband H2JSON) reformats JSON text on storage - sorting object keys, stripping insignificant whitespace - so a literal string/value equality comparison against an expected dataset spuriously fails even when the JSON is semantically identical.IsActualEqualToExpectedJsonValueComparer(org.dbunit.assertion.comparer.value): parses both sides with Jackson and compares the resulting document trees - object member order ignored, array element order still significant, matching JSON's own equality semantics. Database-agnostic by design (works for MySQL/PostgreSQL/H2/MariaDB JSON columns), using the existingValueComparerextension point rather than a per-databaseDataTypeworkaround.ValueComparersconstant, since that class eagerly instantiates every constant it declares, which would force the optionaljackson-databinddependency onto every consumer, not only those comparing JSON columns.valuecomparer.adoc, explaining why it's absent fromValueComparers.Refs: 921
Test plan
IsActualEqualToExpectedJsonValueComparerTest(13 cases: null handling, identical text, whitespace-only/key-order differences, equivalent nested objects/arrays, array-order sensitivity, differing values, malformed JSON on either side)./mvnw clean test, 2048 tests, 0 failures)./mvnw javadoc:javadocclean (no doclint warnings)Summary by Sourcery
Add a JSON-aware value comparer for assertion of JSON column values and document its behavior and rationale, backed by unit tests and a changelog entry.
New Features:
Enhancements:
Documentation:
Tests:
Chores:
Summary by CodeRabbit
New Features
Documentation