lukas-krecan / JsonUnit

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

ParametrizedMatcher passes itself as paremeter instead of value only #111

Closed maricn closed 6 years ago

maricn commented 6 years ago

I'm seeing this exception which indicates a bug or it's a bit misleading:

java.time.format.DateTimeParseException: Text '${json-unit.matches:datetime}2018-04-26T16:33:34.202Z' could not be parsed at index 0

That is, sometimes my matchers receive the whole field value instead only parameter value in matches method call, which seems to be related to net.javacrumbs.jsonunit.core.internal.Diff#compareArrayNodes.

One of the matchers:

public class OffsetDateTimeEqual extends BaseMatcher<OffsetDateTime> implements Matcher<OffsetDateTime>, ParametrizedMatcher {

    /**
     * The particular instant in time that is expected to match.
     */
    private OffsetDateTime instant;

    public OffsetDateTimeEqual() {
    }

    public OffsetDateTimeEqual(OffsetDateTime instant) {
        this.instant = instant;
    }

    @Override
    public boolean matches(final Object item) {
        if (item == null) {
            return this.instant == null;
        }

        if (!(item instanceof OffsetDateTime || item instanceof String)) {
            return false;
        }

        if (this.instant == null) {
            return false;
        }

        if (item instanceof String) {
            return this.instant.isEqual(OffsetDateTime.parse((String) item));
        }

        return this.instant.isEqual((OffsetDateTime) item);
    }

    @Override
    public void setParameter(final String s) {
        this.instant = OffsetDateTime.parse(s);
    }
}

Expected json:

{
  "stories": [
    {
      "createdOn": "${json-unit.matches:datetime}2018-04-26T16:33:34.202Z",
      "nodes": [{"id": "${json-unit.matches:id}5"}]
    }
  ]
}

Actual json:

{
  "stories": [
    {
      "createdOn": "2018-04-26T16:33:34.202Z",
      "nodes": []
    }
  ]
}

Test code:

        assertJsonEquals(expectedResponse, actualJson,
                JsonAssert
                        .withMatcher("datetime", new OffsetDateTimeEqual())
                        .withMatcher("version", new VersionEqual())
                        .withMatcher("id", new SmpIdEqual())
                        .when(IGNORING_EXTRA_FIELDS, IGNORING_ARRAY_ORDER));

Stack trace:

java.time.format.DateTimeParseException: Text '${json-unit.matches:datetime}2018-04-26T16:33:34.202Z' could not be parsed at index 0

    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at java.time.OffsetDateTime.parse(OffsetDateTime.java:387)
    at my.project.common.test.util.OffsetDateTimeEqual.matches(OffsetDateTimeEqual.java:100)
    at net.javacrumbs.jsonunit.core.internal.Diff.checkMatcher(Diff.java:316)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:259)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareObjectNodes(Diff.java:143)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:268)
    at net.javacrumbs.jsonunit.core.internal.Diff.compare(Diff.java:103)
    at net.javacrumbs.jsonunit.core.internal.Diff.similar(Diff.java:550)
    at net.javacrumbs.jsonunit.core.internal.Diff$ArrayComparison.indexOf(Diff.java:494)
    at net.javacrumbs.jsonunit.core.internal.Diff$ArrayComparison.access$200(Diff.java:432)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareArrayNodes(Diff.java:411)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:271)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareObjectNodes(Diff.java:143)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:268)
    at net.javacrumbs.jsonunit.core.internal.Diff.compare(Diff.java:103)
    at net.javacrumbs.jsonunit.core.internal.Diff.similar(Diff.java:550)
    at net.javacrumbs.jsonunit.JsonAssert.assertJsonPartEquals(JsonAssert.java:81)
    at net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals(JsonAssert.java:66)
    at my.project.api.story.SmpIntegrationTest.upsertExistingStory(SmpIntegrationTest.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:67)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
lukas-krecan commented 6 years ago

Thanks, it's indeed a bug in an edge case when ignoring array order is used and only one difference is found. Will fix it.

maricn commented 6 years ago

Thank you!

Also, maybe relevant here - I added @JsonIgnore(NON_EMPTY) to my DTO for serialization, and now I get:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

    at java.util.ArrayList.rangeCheck(ArrayList.java:657)
    at java.util.ArrayList.get(ArrayList.java:433)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareArrayNodes(Diff.java:414)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:271)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareObjectNodes(Diff.java:143)
    at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:268)
    at net.javacrumbs.jsonunit.core.internal.Diff.compare(Diff.java:103)
    at net.javacrumbs.jsonunit.core.internal.Diff.similar(Diff.java:550)
    at net.javacrumbs.jsonunit.JsonAssert.assertJsonPartEquals(JsonAssert.java:81)
    at net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals(JsonAssert.java:66)
    at my.project.api.story.SmpIntegrationTest.upsertExistingStory(SmpIntegrationTest.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
lukas-krecan commented 6 years ago

You can try 1.29.1

maricn commented 6 years ago

Amazing, thank you for the swift solution and published bugfix version! ❤️