lukas-krecan / JsonUnit

Compare JSON in your Unit Tests
Apache License 2.0
879 stars 115 forks source link

Order of net.javacrumbs.jsonunit.core.internal.Node.JsonMap.entrySet() is not consistent with fields #796

Closed glhez closed 1 month ago

glhez commented 1 month ago

Hello,

In our CI, Renovate tries to update JsonUnit (net.javacrumbs.json-unit:json-unit-assertj) from 2.38.0 to 2.40.0 and we have some unit test that fails in the updated branch, while they should not : the problem is tied to how JsonMapAssert create its entrySet() and containsExactly which checks in order that all values in entries are in actual map:

    @Test
    void test_gh_issue_json() {
        String json = "{ \"key3\" : \"A\", \"key2\" : \"B\", \"key1\" : \"C\"}";
        JsonAssertions.assertThatJson(json).isObject().containsExactly(entry("key3", "A"),
                                                                       entry("key2", "B"),
                                                                       entry("key1", "C"));
    }

This fails with this message/trace:

java.lang.AssertionError: [Different value found in node ""] 
Actual and expected have the same elements but not in the same order, at index 0 actual element was:
  "key2"="B"
whereas expected element was:
  "key3"="A"

    at net.javacrumbs.jsonunit.assertj.JsonMapAssert.containsExactlyForProxy(JsonMapAssert.java:157)
    at net.javacrumbs.jsonunit.assertj.JsonMapAssert.containsExactlyForProxy(JsonMapAssert.java:44)

The problem is due to the change here https://github.com/lukas-krecan/JsonUnit/compare/json-unit-parent-2.38.0...json-unit-parent-2.40.0#diff-5b83802f96066955d79fee221c4bf77f04fe03595904b2656256bf5816425cdfR235

One possible solution is to use toCollection and LinkedHashSet, then add Collections::unmodifiable:

entrySet = StreamSupport.stream(Spliterators.spliteratorUnknownSize(fields, java.util.Spliterator.ORDERED), false)
                        .map(keyValue -> new SimpleEntry<>(
                                keyValue.getKey(), keyValue.getValue().getValue()))
                        .collect(collectAndThen(toCollection(LinkedHashSet::new), Collections::unmodifiableSet)));

If I have some time this evening, I'll try to create a PR for 2.x baseline (this probably affect 3.x)

lukas-krecan commented 1 month ago

Thanks, I will look into that

lukas-krecan commented 1 month ago

Please send the PR if you get to it, I will release it ASAP

glhez commented 1 month ago

Yes, will do in ~3/4 hours

glhez commented 1 month ago

@lukas-krecan I've put a PR for v2 because that's what I'm interested in. Some tests are failing in v2 branch like this one:

net.javacrumbs.jsonunit.spring.testit.KotlinDslTest.isEqualToInNodeFailIfDoesNotEqual  Time elapsed: 0.01 s  <<< FAILURE!
org.opentest4j.AssertionFailedError: 

Expecting message to be:
  "[Different value found in node "result.string"] 
expected: "stringValue2"
 but was: "stringValue""
but was:
  "[Different value found in node "result.string"] 
expected: "stringValue2"
 but was: "stringValue""
lukas-krecan commented 1 month ago

Released as 3.4.1 and 2.40.1