From fe30c48295b8174a346db7d0137f6e38956b169d Mon Sep 17 00:00:00 2001 From: shendiao Date: Sun, 2 Mar 2025 06:50:10 +0800 Subject: [PATCH 01/18] refactor for jsonDiff, the draft version --- pom.xml | 52 +- .../com/nezha/jsondiff/CompareContext.java | 89 ++ .../nezha/jsondiff/CompareMatcherItem.java | 43 + .../java/com/nezha/jsondiff/CompareRule.java | 68 ++ .../java/com/nezha/jsondiff/CompareRules.java | 56 ++ .../jsondiff/CompareRulesTransformer.java | 83 ++ .../com/nezha/jsondiff/CustomCompareRule.java | 44 + .../com/nezha/jsondiff/Customization.java | 194 ++++ .../java/com/nezha/jsondiff/FailureField.java | 44 + .../jsondiff}/FieldComparisonFailure.java | 4 +- .../java/com/nezha/jsondiff/JSONCompare.java | 264 ++++++ .../com/nezha/jsondiff/JSONCompareConf.java | 96 ++ .../jsondiff/JSONCompareDeepDetailResult.java | 72 ++ .../jsondiff/JSONCompareDetailResult.java} | 194 +++- .../com/nezha/jsondiff/JSONCompareResult.java | 42 + .../nezha/jsondiff/JSONCompareResultUtil.java | 227 +++++ .../jsondiff/JSONCompareSimpleResult.java | 38 + .../java/com/nezha/jsondiff/JSONParser.java | 102 +++ .../com/nezha/jsondiff/PreProcessItem.java | 20 + .../comparator/AbstractComparator.java | 130 +-- .../comparator/ArraySizeComparator.java | 119 +++ .../comparator/CustomComparator.java | 42 +- .../comparator/DefaultComparator.java | 80 +- .../jsondiff/comparator/JSONComparator.java | 130 +++ .../jsondiff}/comparator/JSONCompareUtil.java | 113 ++- .../com/nezha/jsondiff/constant/Param.java | 29 + .../matcher/ArrayDisorderMatcher.java | 70 ++ .../jsondiff/matcher/ArrayInOrderMatcher.java | 71 ++ .../jsondiff/matcher/ArrayLengthMatcher.java | 73 ++ .../matcher/ArrayRecursivelyMatcher.java | 133 +++ .../jsondiff/matcher}/ArrayValueMatcher.java | 11 +- .../jsondiff/matcher/ArrayWithKeyMatcher.java | 131 +++ .../matcher/ComparatorValueMatcher.java | 67 ++ .../jsondiff/matcher/CustomValueMatcher.java | 57 ++ .../matcher/DegreePreciseMatcher.java | 60 ++ .../jsondiff/matcher/EmptyValueMatcher.java | 67 ++ .../jsondiff/matcher/EscapedJsonMatcher.java | 71 ++ .../matcher/ImprecisePositionMatcher.java | 90 ++ .../jsondiff/matcher/IngorePathMatcher.java | 35 + .../matcher}/LocationAwareValueMatcher.java | 12 +- .../matcher/NumberPreciseMatcher.java | 67 ++ .../matcher/PercentTolerantMatcher.java | 52 ++ .../matcher/RadianPreciseMatcher.java | 60 ++ .../RegularExpressionValueMatcher.java | 11 +- .../matcher/TolerantValueMatcher.java | 51 ++ .../nezha/jsondiff/matcher}/ValueMatcher.java | 9 +- .../matcher}/ValueMatcherException.java | 2 +- .../skyscreamer/jsonassert/Customization.java | 151 --- .../skyscreamer/jsonassert/JSONAssert.java | 748 --------------- .../skyscreamer/jsonassert/JSONCompare.java | 144 --- .../jsonassert/JSONCompareMode.java | 120 --- .../skyscreamer/jsonassert/JSONParser.java | 57 -- .../comparator/ArraySizeComparator.java | 120 --- .../jsonassert/comparator/JSONComparator.java | 79 -- src/test/java/jsondiff/FileUtil.java | 52 ++ .../jsondiff/JSONCompareYamlResultTest.java | 72 ++ .../jsonassert/ArrayValueMatcherTest.java | 283 ------ .../jsonassert/DependencyTest.java | 44 - .../jsonassert/JSONArrayWithNullTest.java | 48 - .../jsonassert/JSONAssertTest.java | 856 ------------------ .../jsonassert/JSONCompareModeTest.java | 74 -- .../jsonassert/JSONCompareTest.java | 201 ---- .../jsonassert/JSONCustomComparatorTest.java | 168 ---- .../RegularExpressionValueMatcherTest.java | 117 --- .../comparator/ArraySizeComparatorTest.java | 141 --- .../comparator/CustomComparatorTest.java | 52 -- .../comparator/JSONCompareUtilTest.java | 54 -- src/test/resources/case_01_a.json | 180 ++++ src/test/resources/case_01_e.json | 180 ++++ src/test/resources/case_01_result.json | 1 + src/test/resources/rule_case01.yaml | 95 ++ 71 files changed, 3948 insertions(+), 3664 deletions(-) create mode 100644 src/main/java/com/nezha/jsondiff/CompareContext.java create mode 100644 src/main/java/com/nezha/jsondiff/CompareMatcherItem.java create mode 100644 src/main/java/com/nezha/jsondiff/CompareRule.java create mode 100644 src/main/java/com/nezha/jsondiff/CompareRules.java create mode 100644 src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java create mode 100644 src/main/java/com/nezha/jsondiff/CustomCompareRule.java create mode 100644 src/main/java/com/nezha/jsondiff/Customization.java create mode 100644 src/main/java/com/nezha/jsondiff/FailureField.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff}/FieldComparisonFailure.java (96%) create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompare.java create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompareConf.java create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java rename src/main/java/{org/skyscreamer/jsonassert/JSONCompareResult.java => com/nezha/jsondiff/JSONCompareDetailResult.java} (57%) create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompareResult.java create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java create mode 100644 src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java create mode 100644 src/main/java/com/nezha/jsondiff/JSONParser.java create mode 100644 src/main/java/com/nezha/jsondiff/PreProcessItem.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff}/comparator/AbstractComparator.java (58%) create mode 100644 src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff}/comparator/CustomComparator.java (50%) rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff}/comparator/DefaultComparator.java (51%) create mode 100644 src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff}/comparator/JSONCompareUtil.java (70%) create mode 100644 src/main/java/com/nezha/jsondiff/constant/Param.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff/matcher}/ArrayValueMatcher.java (97%) create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff/matcher}/LocationAwareValueMatcher.java (83%) create mode 100644 src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java create mode 100644 src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff/matcher}/RegularExpressionValueMatcher.java (95%) create mode 100644 src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff/matcher}/ValueMatcher.java (83%) rename src/main/java/{org/skyscreamer/jsonassert => com/nezha/jsondiff/matcher}/ValueMatcherException.java (98%) delete mode 100644 src/main/java/org/skyscreamer/jsonassert/Customization.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/JSONAssert.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/JSONCompare.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/JSONCompareMode.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/JSONParser.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparator.java delete mode 100644 src/main/java/org/skyscreamer/jsonassert/comparator/JSONComparator.java create mode 100644 src/test/java/jsondiff/FileUtil.java create mode 100644 src/test/java/jsondiff/JSONCompareYamlResultTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/ArrayValueMatcherTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/DependencyTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/JSONArrayWithNullTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/JSONAssertTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/JSONCompareModeTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/JSONCompareTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/JSONCustomComparatorTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcherTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparatorTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/comparator/CustomComparatorTest.java delete mode 100644 src/test/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtilTest.java create mode 100644 src/test/resources/case_01_a.json create mode 100644 src/test/resources/case_01_e.json create mode 100644 src/test/resources/case_01_result.json create mode 100644 src/test/resources/rule_case01.yaml diff --git a/pom.xml b/pom.xml index 86738534..cc8b3e3b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,19 +1,16 @@ - + 4.0.0 - org.skyscreamer - jsonassert - 2.0-rc1 + com.nezha + UltraJSONDiff + 1.0-rc1 jar - JSONassert - Write JSON unit tests in less code. Great for testing REST interfaces. - https://github.com/skyscreamer/JSONassert + UltraJSONDiff + Json Diff Tools - - 8 - @@ -22,11 +19,6 @@ repo - - scm:git:git@github.com:skyscreamer/JSONassert.git - scm:git:git@github.com:skyscreamer/JSONassert.git - git@github.com:skyscreamer/JSONassert.git - carterpage @@ -58,6 +50,31 @@ 2.2 test + + org.yaml + snakeyaml + 2.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.2 + + + com.vaadin.external.google + android-json + 0.0.20131108.vaadin1 + + + commons-lang + commons-lang + 2.6 + + + com.jayway.jsonpath + json-path + 2.9.0 + @@ -66,6 +83,11 @@ org.apache.maven.plugins maven-compiler-plugin 3.11.0 + + 1.8 + 1.8 + UTF-8 + org.sonatype.plugins diff --git a/src/main/java/com/nezha/jsondiff/CompareContext.java b/src/main/java/com/nezha/jsondiff/CompareContext.java new file mode 100644 index 00000000..b4759243 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CompareContext.java @@ -0,0 +1,89 @@ +package com.nezha.jsondiff; + +public class CompareContext { + private Boolean extensible = true; + private Boolean strictOrder = true; + private Boolean ignoreNull = true; + private Boolean fastFail = false; + + public CompareContext(Boolean extensible, Boolean strictOrder, Boolean ignoreNull, Boolean fastFail) { + this.extensible = extensible; + this.strictOrder = strictOrder; + this.ignoreNull = ignoreNull; + this.fastFail = fastFail; + + } + + + // Getter and Setter for extensible + public Boolean getExtensible() { + return extensible; + } + + // Getter and Setter for strictOrder + public Boolean getStrictOrder() { + return strictOrder; + } + + public void setStrictOrder(Boolean strictOrder) { + this.strictOrder = strictOrder; + } + + // Getter and Setter for ignoreNull + public Boolean getIgnoreNull() { + return ignoreNull; + } + + public void setIgnoreNull(Boolean ignoreNull) { + this.ignoreNull = ignoreNull; + } + + // Getter and Setter for quickFail + public Boolean getFastFail() { + return fastFail; + } + + public void setFastFail(Boolean fastFail) {this.fastFail = fastFail;} + + /** + * Is extensible + * + * @return True if results can be extended from what's expected, otherwise false. + */ + public boolean isExtensible() { + return extensible; + } + + public void setExtensible(Boolean extensible) { + this.extensible = extensible; + } + + /** + * Strict order required + * + * @return True if results require strict array ordering, otherwise false. + */ + public boolean hasStrictOrder() { + return strictOrder; + } + + /** + * Need end compare if any failure found + * + * @return True if comparison should be ended when any failure found, otherwise false. + */ + public boolean needQuickFail() { + return fastFail; + } + + /** + * Need skip comparison when null found + * + * @return True if need skip current element when its value is null, otherwise false. + */ + public boolean needIgnoreNull() { + return ignoreNull; + } + + +} diff --git a/src/main/java/com/nezha/jsondiff/CompareMatcherItem.java b/src/main/java/com/nezha/jsondiff/CompareMatcherItem.java new file mode 100644 index 00000000..9216ccd1 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CompareMatcherItem.java @@ -0,0 +1,43 @@ +package com.nezha.jsondiff; + +import java.util.Map; + +public class CompareMatcherItem { + private String name; + private String jsonPath; + private String param; + private Map pararms; + + //创建构造函数 + public CompareMatcherItem(String name, String jsonPath, String param) { + this.name = name; + this.jsonPath = jsonPath; + this.param = param; + } + + // Getter and Setter for path + public String getJsonPath() { + return jsonPath; + } + + public void setJsonPath(String path) { + this.jsonPath = path; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getParam() { + return this.param; + } + + public void setParam(String param) { + this.param = param; + } +} + diff --git a/src/main/java/com/nezha/jsondiff/CompareRule.java b/src/main/java/com/nezha/jsondiff/CompareRule.java new file mode 100644 index 00000000..d484adfd --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CompareRule.java @@ -0,0 +1,68 @@ +package com.nezha.jsondiff; + +import com.nezha.jsondiff.constant.Param; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +public class CompareRule { + private final CompareContext compareContext; + private String jsonPath; + + private List preProcesses; + private List customRules; + + + public CompareRule(Map rule) { + // Default constructor + this.jsonPath = (String) rule.get(Param.JSON_PATH_KEY); + boolean extensible = (Boolean) rule.get(Param.EXTENSIBLE_KEY); + boolean strictOrder = (Boolean) rule.get(Param.STRICT_ORDER); + boolean fastFail = (Boolean) rule.get(Param.FAST_FAIL_KEY); + boolean ignoreNull = (Boolean) rule.get(Param.IGNORE_NULL_KEY); + this.compareContext = new CompareContext(extensible, strictOrder, ignoreNull, fastFail); + +// Map preProcess = (Map) rule.get(Param.PRE_PROCESS_KEY); + List> customRulesMaps = (List>) rule.get(Param.CUSTOM_RULES_KEY); + //conver customRulesMap to CompareMatcherItem + this.customRules = customRulesMaps.stream() + .map(ruleMap -> { + return new CompareMatcherItem((String) ruleMap.get(Param.NAME_KEY), + (String) ruleMap.get(Param.JSON_PATH_KEY), + (String) ruleMap.get(Param.PARAM_KEY)); + }) + .collect(Collectors.toList()); + } + + public CompareContext getCompareContext() { + return this.compareContext; + } + + public String getJsonPath() { + return this.jsonPath; + } + + public void setJsonPath(String jsonPath) { + this.jsonPath = jsonPath; + } + + // Getter and Setter for preProcesses + public List getPreProcesses() { + return preProcesses; + } + + public void setPreProcesses(List preProcesses) { + this.preProcesses = preProcesses; + } + + // Getter and Setter for customRules + public List getCustomRules() { + return customRules; + } + + public void setCustomRules(List customRules) { + this.customRules = customRules; + } +} diff --git a/src/main/java/com/nezha/jsondiff/CompareRules.java b/src/main/java/com/nezha/jsondiff/CompareRules.java new file mode 100644 index 00000000..bd3c4735 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CompareRules.java @@ -0,0 +1,56 @@ +/* + * CompareRules.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nezha.jsondiff; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CompareRules { + private final String defaultMode; + private final CustomCompareRule[] customRules; + + public CompareRules() { + this("STRICT_ORDER", new ArrayList()); + } + + public CompareRules(String defaultMode) { + this(defaultMode, new ArrayList()); + } + + public CompareRules(ArrayList customRules) { + this("STRICT_ORDER", customRules); + } + + public CompareRules(String defaultMode, List customRules) { + this.defaultMode = defaultMode; + this.customRules = customRules.toArray(new CustomCompareRule[0]); + } + + public CompareRules(String defaultMode, CustomCompareRule[] customRules) { + this.defaultMode = defaultMode; + this.customRules = customRules; + } + + public String getDefaultMode() { + return defaultMode; + } + + public List getCustomRules() { + List rules = new ArrayList(); + Collections.addAll(rules, customRules); + return rules; + } +} diff --git a/src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java b/src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java new file mode 100644 index 00000000..74f5b271 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java @@ -0,0 +1,83 @@ +/* + * CompareRulesTranformer.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nezha.jsondiff.comparator.CustomComparator; +import com.nezha.jsondiff.matcher.ValueMatcher; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + + +public final class CompareRulesTransformer { + + private CompareRulesTransformer() { + } + + public static CompareRules stringToCompareRules(final String rulesInJsonStr) { + final ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(rulesInJsonStr, CompareRules.class); + } catch (final JsonProcessingException e) { + e.printStackTrace(); + return new CompareRules(); + } + } + + public static CustomComparator getComparator(final CompareRule compareRule) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + final List customizations = getCustomizationsRe(compareRule); + final int size = customizations.size(); + return new CustomComparator(compareRule.getCompareContext(), + customizations.toArray(new Customization[size])); + + } + + public static CustomComparator getComparator(final String compareRules) { + return getComparator(String.valueOf(stringToCompareRules(compareRules).getCustomRules().get(0))); + } + + private static List getCustomizationsRe(final CompareRule compareRule) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + CompareContext compareContext = compareRule.getCompareContext(); + List customRules = compareRule.getCustomRules(); + + final List customizationList = new ArrayList(); + for (CompareMatcherItem rule : customRules) { + //根据获取到类,调用构造函数 + String path = rule.getJsonPath(); + String param = rule.getParam(); + String ruleName = rule.getName(); + String matchClassName = ruleName + "Matcher"; + //使用反射从ruleName获取到实际的matcher类,ruleName为类名称,matcher的package为com.nezha.jsondiff.matcher + Class clazz = Class.forName("com.nezha.jsondiff.matcher." + matchClassName); + Constructor constructor = clazz.getConstructor(); + + Object matcher = constructor.newInstance(); + // 调用matcherInit方法 + Method matcherInitMethod = clazz.getMethod("matcherInit", String.class, CompareContext.class); + matcherInitMethod.invoke(matcher, param, compareContext); + // 将matcher添加到customizationList中 + customizationList.add(new Customization(path, (ValueMatcher) matcher)); + + } + return customizationList; + } +} + diff --git a/src/main/java/com/nezha/jsondiff/CustomCompareRule.java b/src/main/java/com/nezha/jsondiff/CustomCompareRule.java new file mode 100644 index 00000000..75fb5e89 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/CustomCompareRule.java @@ -0,0 +1,44 @@ +/* + * CustomCompareRule.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +public class CustomCompareRule { + String path; + String[] matcher; + + public CustomCompareRule() {} + + public CustomCompareRule(String path, String[] matcher) { + this.path = path; + this.matcher = matcher; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String[] getMatcher() { + return matcher; + } + + public void setMatcher(String[] matcher) { + this.matcher = matcher; + } +} diff --git a/src/main/java/com/nezha/jsondiff/Customization.java b/src/main/java/com/nezha/jsondiff/Customization.java new file mode 100644 index 00000000..b87491d7 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/Customization.java @@ -0,0 +1,194 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + + +import com.nezha.jsondiff.comparator.JSONComparator; +import com.nezha.jsondiff.matcher.CustomValueMatcher; +import com.nezha.jsondiff.matcher.LocationAwareValueMatcher; +import com.nezha.jsondiff.matcher.ValueMatcher; +import com.nezha.jsondiff.matcher.ValueMatcherException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Associates a custom matcher to a specific jsonpath. + */ +public final class Customization { + private final Pattern path; + private final ValueMatcher matcher; + private int matchLevel; + private String minMatchStr; + + public Customization(String path, ValueMatcher matcher) { + if (path == null) { + path = ""; + } + assert matcher != null; + buildMatchParam(path); + this.path = Pattern.compile(buildPattern(path)); + this.matcher = matcher; + } + + /** + * Creates a new {@link Customization} instance for {@code path} and {@code comparator}. + * + * @param path the json path + * @param comparator the comparator + * @return a new Customization + */ + public static Customization customization(String path, ValueMatcher comparator) { + return new Customization(path, comparator); + } + + private void buildMatchParam(String path) { + Pattern p1 = Pattern.compile("^\\*\\*\\.(.+)"); + Pattern p1_e = Pattern.compile("^\\*\\*\\.(.+)\\*(.*)"); + Matcher m1 = p1.matcher(path); + Matcher m1_e = p1_e.matcher(path); + if (m1.matches() && !m1_e.matches()) { + matchLevel = 1; + minMatchStr = m1.group(1); + } else if (m1_e.matches()) { + matchLevel = 2; + minMatchStr = m1_e.group(2); + } + } + + private boolean matchPath(String path) { + switch (this.matchLevel) { + case 1: + return path.equals(minMatchStr) || path.endsWith("." + minMatchStr); + case 2: + return path.endsWith(minMatchStr) && this.path.matcher(path).matches(); + default: + return this.path.matcher(path).matches(); + } + } + + private String buildPattern(String path) { + // If the path is $, it means that it matches an empty string, that is, + // the root directory, and there is no need to perform path regularization conversion + if (path.equals("$")) return path; + return buildPatternLevel1(path); + } + + private String buildPatternLevel1(String path) { + String regex = "\\*\\*\\."; + String replacement = "(?:.+\\.)?"; + + return buildPattern(path, regex, replacement, 1); + } + + private String buildPatternLevel2(String s) { + if (s.isEmpty()) { + return ""; + } + String regex = "\\*\\*"; + String replacement = ".+"; + + return buildPattern(s, regex, replacement, 2); + } + + private String buildPatternLevel3(String s) { + if (s.isEmpty()) { + return ""; + } + + String regex = "\\*"; + String replacement = "[^\\.]+"; + + return buildPattern(s, regex, replacement, 3); + } + + private String buildPattern(String path, String regex, String replacement, int level) { + StringBuilder sb = new StringBuilder(); + String[] parts = path.split(regex); + for (int i = 0; i < parts.length; i++) { + sb.append(buildPatternForLevel(level, parts[i])); + if (i < parts.length - 1) { + sb.append(replacement); + } + } + return sb.toString(); + } + + private String buildPatternForLevel(int level, String part) { + switch (level) { + case 1: + return buildPatternLevel2(part); + case 2: + return buildPatternLevel3(part); + case 3: + return Pattern.quote(part); + default: + return "Incorrect level."; + } + } + + public boolean appliesToPath(String path) { + return matchPath(path); +// return this.path.matcher(path).matches(); + } + + /** + * Return true if actual value matches expected value using this + * Customization's comparator. Calls to this method should be replaced by + * calls to matches(String prefix, Object actual, Object expected, + * JSONCompareDetailResult result). + * + * @param actual JSON value being tested + * @param expected expected JSON value + * @return true if actual value matches expected value + */ + @Deprecated + public boolean matches(Object actual, Object expected) { + return matcher.equal(actual, expected); + } + + /** + * Return true if actual value matches expected value using this + * Customization's comparator. The equal method used for comparison depends + * on type of comparator. + * + * @param prefix JSON path of the JSON item being tested (only used if + * comparator is a LocationAwareValueMatcher) + * @param actual JSON value being tested + * @param expected expected JSON value + * @param result JSONCompareDetailResult to which match failure may be passed (only + * used if comparator is a LocationAwareValueMatcher) + * @return true if expected and actual equal or any difference has already + * been passed to specified result instance, false otherwise. + * @throws ValueMatcherException if expected and actual values not equal and ValueMatcher + * needs to override default comparison failure message that + * would be generated if this method returned false. + */ + public boolean matches(String prefix, Object actual, Object expected, + JSONCompareDetailResult result, JSONComparator comparator) throws + ValueMatcherException { + if (matcher instanceof LocationAwareValueMatcher) { + return ((LocationAwareValueMatcher) matcher).equal(prefix, actual, expected, result); + } else if (matcher instanceof CustomValueMatcher) { + return ((CustomValueMatcher) matcher).equal(prefix, actual, expected, result, + comparator); + } + return matcher.equal(actual, expected); + } + + public String instanceOfMatcher() { + return matcher.getClass().getSimpleName(); + } +} diff --git a/src/main/java/com/nezha/jsondiff/FailureField.java b/src/main/java/com/nezha/jsondiff/FailureField.java new file mode 100644 index 00000000..d060e09e --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/FailureField.java @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nezha.jsondiff; + +public class FailureField { + private final Object expected; + private final Object actual; + private final String diffKey; + private final String reason; + + public FailureField(Object expected, Object actual, String diffKey, String reason) { + this.expected = expected; + this.actual = actual; + this.diffKey = diffKey; + this.reason = reason; + } + + public Object getExpected() { + return expected; + } + + public Object getActual() { + return actual; + } + + public String getDiffKey() { + return diffKey; + } + + public String getReason() { + return reason; + } +} diff --git a/src/main/java/org/skyscreamer/jsonassert/FieldComparisonFailure.java b/src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java similarity index 96% rename from src/main/java/org/skyscreamer/jsonassert/FieldComparisonFailure.java rename to src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java index a4746f24..33c24ec3 100644 --- a/src/main/java/org/skyscreamer/jsonassert/FieldComparisonFailure.java +++ b/src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java @@ -10,9 +10,9 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff; /** * Models a failure when comparing two fields. diff --git a/src/main/java/com/nezha/jsondiff/JSONCompare.java b/src/main/java/com/nezha/jsondiff/JSONCompare.java new file mode 100644 index 00000000..56ce03c1 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompare.java @@ -0,0 +1,264 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import com.nezha.jsondiff.comparator.CustomComparator; +import com.nezha.jsondiff.comparator.DefaultComparator; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONString; + +import java.util.List; + +/** + * Provides API to compare two JSON entities. but it can + * be programmed against directly to access the functionality. (eg, to make something that works with a + * non-JUnit test framework) + */ +public final class JSONCompare { + private JSONCompare() { + } + + private static JSONComparator getComparatorForMode(CompareContext mode) { + return new DefaultComparator(mode); + } + + /** + * Compares JSON string provided to the expected JSON string using provided comparator, and returns the results of + * the comparison. + * + * @param expectedStr Expected JSON string + * @param actualStr JSON string to compare + * @param comparator Comparator to use + * @return result of the comparison + * @throws JSONException JSON parsing error + * @throws IllegalArgumentException when type of expectedStr doesn't match the type of actualStr + */ + public static JSONCompareDetailResult compareJSON(String expectedStr, String actualStr, JSONComparator comparator) + throws JSONException { + Object expected = JSONParser.parseJSON(expectedStr); + Object actual = JSONParser.parseJSON(actualStr); + if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { + return compareJSON((JSONObject) expected, (JSONObject) actual, comparator); + } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { + return compareJSON((JSONArray) expected, (JSONArray) actual, comparator); + } else if (expected instanceof JSONString && actual instanceof JSONString) { + return compareJson((JSONString) expected, (JSONString) actual); + } else if (expected instanceof JSONObject) { + return new JSONCompareDetailResult().fail("", expected, actual); + } else { + return new JSONCompareDetailResult().fail("", expected, actual); + } + } + + /** + * Compares JSON object provided to the expected JSON object using provided comparator, and returns the results of + * the comparison. + * + * @param expected expected json object + * @param actual actual json object + * @param comparator comparator to use + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual, JSONComparator comparator) + throws JSONException { + return comparator.compareJSON(expected, actual); + } + + /** + * Compares JSON object provided to the expected JSON object using provided comparator, and returns the results of + * the comparison. + * + * @param expected expected json array + * @param actual actual json array + * @param comparator comparator to use + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual, JSONComparator comparator) + throws JSONException { + return comparator.compareJSON(expected, actual); + } + + /** + * Compares {@link JSONString} provided to the expected {@code JSONString}, checking that the + * {@link JSONString#toJSONString()} are equal. + * + * @param expected Expected {@code JSONstring} + * @param actual {@code JSONstring} to compare + * @return result of the comparison + */ + public static JSONCompareDetailResult compareJson(final JSONString expected, final JSONString actual) { + final JSONCompareDetailResult result = new JSONCompareDetailResult(); + final String expectedJson = expected.toJSONString(); + final String actualJson = actual.toJSONString(); + if (!expectedJson.equals(actualJson)) { + result.fail(""); + } + return result; + } + + /** + * Compares JSON string provided to the expected JSON string, and returns the results of the comparison. + * + * @param expectedStr Expected JSON string + * @param actualStr JSON string to compare + * @param mode Defines comparison behavior + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareDetailResult compareJSON(String expectedStr, String actualStr, CompareContext mode) + throws JSONException { + return compareJSON(expectedStr, actualStr, getComparatorForMode(mode)); + } + + /** + * Compares JSONObject provided to the expected JSONObject, and returns the results of the comparison. + * + * @param expected Expected JSONObject + * @param actual JSONObject to compare + * @param mode Defines comparison behavior + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual, CompareContext mode) + throws JSONException { + return compareJSON(expected, actual, getComparatorForMode(mode)); + } + + + /** + * Compares JSONArray provided to the expected JSONArray, and returns the results of the comparison. + * + * @param expected Expected JSONArray + * @param actual JSONArray to compare + * @param mode Defines comparison behavior + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual, CompareContext mode) + throws JSONException { + return compareJSON(expected, actual, getComparatorForMode(mode)); + } + + + /** + * Compares JSONArray provided to the expected JSONArray, and returns the results of the comparison. + * + * @param expectedStr Expected JSON string + * @param actualStr JSON string to compare + * @param compareRules Compare rules in JSON string + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareSimpleResult compareJSONSimple(String expectedStr, String actualStr, + String compareRules) + throws JSONException { + CustomComparator comparator = CompareRulesTransformer.getComparator(compareRules); + return compareJSONSimple(expectedStr, actualStr, comparator); + } + + + public static JSONCompareResult compareJSONYaml(String expectedStr, String actualStr, String yamlRule) + throws Exception { + JSONCompareConf yamlRuleObj = new JSONCompareConf(); + yamlRuleObj.readNodeFromYaml(yamlRule); + List compareRules = yamlRuleObj.getCompareRules(); + + JSONCompareResult result = new JSONCompareResult(); + // 解析 JSON 字符串 + DocumentContext contextExpect = JsonPath.parse(expectedStr); + DocumentContext contextActual = JsonPath.parse(actualStr); + + // 使用路径表达式读取值 + String expectedByJsonPath = expectedStr; + String actualByJsonPath = actualStr; + + for (CompareRule compareRule : compareRules) { + CustomComparator comparator = CompareRulesTransformer.getComparator(compareRule); + if (compareRule.getJsonPath() != null) { + ObjectMapper objectMapper = new ObjectMapper(); + expectedByJsonPath = objectMapper.writeValueAsString(contextExpect.read(compareRule.getJsonPath())); + actualByJsonPath = objectMapper.writeValueAsString(contextActual.read(compareRule.getJsonPath())); + } + + try { + JSONCompareSimpleResult compareSimpleResult = compareJSONSimpleYaml(expectedByJsonPath, actualByJsonPath, comparator); + result.addFailures(compareSimpleResult.getFailure()); + } catch (JSONException e) { + FailureField failureField = new FailureField("", "", compareRule.getJsonPath(), e.getMessage()); + result.addFailure(failureField); + } + + } + return result; + } + + public static JSONCompareDeepDetailResult compareJSONDeep(String expectedStr, String actualStr, + JSONComparator comparator) + throws JSONException { + Object expected = JSONParser.parseJSON(expectedStr); + Object actual = JSONParser.parseJSON(actualStr); + JSONCompareDeepDetailResult result; + if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { + result = new JSONCompareDeepDetailResult(compareJSON((JSONObject) expected, + (JSONObject) actual, comparator)); + } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { + result = new JSONCompareDeepDetailResult(compareJSON((JSONArray) expected, (JSONArray) actual + , comparator)); + } else if (expected instanceof JSONString && actual instanceof JSONString) { + result = new JSONCompareDeepDetailResult(compareJson((JSONString) expected, + (JSONString) actual)); + } else { + result = new JSONCompareDeepDetailResult(); + result.fail("", expected, actual); + return result; + } + JSONCompareResultUtil.getAbsolutePath(expected, actual, result); + return result; + } + + + public static JSONCompareSimpleResult compareJSONSimpleYaml(String expectedStr, String actualStr, CustomComparator comparator) + throws JSONException { + return compareJSONSimple(expectedStr, actualStr, comparator); + } + + public static JSONCompareSimpleResult compareJSONSimple(String expectedStr, String actualStr, + JSONComparator comparator) + throws JSONException { + Object expected = JSONParser.parseJSON(expectedStr); + Object actual = JSONParser.parseJSON(actualStr); + JSONCompareDetailResult result; + if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { + result = compareJSON((JSONObject) expected, (JSONObject) actual, comparator); + } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { + result = compareJSON((JSONArray) expected, (JSONArray) actual, comparator); + } else if (expected instanceof JSONString && actual instanceof JSONString) { + result = compareJson((JSONString) expected, (JSONString) actual); + } else { + result = new JSONCompareDetailResult(); + result.fail("", expected, actual); + } + JSONCompareSimpleResult simpleResult = JSONCompareResultUtil.getSimpleResult(result); + return simpleResult; + } +} diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareConf.java b/src/main/java/com/nezha/jsondiff/JSONCompareConf.java new file mode 100644 index 00000000..c1aa6de4 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompareConf.java @@ -0,0 +1,96 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import org.yaml.snakeyaml.Yaml; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class JSONCompareConf { + List> yamlData = new ArrayList>(); + List compareRules = new ArrayList(); + + private static void processSubRule(Map subRule) { + String forPath = (String) subRule.get("forPath"); + String type = (String) subRule.get("type"); + List> customRules = (List>) subRule.get("customRules"); + Map preProcess = (Map) subRule.get("preProcess"); + Map postProcess = (Map) subRule.get("postProcess"); + + System.out.println("forPath: " + forPath); + System.out.println("type: " + type); + + System.out.println("Custom Rules:"); + for (Map rule : customRules) { + for (Map.Entry entry : rule.entrySet()) { + System.out.println(" Rule Type: " + entry.getKey()); + Map ruleDetails = (Map) entry.getValue(); + for (Map.Entry detail : ruleDetails.entrySet()) { + System.out.println(" " + detail.getKey() + ": " + detail.getValue()); + } + } + } + + System.out.println("Pre Process:"); + for (Map.Entry entry : preProcess.entrySet()) { + System.out.println(" " + entry.getKey() + ": " + entry.getValue()); + } + + System.out.println("Post Process:"); + for (Map.Entry entry : postProcess.entrySet()) { + System.out.println(" " + entry.getKey() + ": " + entry.getValue()); + } + } + + public List> getYamlData() { + return yamlData; + } + + public void readNodeFromYaml(String yamlString) throws Exception { + // 验证 YAML 字符串是否为空 + if (yamlString == null || yamlString.trim().isEmpty()) { + throw new IllegalArgumentException("YAML string cannot be null or empty"); + } + + try { + Yaml yaml = new Yaml(); + this.yamlData = yaml.load(yamlString); + for (Map rule : this.yamlData) { + if (rule.containsKey("subRule")) { + Map subRule = (Map) rule.get("subRule"); + compareRules.add(new CompareRule(subRule)); + } + + } + + } catch (Exception e) { + throw new Exception("Failed to parse or process YAML string", e); + } + } + + public void convertToCompareMatcher() { + for (Map rule : yamlData) { + compareRules.add(new CompareRule(rule)); + } + } + + public List getCompareRules() { + return compareRules; + } + + +} diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java b/src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java new file mode 100644 index 00000000..581e397b --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java @@ -0,0 +1,72 @@ +/* + * JSONCompareDeepDetailResult.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import java.util.ArrayList; +import java.util.List; + +public class JSONCompareDeepDetailResult extends JSONCompareDetailResult { + + private final List actualFailureFields = new ArrayList<>(); + private final List expectedFailureFields = new ArrayList<>(); + private final List unexpectedFields = new ArrayList<>(); + private final List missingFields = new ArrayList<>(); + + public JSONCompareDeepDetailResult() { + super(); + } + + public JSONCompareDeepDetailResult(JSONCompareDetailResult o) { + super(o); + } + + public List getActualFailureFields() { + return actualFailureFields; + } + + public List getExpectedFailureFields() { + return expectedFailureFields; + } + + public List getUnexpectedFields() { + return unexpectedFields; + } + + public List getMissingFields() { + return missingFields; + } + + public void addActualFail(String prefix) { + addToList(actualFailureFields, prefix); + } + + public void addExpectedFail(String prefix) { + addToList(expectedFailureFields, prefix); + } + + public void addMissing(String prefix) { + addToList(missingFields, prefix); + } + + public void addUnexpected(String prefix) { + addToList(unexpectedFields, prefix); + } + + private void addToList(List list, String s) { + if (s == null) return; + list.add(s); + } +} diff --git a/src/main/java/org/skyscreamer/jsonassert/JSONCompareResult.java b/src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java similarity index 57% rename from src/main/java/org/skyscreamer/jsonassert/JSONCompareResult.java rename to src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java index 55672099..7226814a 100644 --- a/src/main/java/org/skyscreamer/jsonassert/JSONCompareResult.java +++ b/src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java @@ -10,44 +10,87 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ + +package com.nezha.jsondiff; -package org.skyscreamer.jsonassert; +import com.nezha.jsondiff.matcher.ValueMatcherException; +import org.json.JSONArray; +import org.json.JSONObject; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.json.JSONArray; -import org.json.JSONObject; - /** * Bean for holding results from JSONCompare. */ -public class JSONCompareResult { +public class JSONCompareDetailResult { private boolean _success; - private StringBuilder _message; + private boolean _complete; // whether need complete comparison. + private boolean _quickFail; // whether need end comparison immediately. + private boolean _ignoreNull; // whether need ignore comparison result for current element when its value is null. + private final StringBuilder _message; private String _field; private Object _expected; private Object _actual; - private final List _fieldFailures = new ArrayList(); - private final List _fieldMissing = new ArrayList(); - private final List _fieldUnexpected = new ArrayList(); + private List _fieldFailures = new ArrayList(); + private List _fieldMissing = new ArrayList(); + private List _fieldUnexpected = new ArrayList(); /** * Default constructor. */ - public JSONCompareResult() { - this(true, null); + public JSONCompareDetailResult() { + this(true, true, false, false, null); } - private JSONCompareResult(boolean success, String message) { + private JSONCompareDetailResult(boolean success, boolean complete, boolean quickFail, + boolean ignoreNull, String message) { _success = success; + _complete = complete; + _quickFail = quickFail; + _ignoreNull = ignoreNull; _message = new StringBuilder(message == null ? "" : message); } + public JSONCompareDetailResult(JSONCompareDetailResult o) { + this._success = o._success; + this._message = o._message; + this._field = o._field; + this._expected = o._expected; + this._actual = o._actual; + this._fieldFailures = o._fieldFailures; + this._fieldMissing = o._fieldMissing; + this._fieldUnexpected = o._fieldUnexpected; + } + + private static String describe(Object value) { + if (value instanceof JSONArray) { + return "a JSON array: " + getShortenString(value.toString()); + } else if (value instanceof JSONObject) { + return "a JSON object: " + getShortenString(value.toString()); + } else if (value == null) { + return "null"; + } else { + return value.toString(); + } + } + + private static String getShortenString(String s) { + if (s.length() > 100) { + return s.substring(0, 60) + "<...>" + s.substring(s.length() - 40); + } + return s; + } + + private static boolean isNull(Object value) { + return value == null || value.equals(JSONObject.NULL); + } + /** * Did the comparison pass? + * * @return True if it passed */ public boolean passed() { @@ -56,14 +99,56 @@ public boolean passed() { /** * Did the comparison fail? + * * @return True if it failed */ public boolean failed() { return !_success; } + /** + * Did the comparison pass? + * + * @return True if it passed + */ + public boolean getSuccess() { + return _success; + } + + /** + * Did the comparison is complete? + * + * @return True if it should be complete + */ + public boolean getComplete() { + return _complete; + } + + public void setComplete(boolean complete) { + _complete = complete; + } + + /** + * Did the comparison should be end immediately? + * + * @return True if it should be end immediately + */ + public boolean quickFail() { + return _quickFail; + } + + /** + * Did the comparison result for current element should be ignore when the value is null? + * + * @return True if it should be ignored + */ + public boolean ignoreNull() { + return _ignoreNull; + } + /** * Result message + * * @return String explaining why if the comparison failed */ public String getMessage() { @@ -72,22 +157,25 @@ public String getMessage() { /** * Get the list of failures on field comparisons + * * @return list of comparsion failures */ public List getFieldFailures() { return Collections.unmodifiableList(_fieldFailures); } - + /** * Get the list of missed on field comparisons + * * @return list of comparsion failures */ public List getFieldMissing() { return Collections.unmodifiableList(_fieldMissing); } - + /** * Get the list of failures on field comparisons + * * @return list of comparsion failures */ public List getFieldUnexpected() { @@ -96,48 +184,51 @@ public List getFieldUnexpected() { /** * Actual field value - * + * * @return a {@code JSONObject}, {@code JSONArray} or other {@code Object} - * instance, or {@code null} if the comparison did not fail on a - * particular field + * instance, or {@code null} if the comparison did not fail on a + * particular field * @deprecated Superseded by {@link #getFieldFailures()} */ @Deprecated public Object getActual() { return _actual; } - + /** * Expected field value - * + * * @return a {@code JSONObject}, {@code JSONArray} or other {@code Object} - * instance, or {@code null} if the comparison did not fail on a - * particular field + * instance, or {@code null} if the comparison did not fail on a + * particular field * @deprecated Superseded by {@link #getFieldFailures()} */ @Deprecated public Object getExpected() { return _expected; } - + /** * Check if comparison failed on any particular fields + * * @return true if there are field failures */ public boolean isFailureOnField() { return !_fieldFailures.isEmpty(); } - + /** * Check if comparison failed with missing on any particular fields + * * @return true if an expected field is missing */ public boolean isMissingOnField() { return !_fieldMissing.isEmpty(); } - + /** * Check if comparison failed with unexpected on any particular fields + * * @return true if an unexpected field is in the result */ public boolean isUnexpectedOnField() { @@ -146,18 +237,20 @@ public boolean isUnexpectedOnField() { /** * Dot-separated path the the field that failed comparison - * + * * @return a {@code String} instance, or {@code null} if the comparison did - * not fail on a particular field + * not fail on a particular field * @deprecated Superseded by {@link #getFieldFailures()} */ @Deprecated public String getField() { return _field; } - + public void fail(String message) { _success = false; + // if does not need completed comparison, quick fail will be true. + if (!_complete) _quickFail = true; if (_message.length() == 0) { _message.append(message); } else { @@ -167,12 +260,14 @@ public void fail(String message) { /** * Identify that the comparison failed - * @param field Which field failed + * + * @param field Which field failed * @param expected Expected result - * @param actual Actual result + * @param actual Actual result * @return result of comparision */ - public JSONCompareResult fail(String field, Object expected, Object actual) { + public JSONCompareDetailResult fail(String field, Object expected, Object actual) { + if (_ignoreNull && isNull(expected)) return this; _fieldFailures.add(new FieldComparisonFailure(field, expected, actual)); this._field = field; this._expected = expected; @@ -183,12 +278,15 @@ public JSONCompareResult fail(String field, Object expected, Object actual) { /** * Identify that the comparison failed - * @param field Which field failed + * + * @param field Which field failed * @param exception exception containing details of match failure * @return result of comparision */ - public JSONCompareResult fail(String field, ValueMatcherException exception) { - fail(field + ": " + exception.getMessage(), exception.getExpected(), exception.getActual()); + public JSONCompareDetailResult fail(String field, ValueMatcherException exception) { + _fieldFailures.add(new FieldComparisonFailure(field, exception.getExpected(), exception.getActual())); + fail(formatFailureMessage(field + ": " + exception.getMessage(), exception.getExpected(), + exception.getActual())); return this; } @@ -203,12 +301,13 @@ private String formatFailureMessage(String field, Object expected, Object actual /** * Identify the missing field - * @param field missing field + * + * @param field missing field * @param expected expected result * @return result of comparison */ - public JSONCompareResult missing(String field, Object expected) { - _fieldMissing.add(new FieldComparisonFailure(field, expected, null)); + public JSONCompareDetailResult missing(String field, Object expected) { + _fieldMissing.add(new FieldComparisonFailure(field, expected, null)); fail(formatMissing(field, expected)); return this; } @@ -222,12 +321,13 @@ private String formatMissing(String field, Object expected) { /** * Identify unexpected field - * @param field unexpected field + * + * @param field unexpected field * @param actual actual result * @return result of comparison */ - public JSONCompareResult unexpected(String field, Object actual) { - _fieldUnexpected.add(new FieldComparisonFailure(field, null, actual)); + public JSONCompareDetailResult unexpected(String field, Object actual) { + _fieldUnexpected.add(new FieldComparisonFailure(field, null, actual)); fail(formatUnexpected(field, actual)); return this; } @@ -239,18 +339,12 @@ private String formatUnexpected(String field, Object actual) { + "\n"; } - private static String describe(Object value) { - if (value instanceof JSONArray) { - return "a JSON array"; - } else if (value instanceof JSONObject) { - return "a JSON object"; - } else { - return String.valueOf(value); - } - } - @Override public String toString() { return _message.toString(); } + + public void setIgnoreNull(boolean ignoreNull) { + _ignoreNull = ignoreNull; + } } diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareResult.java b/src/main/java/com/nezha/jsondiff/JSONCompareResult.java new file mode 100644 index 00000000..1b9805dc --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompareResult.java @@ -0,0 +1,42 @@ +/* + * JSONCompareSimpleResult.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import java.util.ArrayList; +import java.util.List; + +/** + * Function: compare results in simple mode + */ +public class JSONCompareResult { + + private final List failures = new ArrayList<>(); + + public JSONCompareResult() { + } + + public List getFailure() { + return failures; + } + + public void addFailure(FailureField f) { + failures.add(f); + } + + public void addFailures(List newFailures) { + failures.addAll(newFailures); + } +} diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java b/src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java new file mode 100644 index 00000000..3512f1a9 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java @@ -0,0 +1,227 @@ +/* + * JSONCompareResultUtil.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + */ +public class JSONCompareResultUtil { + private static final Pattern patternArray = Pattern.compile("^\\[(.*?)\\]"); + private static final Pattern patternArrayFull = Pattern.compile("(.+?)\\[(.*?)\\]"); + private static final Pattern patternAEqualsB = Pattern.compile("([^=\\s]+)=([^=\\s]+)"); + private JSONCompareResultUtil() { + } + + public static void getAbsolutePath(Object expected, Object actual, + JSONCompareDeepDetailResult result) throws JSONException { + List _fieldFailure = result.getFieldFailures(); + List _fieldMissing = result.getFieldMissing(); + List _fieldUnexpected = result.getFieldUnexpected(); + + for (FieldComparisonFailure f : _fieldFailure) { + result.addExpectedFail(getAbsolutePath(expected, f.getField())); + result.addActualFail(getAbsolutePath(actual, f.getField())); + } + + for (FieldComparisonFailure f : _fieldMissing) { + result.addMissing(getAbsolutePath(expected, f.getField())); + } + + for (FieldComparisonFailure f : _fieldUnexpected) { + result.addUnexpected(getAbsolutePath(actual, f.getField())); + } + } + + public static String getAbsolutePath(Object object, String relativePath) { + + try { +// String[] path = relativePath.split("\\."); + List path = getSplitPath(relativePath); + StringBuilder prefix = new StringBuilder(); + Object obj = object; + + if (obj instanceof JSONArray) { + Matcher matcher = patternArray.matcher(path.get(0)); + if (matcher.find()) { + obj = getIndexAndUpdateRealIndex(prefix, getMiddleString(path.get(0)), obj); + } + } else { + obj = getNodeAndUpdateRealKey(prefix, path.get(0), obj); + } + + for (int i = 1; i < path.size(); i++) { + String p = path.get(i); + + if (p.isEmpty()) return prefix.toString(); + if (obj == null) return null; + obj = getNodeAndUpdateRealKey(prefix, p, obj); + } + + return prefix.toString(); + } catch (Exception e) { + return null; + } + + } + + private static Object getNodeAndUpdateRealKey(StringBuilder prefix, String key, Object obj) throws JSONException { + JSONObject o = (JSONObject) obj; + Matcher matcher = patternArrayFull.matcher(key); + if (prefix.length() > 0) { + prefix.append("."); + } + // 如果是json array路径:a[XXX] + if (matcher.find()) { + // 先获取json array本身的key: a + String arrayKey = matcher.group(1); + prefix.append(arrayKey); + // 再获取相对的index: [XXX],获取array的绝对index,并更新obj + String relativeIndex = getMiddleString(getTailString(key, arrayKey.length())); + return getIndexAndUpdateRealIndex(prefix, relativeIndex, o.get(arrayKey)); + + } else { + prefix.append(key); + return o.get(key); + } + } + + private static Object getIndexAndUpdateRealIndex(StringBuilder prefix, String relativeIndex, + Object obj) throws JSONException { + JSONArray a = (JSONArray) obj; + if (relativeIndex.isEmpty()) { + return a; + } + int index; + Matcher matcher = patternAEqualsB.matcher(relativeIndex); + // 如果index为 key=value的形式 + if (matcher.find()) { + // 获取key + String key = matcher.group(1); + // 获取value + String value = getTailString(relativeIndex, key.length() + 1); + index = getArrayIndexFromKeyValue(a, key, value); + if (index == -1) return null; + } else { + index = Integer.parseInt(relativeIndex); + } + prefix.append("[").append(index).append("]"); + return a.get(index); + } + + private static int getArrayIndexFromKeyValue(JSONArray array, String key, String value) { + try { + for (int i = 0; i < array.length(); i++) { + Object item = array.get(i); + if (item instanceof JSONObject) { + JSONObject o = (JSONObject) item; + if (o.has(key) && String.valueOf(o.get(key)).equals(value)) { + return i; + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + return -1; + } + return -1; + } + + private static List getSplitPath(String s) { + List splitPath = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + int num = 0; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (ch == '[') { + num++; + } else if (ch == ']') { + num--; + } else if (num == 0 && ch == '.') { + splitPath.add(sb.toString()); + sb.setLength(0); + continue; + } + sb.append(ch); + } + splitPath.add(sb.toString()); + return splitPath; + } + + private static String getMiddleString(String s) { + int len = s.length(); + if (len >= 2) { + return s.substring(1, len - 1); + } + return s; + } + + private static String getTailString(String s, int lenHead) { + int len = s.length(); + if (len >= lenHead) { + return s.substring(lenHead, len); + } + return s; + } + + //获取原json对比结果的简化版 + public static JSONCompareSimpleResult getSimpleResult(JSONCompareDetailResult result) { + List _fieldFailure = result.getFieldFailures(); + List _fieldMissing = result.getFieldMissing(); + List _fieldUnexpected = result.getFieldUnexpected(); + JSONCompareSimpleResult simpleResult = new JSONCompareSimpleResult(); + + for (FieldComparisonFailure f : _fieldFailure) { + simpleResult.addFailure(new FailureField(describe(f.getExpected()), + describe(f.getActual()), f.getField(), "actual unequals to expected")); + } + + for (FieldComparisonFailure f : _fieldMissing) { + simpleResult.addFailure(new FailureField(describe(f.getExpected()), null, f.getField(), "only in expected")); + } + + for (FieldComparisonFailure f : _fieldUnexpected) { + simpleResult.addFailure(new FailureField(null, describe(f.getActual()), f.getField(), "only in actual")); + } + + return simpleResult; + } + + private static Object describe(Object value) { + if (value instanceof JSONArray) { + return "a JSON array: " + getShortenString(value.toString()); + } else if (value instanceof JSONObject) { + return "a JSON object: " + getShortenString(value.toString()); + } else { + return value; + } + } + + private static String getShortenString(String s) { + if (s.length() > 100) { + return s.substring(0, 60) + "<...>" + s.substring(s.length() - 40); + } + return s; + } +} diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java b/src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java new file mode 100644 index 00000000..36a5bbc0 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java @@ -0,0 +1,38 @@ +/* + * JSONCompareSimpleResult.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import java.util.ArrayList; +import java.util.List; + +/** + * Function: Compare results in simple mode + */ +public class JSONCompareSimpleResult { + + private final List failures = new ArrayList<>(); + + public JSONCompareSimpleResult() { + } + + public List getFailure() { + return failures; + } + + public void addFailure(FailureField f) { + failures.add(f); + } +} diff --git a/src/main/java/com/nezha/jsondiff/JSONParser.java b/src/main/java/com/nezha/jsondiff/JSONParser.java new file mode 100644 index 00000000..883cc48a --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/JSONParser.java @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +import org.apache.commons.lang.StringEscapeUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONString; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Simple JSON parsing utility. + */ +public class JSONParser { + // regular expression to match a number in JSON format. see http://www.json.org/fatfree.html. + // "A number can be represented as integer, real, or floating point. JSON does not support octal or hex + // ... [or] NaN or Infinity". + private static final String NUMBER_REGEX = "-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"; + + private JSONParser() { + } + + /** + * Takes a JSON string and returns either a {@link JSONObject} or {@link JSONArray}, + * depending on whether the string represents an object or an array. + * + * @param s Raw JSON string to be parsed + * @return JSONObject or JSONArray + * @throws JSONException JSON parsing error + */ + public static Object parseJSON(final String s) throws JSONException { + if (s.trim().startsWith("{")) { + return new JSONObject(s); + } else if (s.trim().startsWith("[")) { + return new JSONArray(s); + } else if (s.trim().startsWith("\"") + || s.trim().matches(NUMBER_REGEX)) { + return new JSONString() { + @Override + public String toJSONString() { + return s; + } + }; + } + throw new JSONException("Unparsable JSON string: " + s); + } + + /** + * Takes an escaped JSON string and returns either a {@link JSONObject} or + * {@link JSONArray}, + * depending on whether the string represents an object or an array. + * + * @param s Raw JSON string to be parsed + * @return JSONObject or JSONArray + * @throws JSONException JSON parsing error + */ + public static Object parseEscapedJSON(final String s) throws JSONException { + String unescapedStr = s; + unescapedStr = getEscapedJSONInUnescapedJSONObject(unescapedStr); + unescapedStr = getEscapedJSONInUnescapedJSONArray(unescapedStr); + return parseJSON(unescapedStr); + } + + private static String getEscapedJSONInUnescapedJSONObject(String s) { + Pattern pattern = Pattern.compile("\"\\{(.*?)\\}\""); + Matcher matcher = pattern.matcher(s); + while (matcher.find()) { + String matchedStr = matcher.group(); + String replacedStr = StringEscapeUtils.unescapeJavaScript(matchedStr.substring(1, + matchedStr.length() - 1)); + s = s.replace(matchedStr, replacedStr); + } + return s; + } + + private static String getEscapedJSONInUnescapedJSONArray(String s) { + Pattern pattern = Pattern.compile("\"\\[(.*?)\\]\""); + Matcher matcher = pattern.matcher(s); + while (matcher.find()) { + String matchedStr = matcher.group(); + String replacedStr = StringEscapeUtils.unescapeJavaScript(matchedStr.substring(1, + matchedStr.length() - 1)); + s = s.replace(matchedStr, replacedStr); + } + return s; + } +} diff --git a/src/main/java/com/nezha/jsondiff/PreProcessItem.java b/src/main/java/com/nezha/jsondiff/PreProcessItem.java new file mode 100644 index 00000000..c4947193 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/PreProcessItem.java @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff; + +public class PreProcessItem { + String path; + String action; +} diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/AbstractComparator.java b/src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java similarity index 58% rename from src/main/java/org/skyscreamer/jsonassert/comparator/AbstractComparator.java rename to src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java index 190e47ea..89a12df2 100644 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/AbstractComparator.java +++ b/src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java @@ -10,41 +10,38 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -package org.skyscreamer.jsonassert.comparator; +package com.nezha.jsondiff.comparator; +import com.nezha.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; -import org.skyscreamer.jsonassert.JSONCompareResult; -import java.util.*; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; -import static org.skyscreamer.jsonassert.comparator.JSONCompareUtil.*; +import static com.nezha.jsondiff.comparator.JSONCompareUtil.*; /** * This class provides a skeletal implementation of the {@link JSONComparator} * interface, to minimize the effort required to implement this interface. - * - * */ public abstract class AbstractComparator implements JSONComparator { - /** - * Default constructor - */ - public AbstractComparator() { - } - /** * Compares JSONObject provided to the expected JSONObject, and returns the results of the comparison. * * @param expected Expected JSONObject * @param actual JSONObject to compare + * @throws JSONException JSON parsing error */ @Override - public final JSONCompareResult compareJSON(JSONObject expected, JSONObject actual) { - JSONCompareResult result = new JSONCompareResult(); + public final JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual) throws JSONException { + JSONCompareDetailResult result = new JSONCompareDetailResult(); + markResultFeature(result); compareJSON("", expected, actual, result); return result; } @@ -54,50 +51,46 @@ public final JSONCompareResult compareJSON(JSONObject expected, JSONObject actua * * @param expected Expected JSONArray * @param actual JSONArray to compare + * @throws JSONException JSON parsing error */ @Override - public final JSONCompareResult compareJSON(JSONArray expected, JSONArray actual) { - JSONCompareResult result = new JSONCompareResult(); - compareJSONArray("", expected, actual, result); + public final JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual) throws JSONException { + JSONCompareDetailResult result = new JSONCompareDetailResult(); + markResultFeature(result); + // 为了使JSONArray对象的根目录能进行自定义规则,在JSONArray对比入口改动为调用compareValues + // compareJSONArray("", expected, actual, result); + compareValues("", expected, actual, result); return result; } - /** - * @param prefix - * @param expected - * @param actual - * @param result - */ - protected void checkJsonObjectKeysActualInExpected(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) { + protected void checkJsonObjectKeysActualInExpected(String prefix, JSONObject expected, JSONObject actual, JSONCompareDetailResult result) + throws JSONException { Set actualKeys = getKeys(actual); for (String key : actualKeys) { + if (result.quickFail()) return; if (!expected.has(key)) { - result.unexpected(prefix, key); + // unexpected的value也需体现在result中,之前传入key + markUnexpected(qualify(prefix, key), actual.get(key), result); } } } - /** - * - * @param prefix - * @param expected - * @param actual - * @param result - */ - protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) { + protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareDetailResult result) throws JSONException { Set expectedKeys = getKeys(expected); for (String key : expectedKeys) { + if (result.quickFail()) return; Object expectedValue = expected.get(key); if (actual.has(key)) { Object actualValue = actual.get(key); compareValues(qualify(prefix, key), expectedValue, actualValue, result); } else { - result.missing(prefix, key); + // missing的value也需体现在result中,之前传入key + markMissing(qualify(prefix, key), expectedValue, result); } } } - protected void compareJSONArrayOfJsonObjects(String key, JSONArray expected, JSONArray actual, JSONCompareResult result) { + protected void compareJSONArrayOfJsonObjects(String key, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) throws JSONException { String uniqueKey = findUniqueKey(expected); if (uniqueKey == null || !isUsableAsUniqueKey(uniqueKey, actual)) { // An expensive last resort @@ -106,7 +99,12 @@ protected void compareJSONArrayOfJsonObjects(String key, JSONArray expected, JSO } Map expectedValueMap = arrayOfJsonObjectToMap(expected, uniqueKey); Map actualValueMap = arrayOfJsonObjectToMap(actual, uniqueKey); + if (!isUsableAsUniqueKeyForBothMap(expectedValueMap, actualValueMap)) { + recursivelyCompareJSONArray(key, expected, actual, result); + return; + } for (Object id : expectedValueMap.keySet()) { + if (result.quickFail()) return; if (!actualValueMap.containsKey(id)) { result.missing(formatUniqueKey(key, uniqueKey, id), expectedValueMap.get(id)); continue; @@ -116,34 +114,52 @@ protected void compareJSONArrayOfJsonObjects(String key, JSONArray expected, JSO compareValues(formatUniqueKey(key, uniqueKey, id), expectedValue, actualValue, result); } for (Object id : actualValueMap.keySet()) { + if (result.quickFail()) return; if (!expectedValueMap.containsKey(id)) { result.unexpected(formatUniqueKey(key, uniqueKey, id), actualValueMap.get(id)); } } } - protected void compareJSONArrayOfSimpleValues(String key, JSONArray expected, JSONArray actual, JSONCompareResult result) { + protected void compareJSONArrayOfSimpleValues(String key, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) throws JSONException { Map expectedCount = JSONCompareUtil.getCardinalityMap(jsonArrayToList(expected)); Map actualCount = JSONCompareUtil.getCardinalityMap(jsonArrayToList(actual)); for (Object o : expectedCount.keySet()) { + if (result.quickFail()) return; if (!actualCount.containsKey(o)) { result.missing(key + "[]", o); } else if (!actualCount.get(o).equals(expectedCount.get(o))) { - result.fail(key + "[]: Expected " + expectedCount.get(o) + " occurrence(s) of " + o - + " but got " + actualCount.get(o) + " occurrence(s)"); + // 改动:加入JSONCompareResult._fieldFailures字段中 + result.fail(key + "[]", "Expected " + expectedCount.get(o) + " occurrence(s) " + + "of " + o, " but got " + actualCount.get(o) + " occurrence(s)"); } } for (Object o : actualCount.keySet()) { + if (result.quickFail()) return; if (!expectedCount.containsKey(o)) { result.unexpected(key + "[]", o); } } } - protected void compareJSONArrayWithStrictOrder(String key, JSONArray expected, JSONArray actual, JSONCompareResult result) { - for (int i = 0; i < expected.length(); ++i) { - Object expectedValue = JSONCompareUtil.getObjectOrNull(expected, i); - Object actualValue = JSONCompareUtil.getObjectOrNull(actual, i); + protected void compareJSONArrayWithStrictOrder(String key, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) throws JSONException { + // 20220825 支持不同长度的json array进行对比 + int length = Math.min(expected.length(), actual.length()); + for (int i = length; i < expected.length(); i++) { + if (result.quickFail()) return; + Object expectedValue = expected.get(i); + result.missing(key + "[" + i + "]", expectedValue); + } + for (int i = length; i < actual.length(); i++) { + if (result.quickFail()) return; + Object actualValue = actual.get(i); + result.unexpected(key + "[" + i + "]", actualValue); + } + // 修改对比的范围 + for (int i = 0; i < length; ++i) { + if (result.quickFail()) return; + Object expectedValue = expected.get(i); + Object actualValue = actual.get(i); compareValues(key + "[" + i + "]", expectedValue, actualValue, result); } } @@ -153,20 +169,14 @@ protected void compareJSONArrayWithStrictOrder(String key, JSONArray expected, J // This is expensive (O(n^2) -- yuck), but may be the only resort for some cases with loose array ordering, and no // easy way to uniquely identify each element. protected void recursivelyCompareJSONArray(String key, JSONArray expected, JSONArray actual, - JSONCompareResult result) { + JSONCompareDetailResult result) throws JSONException { Set matched = new HashSet(); for (int i = 0; i < expected.length(); ++i) { - Object expectedElement = JSONCompareUtil.getObjectOrNull(expected, i); + if (result.quickFail()) return; + Object expectedElement = expected.get(i); boolean matchFound = false; for (int j = 0; j < actual.length(); ++j) { - Object actualElement = JSONCompareUtil.getObjectOrNull(actual, j); - if (expectedElement == actualElement) { - matchFound = true; - break; - } - if ((expectedElement == null && actualElement != null) || (expectedElement != null && actualElement == null)) { - continue; - } + Object actualElement = actual.get(j); if (matched.contains(j) || !actualElement.getClass().equals(expectedElement.getClass())) { continue; } @@ -189,9 +199,19 @@ protected void recursivelyCompareJSONArray(String key, JSONArray expected, JSONA } } if (!matchFound) { - result.fail(key + "[" + i + "] Could not find match for element " + expectedElement); - return; + // 没有匹配上的expected element, 记为missing +// result.fail(key + "[" + i + "] Could not find match for element " + expectedElement); + result.missing(key + "[" + i + "]", expectedElement); + } + } + // 未匹配上的actual,记为unexpected + for (int j = 0; j < actual.length(); ++j) { + if (result.quickFail()) return; + Object actualElement = actual.get(j); + if (matched.contains(j)) { + continue; } + result.unexpected(key + "[" + j + "]", actualElement); } } } diff --git a/src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java b/src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java new file mode 100644 index 00000000..f7b5afe9 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java @@ -0,0 +1,119 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.comparator; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import org.json.JSONArray; +import org.json.JSONException; + +import java.text.MessageFormat; + +/** + * A JSONAssert array size comparator. + * + *

Some typical usage idioms are listed below.

+ * + *

Assuming JSON to be verified is held in String variable ARRAY_OF_JSONOBJECTS and contains:

+ * + * {a:[7, 8, 9]} + * + *

then:

+ * + *

To verify that array 'a' contains 3 elements:

+ * + * + * JSONAssert.assertEquals("{a:[3]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(CompareContext.LENIENT)); + * + * + *

To verify that array 'a' contains between 2 and 6 elements:

+ * + * + * JSONAssert.assertEquals("{a:[2,6]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(CompareContext.LENIENT)); + * + * + * @author Duncan Mackinder + */ +public class ArraySizeComparator extends DefaultComparator { + + /** + * Create new ArraySizeComparator. + * + * @param mode comparison mode, has no impact on ArraySizeComparator but is + * used by instance of superclass DefaultComparator to control + * comparison of JSON items other than arrays. + */ + public ArraySizeComparator(CompareContext mode) { + super(mode); + } + + /** + * Expected array should consist of either 1 or 2 integer values that define + * maximum and minimum valid lengths of the actual array. If expected array + * contains a single integer value, then the actual array must contain + * exactly that number of elements. + */ + @Override + public void compareJSONArray(String prefix, JSONArray expected, + JSONArray actual, JSONCompareDetailResult result) throws JSONException { + String arrayPrefix = prefix + "[]"; + if (expected.length() < 1 || expected.length() > 2) { + result.fail(MessageFormat + .format("{0}: invalid expectation: expected array should contain either 1 or 2 elements but contains {1} elements", + arrayPrefix, expected.length())); + return; + } + if (!(expected.get(0) instanceof Number)) { + result.fail(MessageFormat + .format("{0}: invalid expectation: {1}expected array size ''{2}'' not a number", + arrayPrefix, (expected.length() == 1 ? "" : "minimum "), expected.get(0))); + return; + } + if ((expected.length() == 2 && !(expected.get(1) instanceof Number))) { + result.fail(MessageFormat + .format("{0}: invalid expectation: maximum expected array size ''{1}'' not a number", + arrayPrefix, expected.get(1))); + return; + } + int minExpectedLength = expected.getInt(0); + if (minExpectedLength < 0) { + result.fail(MessageFormat + .format("{0}: invalid expectation: minimum expected array size ''{1}'' negative", + arrayPrefix, minExpectedLength)); + return; + } + int maxExpectedLength = expected.length() == 2 ? expected.getInt(1) + : minExpectedLength; + if (maxExpectedLength < minExpectedLength) { + result.fail(MessageFormat + .format("{0}: invalid expectation: maximum expected array size ''{1}'' less than minimum expected array size ''{2}''", + arrayPrefix, maxExpectedLength, minExpectedLength)); + return; + } + if (actual.length() < minExpectedLength + || actual.length() > maxExpectedLength) { + result.fail( + arrayPrefix, + MessageFormat.format( + "array size of {0}{1} elements", + minExpectedLength, + (expected.length() == 2 ? (" to " + maxExpectedLength) + : "")), + MessageFormat.format("{0} elements", + actual.length())); + } + } + +} diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/CustomComparator.java b/src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java similarity index 50% rename from src/main/java/org/skyscreamer/jsonassert/comparator/CustomComparator.java rename to src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java index 73337bdf..ab467b57 100644 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/CustomComparator.java +++ b/src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java @@ -10,14 +10,15 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -package org.skyscreamer.jsonassert.comparator; +package com.nezha.jsondiff.comparator; -import org.skyscreamer.jsonassert.Customization; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.skyscreamer.jsonassert.JSONCompareResult; -import org.skyscreamer.jsonassert.ValueMatcherException; +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.Customization; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.matcher.ValueMatcherException; +import org.json.JSONException; import java.util.Arrays; import java.util.Collection; @@ -26,21 +27,20 @@ public class CustomComparator extends DefaultComparator { private final Collection customizations; - public CustomComparator(JSONCompareMode mode, Customization... customizations) { + public CustomComparator(CompareContext mode, Customization... customizations) { super(mode); this.customizations = Arrays.asList(customizations); } @Override - public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) { + public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareDetailResult result) throws JSONException { Customization customization = getCustomization(prefix); if (customization != null) { try { - if (!customization.matches(prefix, actualValue, expectedValue, result)) { + if (!customization.matches(prefix, actualValue, expectedValue, result, this)) { result.fail(prefix, expectedValue, actualValue); } - } - catch (ValueMatcherException e) { + } catch (ValueMatcherException e) { result.fail(prefix, e); } } else { @@ -48,6 +48,26 @@ public void compareValues(String prefix, Object expectedValue, Object actualValu } } + // 对黑名单做特殊的排除处理 + @Override + public void markMissing(String prefix, Object expected, JSONCompareDetailResult result) { + Customization customization = getCustomization(prefix); + if (customization != null && customization.instanceOfMatcher().equals("IngorePathMatcher")) { + return; + } + result.missing(prefix, JSONCompareUtil.getIfNull(expected)); + } + + // 对黑名单做特殊的排除处理 + @Override + public void markUnexpected(String prefix, Object actual, JSONCompareDetailResult result) { + Customization customization = getCustomization(prefix); + if (customization != null && customization.instanceOfMatcher().equals("IngorePathMatcher")) { + return; + } + result.unexpected(prefix, JSONCompareUtil.getIfNull(actual)); + } + private Customization getCustomization(String path) { for (Customization c : customizations) if (c.appliesToPath(path)) diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/DefaultComparator.java b/src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java similarity index 51% rename from src/main/java/org/skyscreamer/jsonassert/comparator/DefaultComparator.java rename to src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java index 1e8efc01..c85a2718 100644 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/DefaultComparator.java +++ b/src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java @@ -10,32 +10,34 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ -package org.skyscreamer.jsonassert.comparator; +package com.nezha.jsondiff.comparator; +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.skyscreamer.jsonassert.JSONCompareResult; -import static org.skyscreamer.jsonassert.comparator.JSONCompareUtil.allJSONObjects; -import static org.skyscreamer.jsonassert.comparator.JSONCompareUtil.allSimpleValues; +import static com.nezha.jsondiff.comparator.JSONCompareUtil.allJSONObjects; +import static com.nezha.jsondiff.comparator.JSONCompareUtil.allSimpleValues; /** * This class is the default json comparator implementation. - * Comparison is performed according to {@link JSONCompareMode} that is passed as constructor's argument. + * Comparison is performed according to {@link CompareContext} that is passed as constructor's argument. */ public class DefaultComparator extends AbstractComparator { - JSONCompareMode mode; + CompareContext mode; - public DefaultComparator(JSONCompareMode mode) { + public DefaultComparator(CompareContext mode) { this.mode = mode; } @Override - public void compareJSON(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) { + public void compareJSON(String prefix, JSONObject expected, JSONObject actual, JSONCompareDetailResult result) + throws JSONException { // Check that actual contains all the expected values checkJsonObjectKeysExpectedInActual(prefix, expected, actual, result); @@ -46,13 +48,9 @@ public void compareJSON(String prefix, JSONObject expected, JSONObject actual, J } @Override - public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) { - if (expectedValue == actualValue) { - return; - } - if (expectedValue == null || actualValue == null) { - result.fail(prefix, expectedValue, actualValue); - } else if (areNumbers(expectedValue, actualValue)) { + public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareDetailResult result) + throws JSONException { + if (areNumbers(expectedValue, actualValue)) { if (areNotSameDoubles(expectedValue, actualValue)) { result.fail(prefix, expectedValue, actualValue); } @@ -65,19 +63,35 @@ public void compareValues(String prefix, Object expectedValue, Object actualValu result.fail(prefix, expectedValue, actualValue); } } else { - result.fail(prefix, expectedValue, actualValue); + // Added special handling for NUll, serialization issue due to jackson not recognizing JSONObject.NULL, + // It can only be converted to normal null; Just deal with it here, because only with different types, the null error will appear + result.fail(prefix, JSONCompareUtil.getIfNull(expectedValue), + JSONCompareUtil.getIfNull(actualValue)); } } @Override - public void compareJSONArray(String prefix, JSONArray expected, JSONArray actual, JSONCompareResult result) { - if (expected.length() != actual.length()) { - result.fail(prefix + "[]: Expected " + expected.length() + " values but got " + actual.length()); - return; - } else if (expected.length() == 0) { - return; // Nothing to compare - } + public void compareJSONArray(String prefix, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) + throws JSONException { + // 删除Array长度不一致则失败的判断 +// if (mode.hasStrictOrder()) { +// compareJSONArrayWithStrictOrder(prefix, expected, actual, result); +// } else if (allSimpleValues(expected)) { +// compareJSONArrayOfSimpleValues(prefix, expected, actual, result); +// } else if (allJSONObjects(expected)) { +// compareJSONArrayOfJsonObjects(prefix, expected, actual, result); +// } else { +// // An expensive last resort +// recursivelyCompareJSONArray(prefix, expected, actual, result); +// } + compareJSONArray(mode, prefix, expected, actual, result); + } + @Override + public void compareJSONArray(CompareContext mode, String prefix, JSONArray expected, + JSONArray actual, JSONCompareDetailResult result) + throws JSONException { + // 删除Array长度不一致则失败的判断 if (mode.hasStrictOrder()) { compareJSONArrayWithStrictOrder(prefix, expected, actual, result); } else if (allSimpleValues(expected)) { @@ -90,6 +104,22 @@ public void compareJSONArray(String prefix, JSONArray expected, JSONArray actual } } + @Override + public void markMissing(String prefix, Object expected, JSONCompareDetailResult result) { + result.missing(prefix, JSONCompareUtil.getIfNull(expected)); + } + + @Override + public void markUnexpected(String prefix, Object actual, JSONCompareDetailResult result) { + result.unexpected(prefix, JSONCompareUtil.getIfNull(actual)); + } + + @Override + public void markResultFeature(JSONCompareDetailResult result) { + if (mode.needQuickFail()) result.setComplete(false); + if (mode.needIgnoreNull()) result.setIgnoreNull(true); + } + protected boolean areNumbers(Object expectedValue, Object actualValue) { return expectedValue instanceof Number && actualValue instanceof Number; } diff --git a/src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java b/src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java new file mode 100644 index 00000000..3c970f46 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java @@ -0,0 +1,130 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.comparator; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Interface for comparison handler. + * + * @author Ivan Zaytsev + * 2013-01-04 + */ +public interface JSONComparator { + + /** + * Compares two {@link JSONObject}s and returns the result of the comparison in a {@link JSONCompareDetailResult} object. + * + * @param expected the expected JSON object + * @param actual the actual JSON object + * @return the result of the comparison + * @throws JSONException JSON parsing error + */ + JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual) throws JSONException; + + /** + * Compares two {@link JSONArray}s and returns the result of the comparison in a {@link JSONCompareDetailResult} object. + * + * @param expected the expected JSON array + * @param actual the actual JSON array + * @return the result of the comparison + * @throws JSONException JSON parsing error + */ + JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual) throws JSONException; + + /** + * Compares two {@link JSONObject}s on the provided path represented by {@code prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param prefix the path in the json where the comparison happens + * @param expected the expected JSON object + * @param actual the actual JSON object + * @param result stores the actual state of the comparison result + * @throws JSONException JSON parsing error + */ + void compareJSON(String prefix, JSONObject expected, JSONObject actual, JSONCompareDetailResult result) throws JSONException; + + /** + * Compares two {@link Object}s on the provided path represented by {@code prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param prefix the path in the json where the comparison happens + * @param expectedValue the expected value + * @param actualValue the actual value + * @param result stores the actual state of the comparison result + * @throws JSONException JSON parsing error + */ + void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareDetailResult result) throws JSONException; + + /** + * Compares two {@link JSONArray}s on the provided path represented by {@code prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param prefix the path in the json where the comparison happens + * @param expected the expected JSON array + * @param actual the actual JSON array + * @param result stores the actual state of the comparison result + * @throws JSONException JSON parsing error + */ + void compareJSONArray(String prefix, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) throws JSONException; + + /** + * Compares two {@link JSONArray}s on the provided path represented by {@code prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param mode define different behavior for the comparison of JSON + * @param prefix the path in the json where the comparison happens + * @param expected the expected JSON array + * @param actual the actual JSON array + * @param result stores the actual state of the comparison result + * @throws JSONException JSON parsing error + */ + void compareJSONArray(CompareContext mode, String prefix, JSONArray expected, JSONArray actual, JSONCompareDetailResult result) + throws JSONException; + + /** + * Mark missing field of expected {@link Object}s on the provided path represented by {@code + * prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param prefix the path in the json where the comparison happens + * @param expected the expected element + * @param result stores the actual state of the comparison result + */ + void markMissing(String prefix, Object expected, JSONCompareDetailResult result); + + /** + * Mark unexpected field of actual {@link Object}s on the provided path represented by {@code + * prefix} and + * updates the result of the comparison in the {@code result} {@link JSONCompareDetailResult} object. + * + * @param prefix the path in the json where the comparison happens + * @param actual the expected element + * @param result stores the actual state of the comparison result + */ + void markUnexpected(String prefix, Object actual, JSONCompareDetailResult result); + + /** + * Mark the result of the comparison in the {@code result} {@link JSONCompareDetailResult} if + * it should have completed comparison. + * + * @param result stores the actual state of the comparison result + */ + void markResultFeature(JSONCompareDetailResult result); +} diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtil.java b/src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java similarity index 70% rename from src/main/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtil.java rename to src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java index 8a7fe18d..cdb4ecd7 100644 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtil.java +++ b/src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java @@ -10,31 +10,24 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; + */ -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +package com.nezha.jsondiff.comparator; +import org.apache.commons.lang.StringUtils; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; +import java.util.*; + /** * Utility class that contains Json manipulation methods. */ public final class JSONCompareUtil { - private static Integer INTEGER_ONE = new Integer(1); + public static final double UNIQUE_KEY_WEIGHT = 1.0; + private static final Integer INTEGER_ONE = new Integer(1); - private JSONCompareUtil() { - } /** * Converts the provided {@link JSONArray} to a Map of {@link JSONObject}s where the key of each object @@ -43,8 +36,9 @@ private JSONCompareUtil() { * @param array the JSON array to convert * @param uniqueKey the key to map the JSON objects to * @return the map of {@link JSONObject}s from {@code array} + * @throws JSONException JSON parsing error */ - public static Map arrayOfJsonObjectToMap(JSONArray array, String uniqueKey) { + public static Map arrayOfJsonObjectToMap(JSONArray array, String uniqueKey) throws JSONException { Map valueMap = new HashMap(); for (int i = 0; i < array.length(); ++i) { JSONObject jsonObject = (JSONObject) array.get(i); @@ -59,8 +53,9 @@ public static Map arrayOfJsonObjectToMap(JSONArray array, St * * @param expected the array to find the unique key of * @return the unique key if there's any, otherwise null + * @throws JSONException JSON parsing error */ - public static String findUniqueKey(JSONArray expected) { + public static String findUniqueKey(JSONArray expected) throws JSONException { // Find a unique key for the object (id, name, whatever) JSONObject o = (JSONObject) expected.get(0); // There's at least one at this point for (String candidate : getKeys(o)) { @@ -81,10 +76,11 @@ public static String findUniqueKey(JSONArray expected) { * * * @param candidate is usable as a unique key if every element in the - * @param array is a JSONObject having that key, and no two values are the same. + * @param array is a JSONObject having that key, and no two values are the same. * @return true if the candidate can work as a unique id across array + * @throws JSONException JSON parsing error */ - public static boolean isUsableAsUniqueKey(String candidate, JSONArray array) { + public static boolean isUsableAsUniqueKey(String candidate, JSONArray array) throws JSONException { Set seenValues = new HashSet(); for (int i = 0; i < array.length(); i++) { Object item = array.get(i); @@ -107,41 +103,60 @@ public static boolean isUsableAsUniqueKey(String candidate, JSONArray array) { return true; } + /** + *

Looks to see if unique key is a usable for both expected and actual. + * Returns true IFF:

+ *
    + *
  1. expected unique key val should be same as actual + *
  2. otherwise, it makes no sense to have the unique key + *
+ * + * @param expected a map of expected JSONArray, of key with unique key value + * @param actual a map of actual JSONArray, of key with unique key value + * @return true if the same unique key value is more than UNIQUE_KEY_WEIGHT + */ + public static boolean isUsableAsUniqueKeyForBothMap(Map expected, + Map actual) { + int count = 0; + for (Object keyVal : expected.keySet()) { + if (actual.containsKey(keyVal)) { + count++; + } + } + return (double) count / expected.size() >= UNIQUE_KEY_WEIGHT; + } + /** * Converts the given {@link JSONArray} to a list of {@link Object}s. * * @param expected the JSON array to convert * @return the list of objects from the {@code expected} array + * @throws JSONException JSON parsing error */ - public static List jsonArrayToList(JSONArray expected) { + public static List jsonArrayToList(JSONArray expected) throws JSONException { List jsonObjects = new ArrayList(expected.length()); for (int i = 0; i < expected.length(); ++i) { - jsonObjects.add(getObjectOrNull(expected, i)); + Object o = expected.get(i); + if (o instanceof Double && (int) ((double) o) == (double) o) { + jsonObjects.add((int) ((double) o)); + } else { + jsonObjects.add(o); + } } return jsonObjects; } - /** - * Returns the value present in the given index position. If null value is present, it will return null - * - * @param jsonArray the JSON array to get value from - * @param index index of object to retrieve - * @return value at the given index position - */ - public static Object getObjectOrNull(JSONArray jsonArray, int index) { - return jsonArray.isNull(index) ? null : jsonArray.get(index); - } - /** * Returns whether all of the elements in the given array are simple values. * * @param array the JSON array to iterate through on * @return true if all the elements in {@code array} are simple values + * @throws JSONException JSON parsing error * @see #isSimpleValue(Object) */ - public static boolean allSimpleValues(JSONArray array) { + public static boolean allSimpleValues(JSONArray array) throws JSONException { for (int i = 0; i < array.length(); ++i) { - if (!array.isNull(i) && !isSimpleValue(array.get(i))) { + if (!isSimpleValue(array.get(i))) { return false; } } @@ -163,8 +178,9 @@ public static boolean isSimpleValue(Object o) { * * @param array the array to inspect * @return true if all the elements in the given array are JSONObjects + * @throws JSONException JSON parsing error */ - public static boolean allJSONObjects(JSONArray array) { + public static boolean allJSONObjects(JSONArray array) throws JSONException { for (int i = 0; i < array.length(); ++i) { if (!(array.get(i) instanceof JSONObject)) { return false; @@ -178,8 +194,9 @@ public static boolean allJSONObjects(JSONArray array) { * * @param array the array to inspect * @return true if all the elements in the given array are JSONArrays + * @throws JSONException JSON parsing error */ - public static boolean allJSONArrays(JSONArray array) { + public static boolean allJSONArrays(JSONArray array) throws JSONException { for (int i = 0; i < array.length(); ++i) { if (!(array.get(i) instanceof JSONArray)) { return false; @@ -230,4 +247,28 @@ public static Map getCardinalityMap(final Collection coll) { } return count; } + + /** + * convert to Object.NUll when object is JSONObject.NULL + * + * @param o the collection of items to convert + * @return o or null + */ + public static Object getIfNull(Object o) { + if (o.equals(JSONObject.NULL)) { + return null; + } + return o; + } + + // get param value from yaml,format: "key=key001", return key001 + public static String getParamValue(String param) { + if (StringUtils.isNotBlank(param)) { + return param.replaceAll(" ", "").trim().split("=")[1]; + } + + return null; + } + + } diff --git a/src/main/java/com/nezha/jsondiff/constant/Param.java b/src/main/java/com/nezha/jsondiff/constant/Param.java new file mode 100644 index 00000000..eb674986 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/constant/Param.java @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.constant; + +public class Param { + public static final String STRICT_ORDER = "strictOrder"; + public static final String JSON_PATH_KEY = "jsonPath"; + public static final String EXTENSIBLE_KEY = "extensible"; + public static final String FAST_FAIL_KEY = "fastFail"; + public static final String MODE_KEY = "mode"; + public static final String PRE_PROCESS_KEY = "preProcess"; + public static final String CUSTOM_RULES_KEY = "customRules"; + public static final String PARAM_KEY = "param"; + public static final String NAME_KEY = "name"; + public static final String IGNORE_NULL_KEY = "ignoreNull"; + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java new file mode 100644 index 00000000..7d16c0b8 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +/** + * Function: + * + */ + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONArray; +import org.json.JSONException; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects

* + */ +public class ArrayDisorderMatcher implements CustomValueMatcher { + /** + * Create ArrayDisorderMatcher to match every JsonObject by order + * + */ + public ArrayDisorderMatcher() {} + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + public void matcherInit(String param, CompareContext compareContext) {} + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + if (!(actual instanceof JSONArray)) { + throw new IllegalArgumentException("ArrayObjectValueMatcher applied to non-array actual value"); + } + try { + JSONArray actualArray = (JSONArray) actual; + JSONArray expectedArray = expected instanceof JSONArray ? (JSONArray) expected: new JSONArray(new Object[] { expected }); + CompareContext mode = new CompareContext(false,false, false, false); + comparator.compareJSONArray(mode, prefix, expectedArray, + actualArray, result); + + // any failures have already been passed to result, so return true + return true; + } + catch (JSONException e) { + return false; + } + } + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java new file mode 100644 index 00000000..5b327d96 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java @@ -0,0 +1,71 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nezha.jsondiff.matcher; + +/** + * Function: + * + * + */ + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONArray; +import org.json.JSONException; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects

* + */ +public class ArrayInOrderMatcher implements CustomValueMatcher { + /** + * Create ArrayInOrderMatcher to match every JsonObject by order + * + */ + public ArrayInOrderMatcher() {} + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + @Override + public void matcherInit(String param, CompareContext compareContext) {} + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + if (!(actual instanceof JSONArray)) { + throw new IllegalArgumentException("ArrayObjectValueMatcher applied to non-array actual value"); + } + try { + JSONArray actualArray = (JSONArray) actual; + JSONArray expectedArray = expected instanceof JSONArray ? (JSONArray) expected: new JSONArray(new Object[] { expected }); + CompareContext mode = new CompareContext(false,true, false, false); + comparator.compareJSONArray(mode, prefix, expectedArray, actualArray, + result); + + // any failures have already been passed to result, so return true + return true; + } + catch (JSONException e) { + return false; + } + } + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java new file mode 100644 index 00000000..fca10c43 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java @@ -0,0 +1,73 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +/** + */ + +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONArray; +import org.json.JSONException; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects

* + */ +public class ArrayLengthMatcher implements CustomValueMatcher { + /** + * Create ArrayLengthMatcher to match the length of Array + * + */ + public ArrayLengthMatcher() {} + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + @Override + public void matcherInit(String param, CompareContext compareContext) {} + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + if (!(actual instanceof JSONArray)) { + throw new IllegalArgumentException("ArrayObjectValueMatcher applied to non-array actual value"); + } + try { + JSONArray actualArray = (JSONArray) actual; + JSONArray expectedArray = expected instanceof JSONArray ? (JSONArray) expected: new JSONArray(new Object[] { expected }); + + int actualLen = actualArray.length(); + int expectedLen = expectedArray.length(); + + if (actualLen != expectedLen) { + throw new ValueMatcherException("compare JSON Array Length", String.valueOf(expectedLen), + String.valueOf(actualLen)); + } + + return true; + } + catch (JSONException e) { + return false; + } + } + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java new file mode 100644 index 00000000..08e16370 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java @@ -0,0 +1,133 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package com.nezha.jsondiff.matcher; + +/** + * Function: + * + */ + +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashSet; +import java.util.Set; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects

* + */ +public class ArrayRecursivelyMatcher implements CustomValueMatcher { + + private boolean extensible; + + public ArrayRecursivelyMatcher() { + this(false); + } + + public ArrayRecursivelyMatcher(boolean extensible) { + this.extensible = extensible; + } + + public ArrayRecursivelyMatcher(String extensible) { + this.extensible = extensible.equals("true"); + } + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + if (!(actual instanceof JSONArray)) { + throw new IllegalArgumentException("ArrayObjectValueMatcher applied to non-array actual value"); + } + try { + JSONArray actualArray = (JSONArray) actual; + JSONArray expectedArray = expected instanceof JSONArray ? (JSONArray) expected: new JSONArray(new Object[] { expected }); + + Set matched = new HashSet(); + for (int i = 0; i < expectedArray.length(); ++i) { + if (result.quickFail()) return true; + Object expectedArrayElement = expectedArray.get(i); + boolean matchFound = false; + for (int j = 0; j < actualArray.length(); ++j) { + Object actualArrayElement = actualArray.get(j); + if (matched.contains(j) || !actualArrayElement.getClass().equals(expectedArrayElement.getClass())) { + continue; + } + if (expectedArrayElement instanceof JSONObject) { + if (comparator.compareJSON((JSONObject) expectedArrayElement, + (JSONObject) actualArrayElement).passed()) { + matched.add(j); + matchFound = true; + break; + } + } else if (expectedArrayElement instanceof JSONArray) { + if (comparator.compareJSON((JSONArray) expectedArrayElement, + (JSONArray) actualArrayElement).passed()) { + matched.add(j); + matchFound = true; + break; + } + } else if (expectedArrayElement.equals(actualArrayElement)) { + matched.add(j); + matchFound = true; + break; + } + } + if (!matchFound) { + +// result.fail(key + "[" + i + "] Could not find match for element " + expectedArrayElement); + result.missing(prefix + "[" + i + "]", expectedArrayElement); + } + } + + // If it's loose mode, you don't need to record the extra elements in the actualArray + if (extensible) return true; + + // not match actualArray,as unexpectedArray + for(int j = 0; j < actualArray.length(); ++j) { + if (result.quickFail()) return true; + Object actualArrayElement = actualArray.get(j); + if (matched.contains(j)) { + continue; + } + result.unexpected(prefix + "[" + j + "]", actualArrayElement); + } + + // any failures have already been passed to result, so return true + return true; + } + catch (JSONException e) { + return false; + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + this.extensible = compareContext.getExtensible(); + } + +} diff --git a/src/main/java/org/skyscreamer/jsonassert/ArrayValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java similarity index 97% rename from src/main/java/org/skyscreamer/jsonassert/ArrayValueMatcher.java rename to src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java index 2d4dd8ec..dd76f88b 100644 --- a/src/main/java/org/skyscreamer/jsonassert/ArrayValueMatcher.java +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java @@ -12,13 +12,15 @@ * limitations under the License. */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff.matcher; import java.text.MessageFormat; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.CompareContext; import org.json.JSONArray; import org.json.JSONException; -import org.skyscreamer.jsonassert.comparator.JSONComparator; +import com.nezha.jsondiff.comparator.JSONComparator; /** *

A value matcher for arrays. This operates like STRICT_ORDER array match, @@ -195,7 +197,7 @@ public boolean equal(T o1, T o2) { } @Override - public boolean equal(String prefix, T actual, T expected, JSONCompareResult result) { + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result) { if (!(actual instanceof JSONArray)) { throw new IllegalArgumentException("ArrayValueMatcher applied to non-array actual value"); } @@ -219,4 +221,7 @@ public boolean equal(String prefix, T actual, T expected, JSONCompareResult resu } } + @Override + public void matcherInit(String param, CompareContext compareContext) {} + } diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java new file mode 100644 index 00000000..0d815b33 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java @@ -0,0 +1,131 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package com.nezha.jsondiff.matcher; + + + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.comparator.JSONComparator; +import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; + +import static com.nezha.jsondiff.comparator.JSONCompareUtil.arrayOfJsonObjectToMap; +import static com.nezha.jsondiff.comparator.JSONCompareUtil.formatUniqueKey; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects, of which the + * unique key provided by member variables

* + */ +public class ArrayWithKeyMatcher implements CustomValueMatcher { + private String uniqueKey; + + private boolean extensible; + + public ArrayWithKeyMatcher(){} + + /** + * Create ArrayObjectValueMatcher to match every JsonObject by unique + * key. + * @param uniqueKey the unique key to identify JsonObject + * @param extensible if true, allows keys in actual that don't appear in expected + */ + public ArrayWithKeyMatcher(String uniqueKey, boolean extensible) { + assert uniqueKey != null && !uniqueKey.isEmpty() : "uniqueKey null or empty"; + this.uniqueKey = uniqueKey; + this.extensible = extensible; + } + + public ArrayWithKeyMatcher(String path, String param, CompareContext compareContext){ + this.uniqueKey = param; + this.extensible = compareContext.getExtensible(); + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + this.extensible = compareContext.getExtensible(); + this.uniqueKey = JSONCompareUtil.getParamValue(param); + } + + /** + * Create ArrayObjectValueMatcher to match every JsonObject by unique + * key. + * @param uniqueKey the unique key to identify JsonObject + * @param extensible if true, allows keys in actual that don't appear in expected + */ + public ArrayWithKeyMatcher(String uniqueKey, String extensible) { + this (uniqueKey, extensible.equals("true")); + } + + /** + * Create ArrayObjectValueMatcher to match every JsonObject by unique + * key. + * + * @param uniqueKey the unique key to identify JsonObject + */ + public ArrayWithKeyMatcher(String uniqueKey) { + this (uniqueKey, false); + } + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + if (!(actual instanceof JSONArray)) { + throw new IllegalArgumentException("ArrayObjectValueMatcher applied to non-array actual value"); + } + try { + JSONArray actualArray = (JSONArray) actual; + JSONArray expectedArray = expected instanceof JSONArray ? (JSONArray) expected: new JSONArray(new Object[] { expected }); + Map expectedValueMap = arrayOfJsonObjectToMap(expectedArray, uniqueKey); + Map actualValueMap = arrayOfJsonObjectToMap(actualArray, uniqueKey); + for (Object id : expectedValueMap.keySet()) { + if (result.quickFail()) return true; + if (!actualValueMap.containsKey(id)) { + result.missing(formatUniqueKey(prefix, uniqueKey, id), expectedValueMap.get(id)); + continue; + } + JSONObject expectedValue = expectedValueMap.get(id); + JSONObject actualValue = actualValueMap.get(id); + comparator.compareValues(formatUniqueKey(prefix, uniqueKey, id), expectedValue, + actualValue, result); + } + for (Object id : actualValueMap.keySet()) { + if (extensible || result.quickFail()) return true; + if (!expectedValueMap.containsKey(id)) { + result.unexpected(formatUniqueKey(prefix, uniqueKey, id), actualValueMap.get(id)); + } + } + + // any failures have already been passed to result, so return true + return true; + } + catch (JSONException e) { + return false; + } + } +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java new file mode 100644 index 00000000..30982f61 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java @@ -0,0 +1,67 @@ +/* + * LenientValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.comparator.DefaultComparator; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONException; + +/** + * Function: + * + * + */ +public class ComparatorValueMatcher implements + LocationAwareValueMatcher { + private JSONComparator comparator; + + ComparatorValueMatcher() { + CompareContext mode = new CompareContext(true, true, false, false); + comparator = new DefaultComparator(mode); + } + + ComparatorValueMatcher(CompareContext mode) { + comparator = new DefaultComparator(mode); + } + + + ComparatorValueMatcher(JSONComparator comparator) { + this.comparator = comparator; + } + + @Override + public boolean equal(T o1, T o2) { + return false; + } + + @Override + public boolean equal(String prefix, T actual, T expected, + JSONCompareDetailResult result) + throws ValueMatcherException { + try { + comparator.compareValues(prefix, actual, expected, result); + return true; + }catch (JSONException e) { + return false; + } + } + @Override + public void matcherInit(String param, CompareContext compareContext) { + + } +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java new file mode 100644 index 00000000..2e66e96d --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java @@ -0,0 +1,57 @@ +//f0aa7e0a364165582abddc4c4eed3ddf +/* + * CustomValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.comparator.JSONComparator; + +/** + * Function: + * + */ +public interface CustomValueMatcher extends ValueMatcher { + /** + * Match actual value with expected value. If match fails any of the + * following may occur, return false, pass failure details to specified + * JSONCompareDetailResult and return true, or throw ValueMatcherException + * containing failure details. Passing failure details to JSONCompareDetailResult + * or returning via ValueMatcherException enables more useful failure + * description for cases where expected value depends entirely or in part on + * configuration of the ValueMatcher and therefore expected value passed to + * this method will not give a useful indication of expected value. + * + * @param prefix + * JSON path of the JSON item being tested + * @param actual + * JSON value being tested + * @param expected + * expected JSON value + * @param result + * JSONCompareDetailResult to which match failure may be passed + * @param comparator + * JSONComparator use to compare elements + * @return true if expected and actual equal or any difference has already + * been passed to specified result instance, false otherwise. + * @throws ValueMatcherException + * if expected and actual values not equal and ValueMatcher + * needs to override default comparison failure message that + * would be generated if this method returned false. + */ + boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, + JSONComparator comparator) throws ValueMatcherException; + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java new file mode 100644 index 00000000..5896fbd6 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java @@ -0,0 +1,60 @@ +/* + * ImpreciseAngleValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.util.Objects; + + +public class DegreePreciseMatcher implements ValueMatcher { + private double tolerance; + + public DegreePreciseMatcher() { this (10e-5); } + + public DegreePreciseMatcher(double tolerance) { + this.tolerance = tolerance; + } + + @Override + public boolean equal(T actual, T expected){ + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + + if (actualNum.doubleValue() > 360 || actualNum.doubleValue() < -360 + || expectedNum.doubleValue() >360 || expectedNum.doubleValue() <-360){ + return false; + } + + Double diffAngle = (expectedNum.doubleValue() + 180) % 180 - (actualNum.doubleValue() + 180) % 180; + + return Math.abs(diffAngle) <= tolerance; + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + this.tolerance = + Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + } + +} + diff --git a/src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java new file mode 100644 index 00000000..913c0563 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java @@ -0,0 +1,67 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package com.nezha.jsondiff.matcher; + +/** + * Function: + * + * + */ + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.json.JSONArray; +import org.json.JSONObject; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects

* + */ +public class EmptyValueMatcher implements ValueMatcher { + /** + * Create EmptyValueValueMatcher to match every empty elements, + * eg. empty array, empty object, null, empty String + * + */ + public EmptyValueMatcher() {} + + @Override + public boolean equal(T actual, T expected) { + + return isEmpty(actual) && isEmpty(expected); + } + + private boolean isEmpty(T value) { + if (value instanceof JSONArray && ((JSONArray) value).length() == 0) { + return true; + } + + if (value instanceof JSONObject && value.toString().equals("{}")) { + return true; + } + + if (value instanceof String && ((String) value).isEmpty()) { + return true; + } + + return JSONCompareUtil.getIfNull(value) == null; + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + + } + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java new file mode 100644 index 00000000..f4ea71b0 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java @@ -0,0 +1,71 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package com.nezha.jsondiff.matcher; + +/** + * Function: + * + */ + +import com.nezha.jsondiff.JSONCompareDetailResult; +import com.nezha.jsondiff.JSONParser; +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONComparator; +import org.json.JSONException; + +import java.text.MessageFormat; + +/** + *

A value matcher for arrays of JsonObjects. This operates like + * AbstractComparator.compareJSONArrayOfJsonObjects, of which the + * unique key provided by member variables

* + */ +public class EscapedJsonMatcher implements CustomValueMatcher { + + @Override + /* + * NOTE: method defined as required by ValueMatcher interface but will never + * be called so defined simply to indicate match failure + */ + public boolean equal(T o1, T o2) { + return false; + } + + public void EscapedJsonMatcher(){} + + @Override + public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { + String newPrefix = MessageFormat.format("{0}.", prefix); + String expectedStr = String.valueOf(expected); + String actualStr = String.valueOf(actual); + try { + Object expectedJSON = JSONParser.parseEscapedJSON(expectedStr); + Object actualJSON = JSONParser.parseEscapedJSON(actualStr); + + comparator.compareValues(newPrefix, expectedJSON, actualJSON, result); + + // any failures have already been passed to result, so return true + return true; + } + catch (JSONException e) { + return expectedStr.equals(actualStr); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + } + +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java new file mode 100644 index 00000000..c558cdc4 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java @@ -0,0 +1,90 @@ +/* + * ImprecisePositionMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.util.Objects; + +/** + * Function: Imprecise position comparison (front-end model data) + * position the value is in the form of a string,eg: {"position": "-300.0,-250.0"} + */ +public class ImprecisePositionMatcher implements ValueMatcher { + private double tolerance; + private String separator; + + public ImprecisePositionMatcher() { this (10e-3, ","); } + + public ImprecisePositionMatcher(double tolerance) { + this (tolerance, ","); + } + + public ImprecisePositionMatcher(double tolerance, String seperator) { + this.tolerance = tolerance; + this.separator = seperator; + } + + @Override + public boolean equal(T actual, T expected){ + return compare(actual.toString(), expected.toString(), separator); + } + + private boolean compare(String actual, String expected, String sep) { + if (sep.isEmpty()) return compareNums(actual, expected); + + String curSep = sep.substring(0, 1); + String[] actualArr = actual.split(curSep); + String[] expectedArr = expected.split(curSep); + + if (expectedArr.length != actualArr.length ){ + return false; + } + + for (int i = 0; i < actualArr.length; i++) { + if (!compare(actualArr[i], expectedArr[i], sep.substring(1))) return false; + } + + return true; + + } + + private boolean compareNums(String actual, String expected) { + try { + BigDecimal actualNum = new BigDecimal(actual); + BigDecimal expectedNum = new BigDecimal(expected); + BigDecimal diffValue = actualNum.subtract(expectedNum).abs(); + if (diffValue.compareTo(BigDecimal.valueOf(tolerance)) == 1 ){ + return false; + } + return true; + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + //format tolerance=1e-3;separator=, + tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue( + param.replaceAll(" ", "").trim().split(";")[0]))); + + separator = Objects.requireNonNull(JSONCompareUtil.getParamValue( + param.replaceAll(" ", "").trim().split(";")[1])); + } +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java new file mode 100644 index 00000000..0326dd30 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; + +/** + * Function: + * + * + */ +public class IngorePathMatcher implements ValueMatcher { + + public IngorePathMatcher() {} + @Override + public boolean equal(T o1, T o2) { + return true; + } + + @Override + public void matcherInit(String param, CompareContext compareContext) {} + +} diff --git a/src/main/java/org/skyscreamer/jsonassert/LocationAwareValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java similarity index 83% rename from src/main/java/org/skyscreamer/jsonassert/LocationAwareValueMatcher.java rename to src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java index cc2b7449..c3b0084a 100644 --- a/src/main/java/org/skyscreamer/jsonassert/LocationAwareValueMatcher.java +++ b/src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java @@ -15,7 +15,9 @@ /** * */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.JSONCompareDetailResult; /** * A ValueMatcher extension that provides location in form of prefix to the equals method. @@ -28,8 +30,8 @@ public interface LocationAwareValueMatcher extends ValueMatcher { /** * Match actual value with expected value. If match fails any of the * following may occur, return false, pass failure details to specified - * JSONCompareResult and return true, or throw ValueMatcherException - * containing failure details. Passing failure details to JSONCompareResult + * JSONCompareDetailResult and return true, or throw ValueMatcherException + * containing failure details. Passing failure details to JSONCompareDetailResult * or returning via ValueMatcherException enables more useful failure * description for cases where expected value depends entirely or in part on * configuration of the ValueMatcher and therefore expected value passed to @@ -42,7 +44,7 @@ public interface LocationAwareValueMatcher extends ValueMatcher { * @param expected * expected JSON value * @param result - * JSONCompareResult to which match failure may be passed + * JSONCompareDetailResult to which match failure may be passed * @return true if expected and actual equal or any difference has already * been passed to specified result instance, false otherwise. * @throws ValueMatcherException @@ -50,5 +52,5 @@ public interface LocationAwareValueMatcher extends ValueMatcher { * needs to override default comparison failure message that * would be generated if this method returned false. */ - boolean equal(String prefix, T actual, T expected, JSONCompareResult result) throws ValueMatcherException; + boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result) throws ValueMatcherException; } diff --git a/src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java new file mode 100644 index 00000000..ac683223 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java @@ -0,0 +1,67 @@ +/* + * NumberPreciseMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Objects; + + +public class NumberPreciseMatcher implements ValueMatcher{ + private int newScale; + private int roundingMode; + + public NumberPreciseMatcher() { + this(6, 4); + } + + public NumberPreciseMatcher(int newScale) { + this(newScale, 4); + } + + public NumberPreciseMatcher(int newScale, int roundingMode) { + this.newScale = newScale; + this.roundingMode = roundingMode; + } + + @Override + public boolean equal(T actual, T expected) { + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + + BigDecimal actualNumNew = actualNum.setScale(newScale, RoundingMode.valueOf(roundingMode)); + BigDecimal expectedNumNew = expectedNum.setScale(newScale, + RoundingMode.valueOf(roundingMode)); + + return actualNumNew.equals(expectedNumNew); + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + newScale = Integer.parseInt(Objects.requireNonNull(JSONCompareUtil.getParamValue( + param.replaceAll(" ", "").trim().split(",")[0]))); + + roundingMode = Integer.parseInt(Objects.requireNonNull(JSONCompareUtil.getParamValue( + param.replaceAll(" ", "").trim().split(",")[1]))); + } +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java new file mode 100644 index 00000000..e8714cc3 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java @@ -0,0 +1,52 @@ +/* + * TolerantValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.util.Objects; + +/** + * Function: Percentage tolerance matching + */ +public class PercentTolerantMatcher implements ValueMatcher { + private double tolerance; + + public PercentTolerantMatcher() { this (10e-3); } + + public PercentTolerantMatcher(double tolerance) { this.tolerance = tolerance; } + + @Override + public boolean equal(T actual, T expected){ + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + BigDecimal diffValue = actualNum.subtract(expectedNum).abs(); + BigDecimal percent = diffValue.divide(expectedNum).abs(); + + return percent.compareTo(BigDecimal.valueOf(tolerance)) != 1; + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + } +} diff --git a/src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java new file mode 100644 index 00000000..1cd4b097 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java @@ -0,0 +1,60 @@ +/* + * ImpreciseRotateValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.util.Objects; + +/** + * Function: inaccurate radian matcher + */ + +public class RadianPreciseMatcher implements ValueMatcher { + private double tolerance; + + public RadianPreciseMatcher() { this (10e-5); } + + public RadianPreciseMatcher(double tolerance) { + this.tolerance = tolerance; + } + + @Override + public boolean equal(T actual, T expected){ + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + if (actualNum.doubleValue() > (2 * Math.PI) || actualNum.doubleValue() < -(2 * Math.PI) + || expectedNum.doubleValue() >(2 * Math.PI) || expectedNum.doubleValue() < -(2 * Math.PI)){ + return false; + } + + Double diffAngle = (expectedNum.doubleValue() + Math.PI) % Math.PI - (actualNum.doubleValue() + Math.PI) % Math.PI; + + return Math.abs(diffAngle) <= tolerance; + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + } +} + diff --git a/src/main/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java similarity index 95% rename from src/main/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcher.java rename to src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java index 19a4ef1d..0a8f0567 100644 --- a/src/main/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcher.java +++ b/src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java @@ -12,13 +12,13 @@ * limitations under the License. */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import org.skyscreamer.jsonassert.ValueMatcher; - /** * A JSONassert value matcher that matches actual value to regular expression. * If non-null regular expression passed to constructor, then all actual values @@ -93,4 +93,9 @@ private boolean isStaticPattern() { private String getPatternType() { return isStaticPattern()? "Constant": "Dynamic"; } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + + } } diff --git a/src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java new file mode 100644 index 00000000..5b37dea8 --- /dev/null +++ b/src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java @@ -0,0 +1,51 @@ +/* + * TolerantValueMatcher.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; +import com.nezha.jsondiff.comparator.JSONCompareUtil; + +import java.math.BigDecimal; +import java.util.Objects; + +/** + * Function: tolerance matching + */ +public class TolerantValueMatcher implements ValueMatcher { + private double tolerance; + + public TolerantValueMatcher() { this (10e-5); } + + public TolerantValueMatcher(double tolerance) { this.tolerance = tolerance; } + + @Override + public boolean equal(T actual, T expected){ + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + BigDecimal diffValue = actualNum.subtract(expectedNum).abs(); + + return diffValue.compareTo(BigDecimal.valueOf(tolerance)) != 1; + } catch (NumberFormatException e) { + return actual.equals(expected); + } + } + @Override + public void matcherInit(String param, CompareContext compareContext) {tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + + } +} diff --git a/src/main/java/org/skyscreamer/jsonassert/ValueMatcher.java b/src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java similarity index 83% rename from src/main/java/org/skyscreamer/jsonassert/ValueMatcher.java rename to src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java index a05691a1..0434572d 100644 --- a/src/main/java/org/skyscreamer/jsonassert/ValueMatcher.java +++ b/src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java @@ -12,7 +12,9 @@ * limitations under the License. */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff.matcher; + +import com.nezha.jsondiff.CompareContext; /** * Represents a value matcher that can compare two objects for equality. @@ -30,4 +32,9 @@ public interface ValueMatcher { */ boolean equal(T o1, T o2); + /* + * init matcher by yaml rule + */ + void matcherInit(String param, CompareContext compareContext); + } diff --git a/src/main/java/org/skyscreamer/jsonassert/ValueMatcherException.java b/src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java similarity index 98% rename from src/main/java/org/skyscreamer/jsonassert/ValueMatcherException.java rename to src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java index 19807722..470e923e 100644 --- a/src/main/java/org/skyscreamer/jsonassert/ValueMatcherException.java +++ b/src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package org.skyscreamer.jsonassert; +package com.nezha.jsondiff.matcher; /** * Exception that may be thrown by ValueMatcher subclasses to provide more detail on why matches method failed. diff --git a/src/main/java/org/skyscreamer/jsonassert/Customization.java b/src/main/java/org/skyscreamer/jsonassert/Customization.java deleted file mode 100644 index c812a447..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/Customization.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import java.util.regex.Pattern; - -/** - * Associates a custom matcher to a specific jsonpath. - */ -public final class Customization { - private final Pattern path; - private final ValueMatcher comparator; - - public Customization(String path, ValueMatcher comparator) { - assert path != null; - assert comparator != null; - this.path = Pattern.compile(buildPattern(path)); - this.comparator = comparator; - } - - private String buildPattern(String path) { - return buildPatternLevel1(path); - } - - private String buildPatternLevel1(String path) { - String regex = "\\*\\*\\."; - String replacement = "(?:.+\\.)?"; - - return buildPattern(path, regex, replacement, 1); - } - - private String buildPatternLevel2(String s) { - if (s.isEmpty()) { - return ""; - } - String regex = "\\*\\*"; - String replacement = ".+"; - - return buildPattern(s, regex, replacement, 2); - } - - private String buildPatternLevel3(String s) { - if (s.isEmpty()) { - return ""; - } - - String regex = "\\*"; - String replacement = "[^\\.]+"; - - return buildPattern(s, regex, replacement, 3); - } - - private String buildPattern(String path, String regex, String replacement, int level) { - StringBuilder sb = new StringBuilder(); - String[] parts = path.split(regex); - for (int i = 0; i < parts.length; i++) { - sb.append(buildPatternForLevel(level, parts[i])); - if (i < parts.length - 1) { - sb.append(replacement); - } - } - return sb.toString(); - } - - private String buildPatternForLevel(int level, String part) { - switch (level) { - case 1: - return buildPatternLevel2(part); - case 2: - return buildPatternLevel3(part); - case 3: - return Pattern.quote(part); - default: - return "Incorrect level."; - } - } - - /** - * Creates a new {@link Customization} instance for {@code path} and {@code comparator}. - * - * @param path the json path - * @param comparator the comparator - * @return a new Customization - */ - public static Customization customization(String path, ValueMatcher comparator) { - return new Customization(path, comparator); - } - - public boolean appliesToPath(String path) { - return this.path.matcher(path).matches(); - } - - /** - * Return true if actual value matches expected value using this - * Customization's comparator. Calls to this method should be replaced by - * calls to matches(String prefix, Object actual, Object expected, - * JSONCompareResult result). - * - * @param actual - * JSON value being tested - * @param expected - * expected JSON value - * @return true if actual value matches expected value - */ - @Deprecated - public boolean matches(Object actual, Object expected) { - return comparator.equal(actual, expected); - } - - /** - * Return true if actual value matches expected value using this - * Customization's comparator. The equal method used for comparison depends - * on type of comparator. - * - * @param prefix - * JSON path of the JSON item being tested (only used if - * comparator is a LocationAwareValueMatcher) - * @param actual - * JSON value being tested - * @param expected - * expected JSON value - * @param result - * JSONCompareResult to which match failure may be passed (only - * used if comparator is a LocationAwareValueMatcher) - * @return true if expected and actual equal or any difference has already - * been passed to specified result instance, false otherwise. - * @throws ValueMatcherException - * if expected and actual values not equal and ValueMatcher - * needs to override default comparison failure message that - * would be generated if this method returned false. - */ - public boolean matches(String prefix, Object actual, Object expected, - JSONCompareResult result) throws ValueMatcherException { - if (comparator instanceof LocationAwareValueMatcher) { - return ((LocationAwareValueMatcher)comparator).equal(prefix, actual, expected, result); - } - return comparator.equal(actual, expected); - } -} diff --git a/src/main/java/org/skyscreamer/jsonassert/JSONAssert.java b/src/main/java/org/skyscreamer/jsonassert/JSONAssert.java deleted file mode 100644 index 5a2eec18..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/JSONAssert.java +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.skyscreamer.jsonassert.comparator.JSONComparator; - -/** - *

A set of assertion methods useful for writing tests methods that return JSON.

- * - *

There are two modes, strict and non-strict. In most cases, you will probably want - * to set strict to false, since that will make the tests less brittle.

- * - *

Strict tests require all of the elements requested to be returned, and only those elements - * (ie, the tests are non-extensible). Arrays of elements must be returned in the same - * order as expected. For example, say I'm expecting:

- * - * {id:123,things['a','b','c']} - * - *

The following would match when doing non-strict checking, but would fail on strict checking:

- * - * {id:123,things['c','b','a'],anotherfield:'blah'} - * - *

This library uses org.json. It has fewer dependencies than other JSON libraries (like net.sf.json), - * making JSONassert more portable.

- * - *

There are two known issues when dealing with non-strict comparisons:

- *
    - *
  • Unless the order is strict, checking does not handle mixed types in the JSONArray - * (e.g. [1,2,{a:"b"}] or [{pet:"cat"},{car:"Ford"}])
  • - *
  • Unless the order is strict, checking cannot handle arrays of arrays (e.g. [[1,2],[3,4]])
  • - *
- *

You do not have to worry about encountering a false positive or false negative in these two edge cases. - * JSONassert will identify the conditions and throw a descriptive {@link IllegalArgumentException}. These - * cases will be fixed in future versions.

- * - */ -public class JSONAssert { - private JSONAssert() {} - - /** - * Asserts that the JSONObject provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String expectedStr, JSONObject actual, boolean strict) { - assertEquals(expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String message, String expectedStr, JSONObject actual, boolean strict) { - assertEquals(message, expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @see #assertEquals(String, JSONObject, boolean) - * - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String expectedStr, JSONObject actual, boolean strict) { - assertNotEquals(expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @see #assertEquals(String, JSONObject, boolean) - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String message, String expectedStr, JSONObject actual, boolean strict) { - assertNotEquals(message, expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String expectedStr, JSONObject actual, JSONCompareMode compareMode) { - assertEquals("", expectedStr, actual, compareMode); - } - - /** - * Asserts that the JSONObject provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String message, String expectedStr, JSONObject actual, JSONCompareMode compareMode) - { - Object expected = JSONParser.parseJSON(expectedStr); - if (expected instanceof JSONObject) { - assertEquals(message, (JSONObject)expected, actual, compareMode); - } - else { - throw new AssertionError("Expecting a JSON array, but passing in a JSON object"); - } - } - - /** - * Asserts that the JSONObject provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @see #assertEquals(String, JSONObject, JSONCompareMode) - * - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String expectedStr, JSONObject actual, JSONCompareMode compareMode) { - assertNotEquals("", expectedStr, actual, compareMode); - } - - /** - * Asserts that the JSONObject provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @see #assertEquals(String, JSONObject, JSONCompareMode) - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String message, String expectedStr, JSONObject actual, - JSONCompareMode compareMode) { - Object expected = JSONParser.parseJSON(expectedStr); - if (expected instanceof JSONObject) { - assertNotEquals(message, (JSONObject) expected, actual, compareMode); - } - else { - throw new AssertionError("Expecting a JSON array, but passing in a JSON object"); - } - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String expectedStr, JSONArray actual, boolean strict) { - assertEquals(expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String message, String expectedStr, JSONArray actual, boolean strict) { - assertEquals(message, expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String expectedStr, JSONArray actual, boolean strict) { - assertNotEquals(expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String message, String expectedStr, JSONArray actual, boolean strict) { - assertNotEquals(message, expectedStr, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String expectedStr, JSONArray actual, JSONCompareMode compareMode) { - assertEquals("", expectedStr, actual, compareMode); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String message, String expectedStr, JSONArray actual, JSONCompareMode compareMode) { - Object expected = JSONParser.parseJSON(expectedStr); - if (expected instanceof JSONArray) { - assertEquals(message, (JSONArray) expected, actual, compareMode); - } - else { - throw new AssertionError("Expecting a JSON object, but passing in a JSON array"); - } - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String expectedStr, JSONArray actual, JSONCompareMode compareMode) { - Object expected = JSONParser.parseJSON(expectedStr); - if (expected instanceof JSONArray) { - assertNotEquals((JSONArray) expected, actual, compareMode); - } - else { - throw new AssertionError("Expecting a JSON object, but passing in a JSON array"); - } - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String message, String expectedStr, JSONArray actual, - JSONCompareMode compareMode) { - Object expected = JSONParser.parseJSON(expectedStr); - if (expected instanceof JSONArray) { - assertNotEquals(message, (JSONArray) expected, actual, compareMode); - } - else { - throw new AssertionError("Expecting a JSON object, but passing in a JSON array"); - } - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String expectedStr, String actualStr, boolean strict) { - assertEquals(expectedStr, actualStr, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String message, String expectedStr, String actualStr, boolean strict) { - assertEquals(message, expectedStr, actualStr, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String expectedStr, String actualStr, boolean strict) { - assertNotEquals(expectedStr, actualStr, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String message, String expectedStr, String actualStr, boolean strict) { - assertNotEquals(message, expectedStr, actualStr, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String expectedStr, String actualStr, JSONCompareMode compareMode) { - assertEquals("", expectedStr, actualStr, compareMode); - } - - /** - * Asserts that the JSONArray provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String message, String expectedStr, String actualStr, JSONCompareMode compareMode) { - if (expectedStr==actualStr) return; - if (expectedStr==null){ - throw new AssertionError("Expected string is null."); - }else if (actualStr==null){ - throw new AssertionError("Actual string is null."); - } - JSONCompareResult result = JSONCompare.compareJSON(expectedStr, actualStr, compareMode); - if (result.failed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String expectedStr, String actualStr, JSONCompareMode compareMode) { - assertNotEquals("", expectedStr, actualStr, compareMode); - } - - /** - * Asserts that the JSONArray provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String message, String expectedStr, String actualStr, - JSONCompareMode compareMode) { - JSONCompareResult result = JSONCompare.compareJSON(expectedStr, actualStr, compareMode); - if (result.passed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the json string provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param comparator Comparator - */ - public static void assertEquals(String expectedStr, String actualStr, JSONComparator comparator) { - assertEquals("", expectedStr, actualStr, comparator); - - } - - /** - * Asserts that the json string provided matches the expected string. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param comparator Comparator - */ - public static void assertEquals(String message, String expectedStr, String actualStr, JSONComparator comparator) { - JSONCompareResult result = JSONCompare.compareJSON(expectedStr, actualStr, comparator); - if (result.failed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the json string provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param comparator Comparator - */ - public static void assertNotEquals(String expectedStr, String actualStr, JSONComparator comparator) { - assertNotEquals("", expectedStr, actualStr, comparator); - } - - /** - * Asserts that the json string provided does not match the expected string. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expectedStr Expected JSON string - * @param actualStr String to compare - * @param comparator Comparator - */ - public static void assertNotEquals(String message, String expectedStr, String actualStr, - JSONComparator comparator) { - JSONCompareResult result = JSONCompare.compareJSON(expectedStr, actualStr, comparator); - if (result.passed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param comparator Comparator - */ - public static void assertEquals(JSONObject expected, JSONObject actual, JSONComparator comparator) { - assertEquals("", expected, actual, comparator); - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param comparator Comparator - */ - public static void assertEquals(String message, JSONObject expected, JSONObject actual, JSONComparator comparator) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, comparator); - if (result.failed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param comparator Comparator - */ - public static void assertNotEquals(JSONObject expected, JSONObject actual, JSONComparator comparator) { - assertNotEquals("", expected, actual, comparator); - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param comparator Comparator - */ - public static void assertNotEquals(String message, JSONObject expected, JSONObject actual, - JSONComparator comparator) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, comparator); - if (result.passed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertEquals(JSONObject expected, JSONObject actual, boolean strict) { - assertEquals(expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String message, JSONObject expected, JSONObject actual, boolean strict) { - assertEquals(message, expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(JSONObject expected, JSONObject actual, boolean strict) { - assertNotEquals(expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String message, JSONObject expected, JSONObject actual, boolean strict) { - assertNotEquals(message, expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(JSONObject expected, JSONObject actual, JSONCompareMode compareMode) { - assertEquals("", expected, actual, compareMode); - } - - /** - * Asserts that the JSONObject provided matches the expected JSONObject. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String message, JSONObject expected, JSONObject actual, - JSONCompareMode compareMode) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - if (result.failed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(JSONObject expected, JSONObject actual, JSONCompareMode compareMode) { - assertNotEquals("", expected, actual, compareMode); - } - - /** - * Asserts that the JSONObject provided does not match the expected JSONObject. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String message, JSONObject expected, JSONObject actual, - JSONCompareMode compareMode) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - if (result.passed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONArray provided matches the expected JSONArray. If it isn't it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertEquals(JSONArray expected, JSONArray actual, boolean strict) { - assertEquals("", expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected JSONArray. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertEquals(String message, JSONArray expected, JSONArray actual, boolean strict) { - assertEquals(message, expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected JSONArray. If it is it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(JSONArray expected, JSONArray actual, boolean strict) { - assertNotEquals(expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided does not match the expected JSONArray. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param strict Enables strict checking - */ - public static void assertNotEquals(String message, JSONArray expected, JSONArray actual, boolean strict) { - assertNotEquals(message, expected, actual, strict ? JSONCompareMode.STRICT : JSONCompareMode.LENIENT); - } - - /** - * Asserts that the JSONArray provided matches the expected JSONArray. If it isn't it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(JSONArray expected, JSONArray actual, JSONCompareMode compareMode) { - assertEquals("", expected, actual, compareMode); - } - - /** - * Asserts that the JSONArray provided matches the expected JSONArray. If it isn't it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertEquals(String message, JSONArray expected, JSONArray actual, JSONCompareMode compareMode) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - if (result.failed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - /** - * Asserts that the JSONArray provided does not match the expected JSONArray. If it is it throws an - * {@link AssertionError}. - * - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(JSONArray expected, JSONArray actual, JSONCompareMode compareMode) { - assertNotEquals("", expected, actual, compareMode); - } - - /** - * Asserts that the JSONArray provided does not match the expected JSONArray. If it is it throws an - * {@link AssertionError}. - * - * @param message Error message to be displayed in case of assertion failure - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param compareMode Specifies which comparison mode to use - */ - public static void assertNotEquals(String message, JSONArray expected, JSONArray actual, - JSONCompareMode compareMode) { - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - if (result.passed()) { - throw new AssertionError(getCombinedMessage(message, result.getMessage())); - } - } - - private static String getCombinedMessage(String message1, String message2) { - String combinedMessage = ""; - - if(message1 == null || "".equals(message1)) { - combinedMessage = message2; - } else { - combinedMessage = message1 + " " + message2; - } - return combinedMessage; - } -} diff --git a/src/main/java/org/skyscreamer/jsonassert/JSONCompare.java b/src/main/java/org/skyscreamer/jsonassert/JSONCompare.java deleted file mode 100644 index c17115df..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/JSONCompare.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONString; -import org.skyscreamer.jsonassert.comparator.DefaultComparator; -import org.skyscreamer.jsonassert.comparator.JSONComparator; - -/** - * Provides API to compare two JSON entities. This is the backend to {@link JSONAssert}, but it can - * be programmed against directly to access the functionality. (eg, to make something that works with a - * non-JUnit test framework) - */ -public final class JSONCompare { - private JSONCompare() { - } - - private static JSONComparator getComparatorForMode(JSONCompareMode mode) { - return new DefaultComparator(mode); - } - - /** - * Compares JSON string provided to the expected JSON string using provided comparator, and returns the results of - * the comparison. - * @param expectedStr Expected JSON string - * @param actualStr JSON string to compare - * @param comparator Comparator to use - * @return result of the comparison - * @throws IllegalArgumentException when type of expectedStr doesn't match the type of actualStr - */ - public static JSONCompareResult compareJSON(String expectedStr, String actualStr, JSONComparator comparator) { - Object expected = JSONParser.parseJSON(expectedStr); - Object actual = JSONParser.parseJSON(actualStr); - if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { - return compareJSON((JSONObject) expected, (JSONObject) actual, comparator); - } - else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { - return compareJSON((JSONArray)expected, (JSONArray)actual, comparator); - } - else if (expected instanceof JSONString && actual instanceof JSONString) { - return compareJson((JSONString) expected, (JSONString) actual); - } - else if (expected instanceof JSONObject) { - return new JSONCompareResult().fail("", expected, actual); - } - else { - return new JSONCompareResult().fail("", expected, actual); - } - } - - /** - * Compares JSON object provided to the expected JSON object using provided comparator, and returns the results of - * the comparison. - * @param expected expected json object - * @param actual actual json object - * @param comparator comparator to use - * @return result of the comparison - */ - public static JSONCompareResult compareJSON(JSONObject expected, JSONObject actual, JSONComparator comparator) { - return comparator.compareJSON(expected, actual); - } - - /** - * Compares JSON object provided to the expected JSON object using provided comparator, and returns the results of - * the comparison. - * @param expected expected json array - * @param actual actual json array - * @param comparator comparator to use - * @return result of the comparison - */ - public static JSONCompareResult compareJSON(JSONArray expected, JSONArray actual, JSONComparator comparator) { - return comparator.compareJSON(expected, actual); - } - - /** - * Compares {@link JSONString} provided to the expected {@code JSONString}, checking that the - * {@link org.json.JSONString#toJSONString()} are equal. - * - * @param expected Expected {@code JSONstring} - * @param actual {@code JSONstring} to compare - * @return result of the comparison - */ - public static JSONCompareResult compareJson(final JSONString expected, final JSONString actual) { - final JSONCompareResult result = new JSONCompareResult(); - final String expectedJson = expected.toJSONString(); - final String actualJson = actual.toJSONString(); - if (!expectedJson.equals(actualJson)) { - result.fail(""); - } - return result; - } - - /** - * Compares JSON string provided to the expected JSON string, and returns the results of the comparison. - * - * @param expectedStr Expected JSON string - * @param actualStr JSON string to compare - * @param mode Defines comparison behavior - * @return result of the comparison - */ - public static JSONCompareResult compareJSON(String expectedStr, String actualStr, JSONCompareMode mode) { - return compareJSON(expectedStr, actualStr, getComparatorForMode(mode)); - } - - /** - * Compares JSONObject provided to the expected JSONObject, and returns the results of the comparison. - * - * @param expected Expected JSONObject - * @param actual JSONObject to compare - * @param mode Defines comparison behavior - * @return result of the comparison - */ - public static JSONCompareResult compareJSON(JSONObject expected, JSONObject actual, JSONCompareMode mode) { - return compareJSON(expected, actual, getComparatorForMode(mode)); - } - - - /** - * Compares JSONArray provided to the expected JSONArray, and returns the results of the comparison. - * - * @param expected Expected JSONArray - * @param actual JSONArray to compare - * @param mode Defines comparison behavior - * @return result of the comparison - */ - public static JSONCompareResult compareJSON(JSONArray expected, JSONArray actual, JSONCompareMode mode) { - return compareJSON(expected, actual, getComparatorForMode(mode)); - } - -} diff --git a/src/main/java/org/skyscreamer/jsonassert/JSONCompareMode.java b/src/main/java/org/skyscreamer/jsonassert/JSONCompareMode.java deleted file mode 100644 index 8185b065..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/JSONCompareMode.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -/** - *

These different modes define different behavior for the comparison of JSON for testing. - * Each mode encapsulates two underlying behaviors: extensibility and strict ordering.

- * - * - * - * - * - * - * - * - *
- * Behavior of JSONCompareMode - *
 ExtensibleStrict Ordering
STRICTnoyes
LENIENTyesno
NON_EXTENSIBLEnono
STRICT_ORDERyesyes
- * - *

If extensibility not allowed, then all of the expected values must match in what's being tested, - * but any additional fields will cause the test to fail. When extensibility is allowed, all values - * must still match. For example, if you're expecting:

- * - * {id:1,name:"Carter"} - * - *

Then the following will pass when extensible, and will fail when not:

- * - * {id:1,name:"Carter",favoriteColor:"blue"} - * - *

If strict ordering is enabled, JSON arrays must be in strict sequence. For example, if you're expecting:

- * - * {id:1,friends:[{id:2},{id:3}]} - * - *

Then the following will fail strict ordering, but will otherwise pass:

- * - * {id:1,friends:[{id:3},{id:2}]} - * - */ -public enum JSONCompareMode { - /** - * Strict checking. Not extensible, and strict array ordering. - */ - STRICT(false, true), - /** - * Lenient checking. Extensible, and non-strict array ordering. - */ - LENIENT(true, false), - /** - * Non-extensible checking. Not extensible, and non-strict array ordering. - */ - NON_EXTENSIBLE(false, false), - /** - * Strict order checking. Extensible, and strict array ordering. - */ - STRICT_ORDER(true, true); - - private final boolean _extensible; - private final boolean _strictOrder; - - JSONCompareMode(boolean extensible, boolean strictOrder) { - _extensible = extensible; - _strictOrder = strictOrder; - } - - /** - * Is extensible - * @return True if results can be extended from what's expected, otherwise false. - */ - public boolean isExtensible() { - return _extensible; - } - - /** - * Strict order required - * @return True if results require strict array ordering, otherwise false. - */ - public boolean hasStrictOrder() { - return _strictOrder; - } - - /** - * Get the equivalent {@code JSONCompareMode} with or without strict ordering. - * - * @param strictOrdering if true, requires strict ordering of array elements - * @return the equivalent {@code JSONCompareMode} - */ - public JSONCompareMode withStrictOrdering(boolean strictOrdering) { - if (strictOrdering) { - return isExtensible() ? STRICT_ORDER : STRICT; - } else { - return isExtensible() ? LENIENT : NON_EXTENSIBLE; - } - } - - /** - * Get the equivalent {@code JSONCompareMode} with or without extensibility. - * - * @param extensible if true, allows keys in actual that don't appear in expected - * @return the equivalent {@code JSONCompareMode} - */ - public JSONCompareMode withExtensible(boolean extensible) { - if (extensible) { - return hasStrictOrder() ? STRICT_ORDER : LENIENT; - } else { - return hasStrictOrder() ? STRICT : NON_EXTENSIBLE; - } - } -} diff --git a/src/main/java/org/skyscreamer/jsonassert/JSONParser.java b/src/main/java/org/skyscreamer/jsonassert/JSONParser.java deleted file mode 100644 index a70af96c..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/JSONParser.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONString; - -/** - * Simple JSON parsing utility. - */ -public class JSONParser { - // regular expression to match a number in JSON format. see http://www.json.org/fatfree.html. - // "A number can be represented as integer, real, or floating point. JSON does not support octal or hex - // ... [or] NaN or Infinity". - private static final String NUMBER_REGEX = "-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"; - - private JSONParser() {} - - /** - * Takes a JSON string and returns either a {@link org.json.JSONObject} or {@link org.json.JSONArray}, - * depending on whether the string represents an object or an array. - * - * @param s Raw JSON string to be parsed - * @return JSONObject or JSONArray - */ - public static Object parseJSON(final String s) { - if (s.trim().startsWith("{")) { - return new JSONObject(s); - } - else if (s.trim().startsWith("[")) { - return new JSONArray(s); - } else if (s.trim().startsWith("\"") - || s.trim().matches(NUMBER_REGEX)) { - return new JSONString() { - @Override - public String toJSONString() { - return s; - } - }; - } - throw new JSONException("Unparsable JSON string: " + s); - } -} diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparator.java b/src/main/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparator.java deleted file mode 100644 index 7e348b82..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparator.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; - -import java.text.MessageFormat; - -import org.json.JSONArray; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.skyscreamer.jsonassert.JSONCompareResult; - -/** - * A JSONAssert array size comparator. - * - *

Some typical usage idioms are listed below.

- * - *

Assuming JSON to be verified is held in String variable ARRAY_OF_JSONOBJECTS and contains:

- * - * {a:[7, 8, 9]} - * - *

then:

- * - *

To verify that array 'a' contains 3 elements:

- * - * - * JSONAssert.assertEquals("{a:[3]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(JSONCompareMode.LENIENT)); - * - * - *

To verify that array 'a' contains between 2 and 6 elements:

- * - * - * JSONAssert.assertEquals("{a:[2,6]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(JSONCompareMode.LENIENT)); - * - * - * @author Duncan Mackinder - * - */ -public class ArraySizeComparator extends DefaultComparator { - - /** - * Create new ArraySizeComparator. - * - * @param mode - * comparison mode, has no impact on ArraySizeComparator but is - * used by instance of superclass DefaultComparator to control - * comparison of JSON items other than arrays. - */ - public ArraySizeComparator(JSONCompareMode mode) { - super(mode); - } - - /** - * Expected array should consist of either 1 or 2 integer values that define - * maximum and minimum valid lengths of the actual array. If expected array - * contains a single integer value, then the actual array must contain - * exactly that number of elements. - */ - @Override - public void compareJSONArray(String prefix, JSONArray expected, - JSONArray actual, JSONCompareResult result) { - String arrayPrefix = prefix + "[]"; - if (expected.length() < 1 || expected.length() > 2) { - result.fail(MessageFormat - .format("{0}: invalid expectation: expected array should contain either 1 or 2 elements but contains {1} elements", - arrayPrefix, expected.length())); - return; - } - if (!(expected.get(0) instanceof Number)) { - result.fail(MessageFormat - .format("{0}: invalid expectation: {1}expected array size ''{2}'' not a number", - arrayPrefix, (expected.length() == 1? "": "minimum "), expected.get(0))); - return; - } - if ((expected.length() == 2 && !(expected.get(1) instanceof Number))) { - result.fail(MessageFormat - .format("{0}: invalid expectation: maximum expected array size ''{1}'' not a number", - arrayPrefix, expected.get(1))); - return; - } - int minExpectedLength = expected.getInt(0); - if (minExpectedLength < 0) { - result.fail(MessageFormat - .format("{0}: invalid expectation: minimum expected array size ''{1}'' negative", - arrayPrefix, minExpectedLength)); - return; - } - int maxExpectedLength = expected.length() == 2 ? expected.getInt(1) - : minExpectedLength; - if (maxExpectedLength < minExpectedLength) { - result.fail(MessageFormat - .format("{0}: invalid expectation: maximum expected array size ''{1}'' less than minimum expected array size ''{2}''", - arrayPrefix, maxExpectedLength, minExpectedLength)); - return; - } - if (actual.length() < minExpectedLength - || actual.length() > maxExpectedLength) { - result.fail( - arrayPrefix, - MessageFormat.format( - "array size of {0}{1} elements", - minExpectedLength, - (expected.length() == 2 ? (" to " + maxExpectedLength) - : "")), - MessageFormat.format("{0} elements", - actual.length())); - } - } - -} diff --git a/src/main/java/org/skyscreamer/jsonassert/comparator/JSONComparator.java b/src/main/java/org/skyscreamer/jsonassert/comparator/JSONComparator.java deleted file mode 100644 index 9a78d493..00000000 --- a/src/main/java/org/skyscreamer/jsonassert/comparator/JSONComparator.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.skyscreamer.jsonassert.JSONCompareResult; - -/** - * Interface for comparison handler. - * - * @author Ivan Zaytsev - * 2013-01-04 - */ -public interface JSONComparator { - - /** - * Compares two {@link JSONObject}s and returns the result of the comparison in a {@link JSONCompareResult} object. - * - * @param expected the expected JSON object - * @param actual the actual JSON object - * @return the result of the comparison - */ - JSONCompareResult compareJSON(JSONObject expected, JSONObject actual); - - /** - * Compares two {@link JSONArray}s and returns the result of the comparison in a {@link JSONCompareResult} object. - * - * @param expected the expected JSON array - * @param actual the actual JSON array - * @return the result of the comparison - */ - JSONCompareResult compareJSON(JSONArray expected, JSONArray actual); - - /** - * Compares two {@link JSONObject}s on the provided path represented by {@code prefix} and - * updates the result of the comparison in the {@code result} {@link JSONCompareResult} object. - * - * @param prefix the path in the json where the comparison happens - * @param expected the expected JSON object - * @param actual the actual JSON object - * @param result stores the actual state of the comparison result - */ - void compareJSON(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result); - - /** - * Compares two {@link Object}s on the provided path represented by {@code prefix} and - * updates the result of the comparison in the {@code result} {@link JSONCompareResult} object. - * - * @param prefix the path in the json where the comparison happens - * @param expectedValue the expected value - * @param actualValue the actual value - * @param result stores the actual state of the comparison result - */ - void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result); - - /** - * Compares two {@link JSONArray}s on the provided path represented by {@code prefix} and - * updates the result of the comparison in the {@code result} {@link JSONCompareResult} object. - * - * @param prefix the path in the json where the comparison happens - * @param expected the expected JSON array - * @param actual the actual JSON array - * @param result stores the actual state of the comparison result - */ - void compareJSONArray(String prefix, JSONArray expected, JSONArray actual, JSONCompareResult result); -} diff --git a/src/test/java/jsondiff/FileUtil.java b/src/test/java/jsondiff/FileUtil.java new file mode 100644 index 00000000..120871cb --- /dev/null +++ b/src/test/java/jsondiff/FileUtil.java @@ -0,0 +1,52 @@ +/* + * FileUtil.java +* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jsondiff; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class FileUtil { + public static String DIR_PATH = System.getProperty("user.dir"); + + public FileUtil() { + } + + public static String readFile(String fileName) { + try{ + String path = DIR_PATH + fileName; + File file = new File(path); + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + String line; +// System.out.println("Reading text file using FileReader"); + StringBuffer sb = new StringBuffer(); + while((line = br.readLine()) != null){ + //逐行读取 +// System.out.println(line); + sb.append(line).append("\n"); + } + br.close(); + fr.close(); + return sb.toString(); + } catch (IOException e) { + e.printStackTrace();; + return null; + } + + } +} diff --git a/src/test/java/jsondiff/JSONCompareYamlResultTest.java b/src/test/java/jsondiff/JSONCompareYamlResultTest.java new file mode 100644 index 00000000..01f36add --- /dev/null +++ b/src/test/java/jsondiff/JSONCompareYamlResultTest.java @@ -0,0 +1,72 @@ +/* + * ArrayObjectValueMatcherTest.java + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jsondiff; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nezha.jsondiff.JSONCompare; +import com.nezha.jsondiff.JSONCompareResult; +import org.junit.Test; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + + +public class JSONCompareYamlResultTest { + + private static final String TEST_PATH = "/src/test/resources/"; + + private void runTestCase(String caseNumber) throws Exception { + // Read the test file + String expectedJSON = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_a.json"); + String actualJSON = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_e.json"); + String rules = FileUtil.readFile(TEST_PATH + "rule_case" + caseNumber + ".yaml"); + + + JSONCompareResult result = JSONCompare.compareJSONYaml(expectedJSON, actualJSON, rules); + + ObjectMapper objectMapper = new ObjectMapper(); + String actualResult = objectMapper.writeValueAsString(result.getFailure()); + String outputFilePath = "./testoutput/case_" + caseNumber + "_diff.json"; + writeToFile(outputFilePath, actualResult); + actualResult=FileUtil.readFile(outputFilePath); + System.out.println("case_" + caseNumber); + System.out.println(actualResult); + String expectResult = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_result.json"); + + assertEquals("case_" + caseNumber, actualResult,expectResult); + + } + + private void writeToFile(String filePath, String content) throws IOException { + File file = new File(filePath); + File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); // Create all necessary parent directories + } + + try (FileWriter writer = new FileWriter(filePath)) { + writer.write(content); + } + } + + @Test + public void TestCase() throws Exception { + runTestCase("01"); + } +} diff --git a/src/test/java/org/skyscreamer/jsonassert/ArrayValueMatcherTest.java b/src/test/java/org/skyscreamer/jsonassert/ArrayValueMatcherTest.java deleted file mode 100644 index fa815d3c..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/ArrayValueMatcherTest.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.text.MessageFormat; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Test; -import org.skyscreamer.jsonassert.comparator.ArraySizeComparator; -import org.skyscreamer.jsonassert.comparator.CustomComparator; -import org.skyscreamer.jsonassert.comparator.DefaultComparator; -import org.skyscreamer.jsonassert.comparator.JSONComparator; - -/** - * Unit tests for ArrayValueMatcher - * - * @author Duncan Mackinder - * - */ -public class ArrayValueMatcherTest { - - private static final String ARRAY_OF_JSONOBJECTS = "{a:[{background:white,id:1,type:row},{background:grey,id:2,type:row},{background:white,id:3,type:row},{background:grey,id:4,type:row}]}"; - private static final String ARRAY_OF_INTEGERS = "{a:[1,2,3,4,5]}"; - private static final String ARRAY_OF_JSONARRAYS = "{a:[[6,7,8],[9,10,11],[12,13,14],[19,20,21,22]]}"; - private static final JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - - private void doTest(String jsonPath, ArrayValueMatcher arrayValueMatcher, String expectedJSON, - String actualJSON) { - Customization customization = new Customization(jsonPath, arrayValueMatcher); - JSONAssert.assertEquals(expectedJSON, actualJSON, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - private void doFailingMatchTest(String jsonPath, ArrayValueMatcher arrayValueMatcher, String expectedJSON, String actualJSON, String expectedMessagePattern) { - try { - doTest(jsonPath, arrayValueMatcher, expectedJSON, actualJSON); - } - catch (AssertionError e) { - String failureMessage = MessageFormat.format("Exception message ''{0}'', does not match expected pattern ''{1}''", e.getMessage(), expectedMessagePattern); - assertTrue(failureMessage, e.getMessage().matches(expectedMessagePattern)); - return; - } - fail("AssertionError not thrown"); - } - - @Test - public void matchesSecondElementOfJSONObjectArray() { - doTest("a", new ArrayValueMatcher(comparator, 1), "{a:[{background:grey,id:2,type:row}]}", ARRAY_OF_JSONOBJECTS); - } - - @Test - public void failsWhenSecondElementOfJSONObjectArrayDoesNotMatch() { - doFailingMatchTest("a", - new ArrayValueMatcher(comparator, 1), - "{a:[{background:DOES_NOT_MATCH,id:2,type:row}]}", - ARRAY_OF_JSONOBJECTS, - "a\\[1\\]\\.background\\s*Expected:\\s*DOES_NOT_MATCH\\s*got:\\s*grey\\s*"); - } - - @Test - public void failsWhenThirdElementOfJSONObjectArrayDoesNotMatchInMultiplePlaces() { - doFailingMatchTest("a", - new ArrayValueMatcher(comparator, 2), - "{a:[{background:DOES_NOT_MATCH,id:3,type:WRONG_TYPE}]}", - ARRAY_OF_JSONOBJECTS, - "a\\[2\\]\\.background\\s*Expected:\\s*DOES_NOT_MATCH\\s*got:\\s*white\\s*;\\s*a\\[2\\]\\.type\\s*Expected:\\s*WRONG_TYPE\\s*got:\\s*row\\s*"); - } - - @Test - public void failsWhenTwoElementsOfJSONObjectArrayDoNotMatch() { - doFailingMatchTest("a", - new ArrayValueMatcher(comparator, 1, 2), - "{a:[{background:DOES_NOT_MATCH,id:2,type:row},{background:white,id:3,type:WRONG_TYPE}]}", - ARRAY_OF_JSONOBJECTS, - "a\\[1\\]\\.background\\s*Expected:\\s*DOES_NOT_MATCH\\s*got:\\s*grey\\s*;\\s*a\\[2\\]\\.type\\s*Expected:\\s*WRONG_TYPE\\s*got:\\s*row\\s*"); - } - - @Test - public void matchesThirdElementOfSimpleValueArray() { - doTest("a", new ArrayValueMatcher(comparator, 2), "{a:[3]}", ARRAY_OF_INTEGERS); - } - - @Test - public void failsWhenTwoElementOfSimpleValueArrayDoNotMatch() { - doFailingMatchTest("a", new ArrayValueMatcher(comparator, 3, 4), "{a:[3,4]}", ARRAY_OF_INTEGERS, - "a\\[3\\]\\s*Expected:\\s3\\s*got:\\s*4\\s*;\\s*a\\[4\\]\\s*Expected:\\s*4\\s*got:\\s*5\\s*"); - } - - @Test - public void matchesFirstElementOfArrayOfJSONArrays() { - doTest("a", new ArrayValueMatcher(comparator, 0), "{a:[[6,7,8]]}", ARRAY_OF_JSONARRAYS); - } - - @Test - public void matchesSizeOfFirstThreeInnerArrays() { - JSONComparator innerArraySizeComparator = new ArraySizeComparator(JSONCompareMode.STRICT_ORDER); - doTest("a", new ArrayValueMatcher(innerArraySizeComparator, 0, 2), "{a:[[3]]}", ARRAY_OF_JSONARRAYS); - } - - @Test - public void failsWhenInnerArraySizeDoesNotMatch() { - JSONComparator innerArraySizeComparator = new ArraySizeComparator(JSONCompareMode.STRICT_ORDER); - doFailingMatchTest("a", - new ArrayValueMatcher(innerArraySizeComparator), - "{a:[[3]]}", - ARRAY_OF_JSONARRAYS, - "a\\[3\\]\\[\\]\\s*Expected:\\s*array size of 3 elements\\s*got:\\s*4 elements\\s*"); - } - - @Test - public void failsWhenInnerJSONObjectArrayElementDoesNotMatch() { - ArrayValueMatcher innerArrayValueMatcher = new ArrayValueMatcher(comparator, 1); - JSONComparator innerArrayComparator = new CustomComparator( - JSONCompareMode.LENIENT, new Customization("a[2]", innerArrayValueMatcher)); - doFailingMatchTest("a", - new ArrayValueMatcher(innerArrayComparator, 2), // tests inner array i.e. [12,13,14] - "{a:[[99]]}", - ARRAY_OF_JSONARRAYS, - "a\\[2\\]\\[1\\]\\s*Expected:\\s*99\\s*got:\\s*13\\s*"); - } - - @Test - public void matchesEveryElementOfJSONObjectArray() { - doTest("a", new ArrayValueMatcher(comparator), "{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS); - } - - @Test - public void failsWhenNotEveryElementOfJSONObjectArrayMatches() { - doFailingMatchTest("a", - new ArrayValueMatcher(comparator), - "{a:[{background:white}]}", - ARRAY_OF_JSONOBJECTS, - "a\\[1\\]\\.background\\s*Expected:\\s*white\\s*got:\\s*grey\\s*;\\s*a\\[3\\]\\.background\\s*Expected:\\s*white\\s*got:\\s*grey\\s*"); - } - - @Test - public void matchesEveryElementOfJSONObjectArrayWhenRangeTooLarge() { - doTest("a", new ArrayValueMatcher(comparator, 0, 500), "{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS); - } - - @Test - public void matchesElementPairsStartingFromElement1OfJSONObjectArrayWhenRangeTooLarge() { - doTest("a", new ArrayValueMatcher(comparator, 1, 500), "{a:[{background:grey},{background:white}]}", ARRAY_OF_JSONOBJECTS); - } - - @Test - public void matchesElementPairsStartingFromElement0OfJSONObjectArrayWhenRangeTooLarge() { - doTest("a", new ArrayValueMatcher(comparator), "{a:[{background:white},{background:grey}]}", ARRAY_OF_JSONOBJECTS); - } - - @Test - public void failsWhenAppliedToNonArray() { - try { - doTest("a", new ArrayValueMatcher(comparator), "{a:[{background:white}]}", "{a:{attr1:value1,attr2:value2}}"); - } - catch (IllegalArgumentException e) { - assertEquals("Exception message", "ArrayValueMatcher applied to non-array actual value", e.getMessage()); - return; - } - fail("Did not throw IllegalArgumentException"); - } - - /* - * Following tests verify the ability to match an element containing either - * a simple value or a JSON object against simple value or JSON object - * without requiring expected value to be wrapped in an array reducing - * slightly the syntactic load on teh test author & reader. - */ - - @Test - public void simpleValueMatchesSecondElementOfJSONObjectArray() { - doTest("a", new ArrayValueMatcher(comparator, 3), "{a:4}", ARRAY_OF_INTEGERS); - } - - @Test - public void jsonObjectMatchesSecondElementOfJSONObjectArray() { - doTest("a", new ArrayValueMatcher(comparator, 1), "{a:{background:grey,id:2,type:row}}", ARRAY_OF_JSONOBJECTS); - } - - /* - * Following tests contain copies of code quoted in ArrayValueMatcher JavaDoc and are included to verify that the exact code documented works as expected. - */ - @Test - public void verifyIdAttributeOfFirstArrayElementMatches() { - JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 0)); - JSONAssert.assertEquals("{a:[{id:1}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifyIdAttributeOfFirstArrayElementMatchesSimplifiedExpectedSyntax() { - JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 0)); - JSONAssert.assertEquals("{a:{id:1}}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifyTypeAttributeOfSecondAndThirdElementMatchesRow() { - JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 1, 2)); - JSONAssert.assertEquals("{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifyTypeAttributeOfEveryArrayElementMatchesRow() { - JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator)); - JSONAssert.assertEquals("{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifyEveryArrayElementWithCustomComparator() { - // get length of array we will verify - int aLength = ((JSONArray)((JSONObject)JSONParser.parseJSON(ARRAY_OF_JSONOBJECTS)).get("a")).length(); - // create array of customizations one for each array element - RegularExpressionValueMatcher regExValueMatcher = new RegularExpressionValueMatcher("\\d+"); // matches one or more digits - Customization[] customizations = new Customization[aLength]; - for (int i=0; i regExArrayValueMatcher = new ArrayValueMatcher(regExComparator); - Customization regExArrayValueCustomization = new Customization("a", regExArrayValueMatcher); - CustomComparator regExCustomArrayValueComparator = new CustomComparator(JSONCompareMode.STRICT_ORDER, new Customization[] { regExArrayValueCustomization }); - JSONAssert.assertEquals("{a:[{id:X}]}", ARRAY_OF_JSONOBJECTS, regExCustomArrayValueComparator); - } - - @Test - public void verifyBackgroundAttributesOfEveryArrayElementAlternateBetweenWhiteAndGrey() { - JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator)); - JSONAssert.assertEquals("{a:[{background:white},{background:grey}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifyEveryElementOfArrayIsJSONArrayOfLength3() { - JSONComparator comparator = new ArraySizeComparator(JSONCompareMode.STRICT_ORDER); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 0, 2)); - JSONAssert.assertEquals("{a:[[3]]}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifySecondElementOfArrayIsJSONArrayWhoseFirstElementIs9() { - Customization innerCustomization = new Customization("a[1]", new ArrayValueMatcher(comparator, 0)); - JSONComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, innerCustomization); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 1)); - JSONAssert.assertEquals("{a:[[9]]}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifySecondElementOfArrayIsJSONArrayWhoseFirstElementIs9WithSimpliedExpectedString() { - Customization innerCustomization = new Customization("a[1]", new ArrayValueMatcher(comparator, 0)); - JSONComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, innerCustomization); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 1)); - JSONAssert.assertEquals("{a:[9]}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } - - @Test - public void verifySecondElementOfArrayIsJSONArrayWhoseFirstElementIs9WithEvenMoreSimpliedExpectedString() { - Customization innerCustomization = new Customization("a[1]", new ArrayValueMatcher(comparator, 0)); - JSONComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, innerCustomization); - Customization customization = new Customization("a", new ArrayValueMatcher(comparator, 1)); - JSONAssert.assertEquals("{a:9}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization)); - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/DependencyTest.java b/src/test/java/org/skyscreamer/jsonassert/DependencyTest.java deleted file mode 100644 index ad0519da..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/DependencyTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.json.JSONObject; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit tests for our external/third-party dependencies. - * - * @author Carter Page - */ -public class DependencyTest { - @Test - public void nop() { - // Cloudbees doesn't like a unit test class with no tests - } - - //@Test // For https://github.com/skyscreamer/JSONassert/issues/25 - public void testJSonGetLong() throws Exception { - Long target = -4611686018427386614L; - String targetString = target.toString(); - - JSONObject value = new JSONObject().put("id", target); - Assert.assertEquals(target, (Long) value.getLong("id")); //Correct: when put as long getLong is correct - - value = new JSONObject().put("id", targetString); - Assert.assertEquals(target, (Long) Long.parseLong(value.getString("id"))); //Correct: when put as String getString is correct - Assert.assertEquals(target, (Long) value.getLong("id")); //Bug: Having json convert the string to long fails - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/JSONArrayWithNullTest.java b/src/test/java/org/skyscreamer/jsonassert/JSONArrayWithNullTest.java deleted file mode 100644 index 0bf11531..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/JSONArrayWithNullTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.skyscreamer.jsonassert; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Test; - -public class JSONArrayWithNullTest { - @Test - public void testJSONArrayWithNullValue() { - JSONArray jsonArray1 = getJSONArray1(); - JSONArray jsonArray2 = getJSONArray2(); - - JSONAssert.assertEquals(jsonArray1, jsonArray2, true); - JSONAssert.assertEquals(jsonArray1, jsonArray2, false); - } - - @Test - public void testJSONArrayWithNullValueAndJsonObject() { - JSONArray jsonArray1 = getJSONArray1(); - JSONObject jsonObject1 = new JSONObject(); - jsonObject1.put("hey", "value"); - - JSONArray jsonArray2 = getJSONArray2(); - JSONObject jsonObject2 = new JSONObject(); - jsonObject2.put("hey", "value"); - - JSONAssert.assertEquals(jsonArray1, jsonArray2, true); - JSONAssert.assertEquals(jsonArray1, jsonArray2, false); - } - - private JSONArray getJSONArray1() { - JSONArray jsonArray1 = new JSONArray(); - jsonArray1.put(1); - jsonArray1.put(JSONObject.NULL); - jsonArray1.put(3); - jsonArray1.put(2); - return jsonArray1; - } - - private JSONArray getJSONArray2() { - JSONArray jsonArray1 = new JSONArray(); - jsonArray1.put(1); - jsonArray1.put(JSONObject.NULL); - jsonArray1.put(3); - jsonArray1.put(2); - return jsonArray1; - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/JSONAssertTest.java b/src/test/java/org/skyscreamer/jsonassert/JSONAssertTest.java deleted file mode 100644 index e17f684b..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/JSONAssertTest.java +++ /dev/null @@ -1,856 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.skyscreamer.jsonassert.JSONCompareMode.LENIENT; -import static org.skyscreamer.jsonassert.JSONCompareMode.NON_EXTENSIBLE; -import static org.skyscreamer.jsonassert.JSONCompareMode.STRICT; -import static org.skyscreamer.jsonassert.JSONCompareMode.STRICT_ORDER; - -import java.util.Arrays; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Assert; -import org.junit.Test; -import org.skyscreamer.jsonassert.comparator.CustomComparator; -import org.skyscreamer.jsonassert.comparator.JSONComparator; - -/** - * Unit tests for {@link JSONAssert} - */ -public class JSONAssertTest { - @Test - public void testString() { - testPass("\"Joe\"", "\"Joe\"", STRICT); - testPass("\"Joe\"", "\"Joe\"", LENIENT); - testPass("\"Joe\"", "\"Joe\"", NON_EXTENSIBLE); - testPass("\"Joe\"", "\"Joe\"", STRICT_ORDER); - testFail("\"Joe\"", "\"Joe1\"", STRICT); - testFail("\"Joe\"", "\"Joe2\"", LENIENT); - testFail("\"Joe\"", "\"Joe3\"", NON_EXTENSIBLE); - testFail("\"Joe\"", "\"Joe4\"", STRICT_ORDER); - } - - @Test - public void testNumber() { - testPass("123", "123", STRICT); - testPass("123", "123", LENIENT); - testPass("123", "123", NON_EXTENSIBLE); - testPass("123", "123", STRICT_ORDER); - testFail("123", "1231", STRICT); - testFail("123", "1232", LENIENT); - testFail("123", "1233", NON_EXTENSIBLE); - testFail("123", "1234", STRICT_ORDER); - testPass("0", "0", STRICT); - testPass("-1", "-1", STRICT); - testPass("0.1", "0.1", STRICT); - testPass("1.2e5", "1.2e5", STRICT); - testPass("20.4e-1", "20.4e-1", STRICT); - testFail("310.1e-1", "31.01", STRICT); // should fail though numbers are the same? - } - - @Test - public void testSimple() { - testPass("{id:1}", "{id:1}", STRICT); - testFail("{id:1}", "{id:2}", STRICT); - testPass("{id:1}", "{id:1}", LENIENT); - testFail("{id:1}", "{id:2}", LENIENT); - testPass("{id:1}", "{id:1}", NON_EXTENSIBLE); - testFail("{id:1}", "{id:2}", NON_EXTENSIBLE); - testPass("{id:1}", "{id:1}", STRICT_ORDER); - testFail("{id:1}", "{id:2}", STRICT_ORDER); - } - - @Test - public void testSimpleStrict() { - testPass("{id:1}", "{id:1,name:\"Joe\"}", LENIENT); - testFail("{id:1}", "{id:1,name:\"Joe\"}", STRICT); - testPass("{id:1}", "{id:1,name:\"Joe\"}", STRICT_ORDER); - testFail("{id:1}", "{id:1,name:\"Joe\"}", NON_EXTENSIBLE); - } - - @Test - public void testReversed() { - testPass("{name:\"Joe\",id:1}", "{id:1,name:\"Joe\"}", LENIENT); - testPass("{name:\"Joe\",id:1}", "{id:1,name:\"Joe\"}", STRICT); - testPass("{name:\"Joe\",id:1}", "{id:1,name:\"Joe\"}", NON_EXTENSIBLE); - testPass("{name:\"Joe\",id:1}", "{id:1,name:\"Joe\"}", STRICT_ORDER); - } - - @Test // Currently JSONAssert assumes JSONObject. - public void testArray() { - testPass("[1,2,3]","[1,2,3]", STRICT); - testPass("[1,2,3]","[1,3,2]", LENIENT); - testFail("[1,2,3]","[1,3,2]", STRICT); - testFail("[1,2,3]","[4,5,6]", LENIENT); - testPass("[1,2,3]","[1,2,3]", STRICT_ORDER); - testPass("[1,2,3]","[1,3,2]", NON_EXTENSIBLE); - testFail("[1,2,3]","[1,3,2]", STRICT_ORDER); - testFail("[1,2,3]","[4,5,6]", NON_EXTENSIBLE); - } - - @Test - public void testNested() { - testPass("{id:1,address:{addr1:\"123 Main\", addr2:null, city:\"Houston\", state:\"TX\"}}", - "{id:1,address:{addr1:\"123 Main\", addr2:null, city:\"Houston\", state:\"TX\"}}", STRICT); - testFail("{id:1,address:{addr1:\"123 Main\", addr2:null, city:\"Houston\", state:\"TX\"}}", - "{id:1,address:{addr1:\"123 Main\", addr2:null, city:\"Austin\", state:\"TX\"}}", STRICT); - } - - @Test - public void testVeryNested() { - testPass("{a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{p:\"blah\"}}}}}}}}}}}}}}}}", - "{a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{p:\"blah\"}}}}}}}}}}}}}}}}", STRICT); - testFail("{a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{p:\"blah\"}}}}}}}}}}}}}}}}", - "{a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{z:\"blah\"}}}}}}}}}}}}}}}}", STRICT); - } - - @Test - public void testSimpleArray() { - testPass("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Exact to exact (strict) - "{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", - STRICT); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Out-of-order fails (strict) - "{id:1,pets:[\"dog\",\"fish\",\"cat\"]}", - STRICT); - testPass("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Out-of-order ok - "{id:1,pets:[\"dog\",\"fish\",\"cat\"]}", - LENIENT); - testPass("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Out-of-order ok - "{id:1,pets:[\"dog\",\"fish\",\"cat\"]}", - NON_EXTENSIBLE); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Out-of-order fails (strict order) - "{id:1,pets:[\"dog\",\"fish\",\"cat\"]}", - STRICT_ORDER); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Mismatch - "{id:1,pets:[\"dog\",\"cat\",\"bird\"]}", - STRICT); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Mismatch - "{id:1,pets:[\"dog\",\"cat\",\"bird\"]}", - LENIENT); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Mismatch - "{id:1,pets:[\"dog\",\"cat\",\"bird\"]}", - STRICT_ORDER); - testFail("{id:1,pets:[\"dog\",\"cat\",\"fish\"]}", // Mismatch - "{id:1,pets:[\"dog\",\"cat\",\"bird\"]}", - NON_EXTENSIBLE); - } - - @Test - public void testSimpleMixedArray() { - testPass("{stuff:[321, \"abc\"]}", "{stuff:[\"abc\", 321]}", LENIENT); - testFail("{stuff:[321, \"abc\"]}", "{stuff:[\"abc\", 789]}", LENIENT); - } - - @Test - public void testComplexMixedStrictArray() { - testPass("{stuff:[{pet:\"cat\"},{car:\"Ford\"}]}", "{stuff:[{pet:\"cat\"},{car:\"Ford\"}]}", STRICT); - } - - @Test - public void testComplexMixedArray() { - testPass("{stuff:[{pet:\"cat\"},{car:\"Ford\"}]}", "{stuff:[{pet:\"cat\"},{car:\"Ford\"}]}", LENIENT); - } - - @Test - public void testComplexArrayNoUniqueID() { - testPass("{stuff:[{address:{addr1:\"123 Main\"}}, {address:{addr1:\"234 Broad\"}}]}", - "{stuff:[{address:{addr1:\"123 Main\"}}, {address:{addr1:\"234 Broad\"}}]}", - LENIENT); - } - - @Test - public void testSimpleAndComplexStrictArray() { - testPass("{stuff:[123,{a:\"b\"}]}", "{stuff:[123,{a:\"b\"}]}", STRICT); - } - - @Test - public void testSimpleAndComplexArray() { - testPass("{stuff:[123,{a:\"b\"}]}", "{stuff:[123,{a:\"b\"}]}", LENIENT); - } - - @Test - public void testComplexArray() { - testPass("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - STRICT); // Exact to exact (strict) - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:3,name:\"Sue\",pets:[\"fish\",\"bird\"]},{id:2,name:\"Pat\",pets:[\"dog\"]}],pets:[]}", - STRICT); // Out-of-order fails (strict) - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:3,name:\"Sue\",pets:[\"fish\",\"bird\"]},{id:2,name:\"Pat\",pets:[\"dog\"]}],pets:[]}", - STRICT_ORDER); // Out-of-order fails (strict order) - testPass("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:3,name:\"Sue\",pets:[\"fish\",\"bird\"]},{id:2,name:\"Pat\",pets:[\"dog\"]}],pets:[]}", - LENIENT); // Out-of-order ok - testPass("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:3,name:\"Sue\",pets:[\"fish\",\"bird\"]},{id:2,name:\"Pat\",pets:[\"dog\"]}],pets:[]}", - NON_EXTENSIBLE); // Out-of-order ok - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"cat\",\"fish\"]}],pets:[]}", - STRICT); // Mismatch (strict) - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"cat\",\"fish\"]}],pets:[]}", - LENIENT); // Mismatch - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"cat\",\"fish\"]}],pets:[]}", - STRICT_ORDER); // Mismatch - testFail("{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}", - "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"cat\",\"fish\"]}],pets:[]}", - NON_EXTENSIBLE); // Mismatch - } - - @Test - public void testArrayOfArraysStrict() { - testPass("{id:1,stuff:[[1,2],[2,3],[],[3,4]]}", "{id:1,stuff:[[1,2],[2,3],[],[3,4]]}", STRICT); - testFail("{id:1,stuff:[[1,2],[2,3],[3,4],[]]}", "{id:1,stuff:[[1,2],[2,3],[],[3,4]]}", STRICT); - } - - @Test - public void testArrayOfArrays() { - testPass("{id:1,stuff:[[4,3],[3,2],[],[1,2]]}", "{id:1,stuff:[[1,2],[2,3],[],[3,4]]}", LENIENT); - } - - @Test - public void testLenientArrayRecursion() { - testPass("[{\"arr\":[5, 2, 1]}]", "[{\"b\":3, \"arr\":[1, 5, 2]}]", LENIENT); - } - - @Test - public void testFieldMismatch() { - JSONCompareResult result = JSONCompare.compareJSON("{name:\"Pat\"}", "{name:\"Sue\"}", STRICT); - FieldComparisonFailure comparisonFailure = result.getFieldFailures().iterator().next(); - Assert.assertEquals("Pat", comparisonFailure.getExpected()); - Assert.assertEquals("Sue", comparisonFailure.getActual()); - Assert.assertEquals("name", comparisonFailure.getField()); - } - - @Test - public void testBooleanArray() { - testPass("[true, false, true, true, false]", "[true, false, true, true, false]", STRICT); - testPass("[false, true, true, false, true]", "[true, false, true, true, false]", LENIENT); - testFail("[false, true, true, false, true]", "[true, false, true, true, false]", STRICT); - testPass("[false, true, true, false, true]", "[true, false, true, true, false]", NON_EXTENSIBLE); - testFail("[false, true, true, false, true]", "[true, false, true, true, false]", STRICT_ORDER); - } - - @Test - public void testNullProperty() { - testFail("{id:1,name:\"Joe\"}", "{id:1,name:null}", STRICT); - testFail("{id:1,name:null}", "{id:1,name:\"Joe\"}", STRICT); - } - - @Test - public void testIncorrectTypes() { - testFail("{id:1,name:\"Joe\"}", "{id:1,name:[]}", STRICT); - testFail("{id:1,name:[]}", "{id:1,name:\"Joe\"}", STRICT); - } - - @Test - public void testNullEquality() { - testPass("{id:1,name:null}", "{id:1,name:null}", STRICT); - } - - @Test - public void testExpectedArrayButActualObject() { - testFail("[1]", "{id:1}", LENIENT); - } - - @Test - public void testExpectedObjectButActualArray() { - testFail("{id:1}", "[1]", LENIENT); - } - - @Test - public void testEquivalentIntAndLong() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Long.valueOf(12345)); - JSONAssert.assertEquals(expected, actual, true); - JSONAssert.assertEquals(actual, expected, true); - } - - @Test - public void testEquivalentIntAndDouble() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12345.0)); - JSONAssert.assertEquals(expected, actual, true); - JSONAssert.assertEquals(actual, expected, true); - } - - @Test(expected = AssertionError.class) - public void testAssertNotEqualsWhenEqualStrict() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals(expected, actual, true); - } - - @Test(expected = AssertionError.class) - public void testAssertNotEqualsWhenEqualLenient() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals(expected, actual, false); - } - - @Test() - public void testAssertNotEqualsWhenEqualDiffObjectsStrict() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - expected.put("name", "Joe"); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals(expected, actual, true); - } - - @Test(expected = AssertionError.class) - public void testAssertNotEqualsWhenEqualDiffObjectsLenient() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - expected.put("name", "Joe"); - actual.put("name", "Joe"); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals(expected, actual, false); - } - - @Test() - public void testAssertNotEqualsWhenDifferentStrict() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12346)); - JSONAssert.assertNotEquals(expected, actual, true); - } - - @Test() - public void testAssertNotEqualsWhenDifferentLenient() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12346)); - JSONAssert.assertNotEquals(expected, actual, false); - } - - @Test() - public void testAssertNotEqualsString() { - JSONAssert.assertNotEquals("[1,2,3]", "[1,3,2]", STRICT); - JSONAssert.assertNotEquals("[1,2,3]", "[1,2,4]", LENIENT); - JSONAssert.assertNotEquals("[1,2,3]", "[1,3,2]", true); - JSONAssert.assertNotEquals("[1,2,3]", "[1,2,4]", false); - } - - @Test() - public void testAssertEqualsString() { - JSONAssert.assertEquals("[1,2,3]", "[1,2,3]", true); - JSONAssert.assertEquals("{id:12345}", "{id:12345}", false); - JSONAssert.assertEquals("{id:12345}", "{id:12345, name:\"john\"}", LENIENT); - JSONAssert.assertEquals("{id:12345}", "{id:12345}", LENIENT); - JSONAssert.assertEquals("{id:12345}", "{id:12345, name:\"john\"}", LENIENT); - } - - @Test() - public void testAssertNotEqualsStringAndJSONObject() { - JSONObject actual = new JSONObject(); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertEquals("{id:12345}", actual, false); - JSONAssert.assertNotEquals("{id:12346}", actual, false); - } - - @Test() - public void testAssertNotEqualsJSONArray() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertEquals("[1,2,3]", actual, false); - JSONAssert.assertNotEquals("[1,2,4]", actual, false); - JSONAssert.assertNotEquals("[1,3,2]", actual, true); - JSONAssert.assertNotEquals(new JSONArray(Arrays.asList(1, 2, 4)), actual, false); - JSONAssert.assertNotEquals(new JSONArray(Arrays.asList(1, 3, 2)), actual, true); - } - - @Test - public void testAssertEqualsStringJSONArrayBooleanWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertEquals("Message", "[1,2,3]", actual, false); - performAssertEqualsTestForMessageVerification("[1,2,4]", actual, false); - performAssertEqualsTestForMessageVerification("[1,3,2]", actual, true); - } - - @Test - public void testAssertEqualsStringJSONArrayCompareModeWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertEquals("Message", "[1,2,3]", actual, LENIENT); - performAssertEqualsTestForMessageVerification("[1,2,4]", actual, LENIENT); - performAssertEqualsTestForMessageVerification("[1,3,2]", actual, STRICT); - } - - @Test - public void testAssertEqualsJSONArray2BooleanWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertEquals("Message", new JSONArray(Arrays.asList(1, 2, 3)), actual, false); - performAssertEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 2, 4)), actual, false); - performAssertEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 3, 2)), actual, true); - } - - @Test - public void testAssertEqualsJSONArray2JSONCompareWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - - JSONAssert.assertEquals("Message", new JSONArray(Arrays.asList(1, 2, 3)), actual, LENIENT); - performAssertEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 2, 4)), actual, LENIENT); - performAssertEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 3, 2)), actual, STRICT); - } - - @Test - public void testAssertEqualsString2Boolean() { - JSONAssert.assertEquals("Message", "{id:12345}", "{id:12345}", false); - JSONAssert.assertEquals("Message", "{id:12345}", "{id:12345, name:\"john\"}", false); - - performAssertEqualsTestForMessageVerification("{id:12345}", "{id:12345, name:\"john\"}", true); - performAssertEqualsTestForMessageVerification("{id:12345}", "{id:123456}", false); - } - - @Test - public void testAssertEqualsString2JSONCompare() { - JSONAssert.assertEquals("Message", "{id:12345}", "{id:12345}", LENIENT); - JSONAssert.assertEquals("Message", "{id:12345}", "{id:12345, name:\"john\"}", LENIENT); - - performAssertEqualsTestForMessageVerification("{id:12345}", "{id:12345, name:\"john\"}", STRICT); - performAssertEqualsTestForMessageVerification("{id:12345}", "{id:123456}", LENIENT); - } - - @Test - public void testAssertEqualsStringJSONObjectBoolean() { - JSONObject actual = new JSONObject(); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertEquals("Message", "{id:12345}", actual, false); - performAssertEqualsTestForMessageVerification("{id:12346}", actual, false); - performAssertEqualsTestForMessageVerification("[1,2,3]", "[1,3,2]", true); - } - - @Test - public void testAssertEqualsStringJSONObjectJSONCompare() { - JSONObject actual = new JSONObject(); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertEquals("Message", "{id:12345}", actual, LENIENT); - performAssertEqualsTestForMessageVerification("{id:12346}", actual, LENIENT); - performAssertEqualsTestForMessageVerification("[1,2,3]", "[1,3,2]", STRICT); - } - - @Test - public void testAssertEqualsJSONObject2JSONCompare() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("name", "Joe"); - actual.put("id", Integer.valueOf(12345)); - JSONAssert.assertEquals("Message", expected, actual, LENIENT); - - expected.put("street", "St. Paul"); - performAssertEqualsTestForMessageVerification(expected, actual, LENIENT); - - expected = new JSONObject(); - actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12346)); - performAssertEqualsTestForMessageVerification(expected, actual, STRICT); - } - - @Test - public void testAssertEqualsJSONObject2Boolean() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("name", "Joe"); - actual.put("id", Integer.valueOf(12345)); - JSONAssert.assertEquals("Message", expected, actual, false); - - expected.put("street", "St. Paul"); - performAssertEqualsTestForMessageVerification(expected, actual, false); - - expected = new JSONObject(); - actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12346)); - performAssertEqualsTestForMessageVerification(expected, actual, true); - } - - @Test - public void testAssertEqualsString2JsonComparator() throws IllegalArgumentException { - JSONAssert.assertEquals("Message", "{\"entry\":{\"id\":x}}", "{\"entry\":{\"id\":1}}", - new CustomComparator( - JSONCompareMode.STRICT, - new Customization("entry.id", - new RegularExpressionValueMatcher("\\d")) - )); - - performAssertEqualsTestForMessageVerification("{\"entry\":{\"id\":x}}", "{\"entry\":{\"id\":NOT_A_NUMBER}}", - new CustomComparator( - JSONCompareMode.STRICT, - new Customization("entry.id", - new RegularExpressionValueMatcher("\\d")) - )); - } - - @Test - public void testAssertNotEqualsStringJSONArrayBooleanWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertNotEquals("Message", "[1,4,3]", actual, false); - JSONAssert.assertNotEquals("Message", "[1,4,3]", actual, true); - performAssertNotEqualsTestForMessageVerification("[1,3,2]", actual, false); - performAssertNotEqualsTestForMessageVerification("[1,2,3]", actual, true); - } - - @Test - public void testAssertNotEqualsStringJSONArrayCompareModeWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertNotEquals("Message", "[1,2,4]", actual, LENIENT); - JSONAssert.assertNotEquals("Message", "[1,2,4]", actual, STRICT); - performAssertNotEqualsTestForMessageVerification("[1,3,2]", actual, LENIENT); - performAssertNotEqualsTestForMessageVerification("[1,2,3]", actual, STRICT); - } - - @Test - public void testAssertNotEqualsJSONArray2BooleanWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - JSONAssert.assertNotEquals("Message", new JSONArray(Arrays.asList(1, 4, 3)), actual, false); - performAssertNotEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 3, 2)), actual, false); - performAssertNotEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 2, 3)), actual, true); - } - - @Test - public void testAssertNotEqualsJSONArray2JSONCompareWithMessage() { - JSONArray actual = new JSONArray(Arrays.asList(1, 2, 3)); - - JSONAssert.assertNotEquals("Message", new JSONArray(Arrays.asList(1, 4, 3)), actual, LENIENT); - performAssertNotEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 3, 2)), actual, LENIENT); - performAssertNotEqualsTestForMessageVerification(new JSONArray(Arrays.asList(1, 2, 3)), actual, STRICT); - } - - @Test - public void testAssertNotEqualsString2Boolean() { - JSONAssert.assertNotEquals("Message", "{id:12345}", "{id:45}", false); - JSONAssert.assertNotEquals("Message", "{id:12345}", "{id:345, name:\"john\"}", false); - - performAssertNotEqualsTestForMessageVerification("{id:12345}", "{id:12345}", true); - performAssertNotEqualsTestForMessageVerification("{id:12345}", "{id:12345, name:\"John\"}", false); - } - - @Test - public void testAssertNotEqualsString2JSONCompare() { - JSONAssert.assertNotEquals("Message", "{id:12345}", "{id:123}", LENIENT); - JSONAssert.assertNotEquals("Message", "{id:12345, name:\"John\"}", "{id:12345}", LENIENT); - - performAssertNotEqualsTestForMessageVerification("{id:12345}", "{id:12345, name:\"john\"}", LENIENT); - performAssertNotEqualsTestForMessageVerification("{id:12345}", "{id:12345}", STRICT); - } - - @Test - public void testAssertNotEqualsStringJSONObjectBoolean() { - JSONObject actual = new JSONObject(); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals("Message", "{id:1234}", actual, false); - performAssertNotEqualsTestForMessageVerification("{id:12345}", actual, false); - performAssertNotEqualsTestForMessageVerification("[1,2,3]", "[1,2,3]", true); - } - - @Test - public void testAssertNotEqualsStringJSONObjectJSONCompare() { - JSONObject actual = new JSONObject(); - actual.put("id", Double.valueOf(12345)); - JSONAssert.assertNotEquals("Message", "{id:1234}", actual, LENIENT); - performAssertNotEqualsTestForMessageVerification("{id:12345}", actual, LENIENT); - performAssertNotEqualsTestForMessageVerification("[1,2,3]", "[1,2,3]", STRICT); - } - - @Test - public void testAssertNtEqualsJSONObject2JSONCompare() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("name", "Joe"); - actual.put("id", Integer.valueOf(123)); - JSONAssert.assertNotEquals("Message", expected, actual, LENIENT); - - actual.remove("id"); - actual.put("id", Integer.valueOf(12345)); - performAssertNotEqualsTestForMessageVerification(expected, actual, LENIENT); - - expected = new JSONObject(); - actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12345)); - performAssertNotEqualsTestForMessageVerification(expected, actual, STRICT); - } - - @Test - public void testAssertNotEqualsJSONObject2Boolean() { - JSONObject expected = new JSONObject(); - JSONObject actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("name", "Joe"); - actual.put("id", Integer.valueOf(123)); - JSONAssert.assertNotEquals("Message", expected, actual, false); - - actual.remove("id"); - actual.put("id", Integer.valueOf(12345)); - performAssertNotEqualsTestForMessageVerification(expected, actual, false); - - expected = new JSONObject(); - actual = new JSONObject(); - expected.put("id", Integer.valueOf(12345)); - actual.put("id", Double.valueOf(12345)); - performAssertNotEqualsTestForMessageVerification(expected, actual, true); - } - - @Test - public void testAssertNotEqualsString2JsonComparator() throws IllegalArgumentException { - JSONAssert.assertNotEquals("Message", "{\"entry\":{\"id\":x}}", "{\"entry\":{\"id\":NOT_A_NUMBER}}", - new CustomComparator( - JSONCompareMode.STRICT, - new Customization("entry.id", - new RegularExpressionValueMatcher("\\d")) - )); - - performAssertNotEqualsTestForMessageVerification("{\"entry\":{\"id\":x}}", "{\"entry\":{\"id\":1}}", - new CustomComparator( - JSONCompareMode.STRICT, - new Customization("entry.id", - new RegularExpressionValueMatcher("\\d")) - )); - } - - private void testPass(String expected, String actual, JSONCompareMode compareMode) - { - String message = expected + " == " + actual + " (" + compareMode + ")"; - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - Assert.assertTrue(message + "\n " + result.getMessage(), result.passed()); - } - - private void testFail(String expected, String actual, JSONCompareMode compareMode) - { - String message = expected + " != " + actual + " (" + compareMode + ")"; - JSONCompareResult result = JSONCompare.compareJSON(expected, actual, compareMode); - Assert.assertTrue(message, result.failed()); - } - - private void performAssertEqualsTestForMessageVerification( - Object expected, - Object actual, - Object strictMode) { - - String message = "Message"; - String testShouldFailMessage = "The test should fail so that the message in AssertionError could be verified."; - String strictModeMessage = "strictMode must be an instance of JSONCompareMode or Boolean"; - boolean assertEqualsFailed = true; - if(expected instanceof String && actual instanceof String && strictMode instanceof JSONComparator) { - try { - JSONAssert.assertEquals(message, (String) expected, (String) actual, (JSONComparator) strictMode); - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } - else if(expected instanceof String && actual instanceof JSONArray) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertEquals(message, (String) expected, (JSONArray) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertEquals(message, (String) expected, (JSONArray) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof JSONArray && actual instanceof JSONArray) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertEquals(message, (JSONArray) expected, (JSONArray) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertEquals(message, (JSONArray) expected, (JSONArray) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof String && actual instanceof String) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertEquals(message, (String) expected, (String) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertEquals(message, (String) expected, (String) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof String && actual instanceof JSONObject) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertEquals(message, (String) expected, (JSONObject) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertEquals(message, (String) expected, (JSONObject) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof JSONObject && actual instanceof JSONObject) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertEquals(message, (JSONObject) expected, (JSONObject) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertEquals(message, (JSONObject) expected, (JSONObject) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else { - fail("No overloaded method found to call"); - } - } - - private void performAssertNotEqualsTestForMessageVerification( - Object expected, - Object actual, - Object strictMode) - { - - String message = "Message"; - String testShouldFailMessage = "The test should fail so that the message in AssertionError could be verified."; - String strictModeMessage = "strictMode must be an instance of JSONCompareMode or Boolean"; - boolean assertEqualsFailed = true; - if(expected instanceof String && actual instanceof String && strictMode instanceof JSONComparator) { - try { - JSONAssert.assertNotEquals(message, (String) expected, (String) actual, (JSONComparator) strictMode); - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } - else if(expected instanceof String && actual instanceof JSONArray) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertNotEquals(message, (String) expected, (JSONArray) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertNotEquals(message, (String) expected, (JSONArray) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof JSONArray && actual instanceof JSONArray) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertNotEquals(message, (JSONArray) expected, (JSONArray) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertNotEquals(message, (JSONArray) expected, (JSONArray) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof String && actual instanceof String) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertNotEquals(message, (String) expected, (String) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertNotEquals(message, (String) expected, (String) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof String && actual instanceof JSONObject) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertNotEquals(message, (String) expected, (JSONObject) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertNotEquals(message, (String) expected, (JSONObject) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else if(expected instanceof JSONObject && actual instanceof JSONObject) { - try { - if(strictMode instanceof JSONCompareMode) { - JSONAssert.assertNotEquals(message, (JSONObject) expected, (JSONObject) actual, (JSONCompareMode) strictMode); - } else if(strictMode instanceof Boolean) { - JSONAssert.assertNotEquals(message, (JSONObject) expected, (JSONObject) actual, (Boolean) strictMode); - } else { - fail(strictModeMessage); - } - assertEqualsFailed = false; - fail(testShouldFailMessage); //will throw AssertionError - } catch (AssertionError ae) { - handleAssertionError(message, assertEqualsFailed, ae); - } - } else { - fail("No overloaded method found to call"); - } - } - - private void handleAssertionError(String message, boolean assertEqualsFailed, AssertionError ae) throws AssertionError { - if(assertEqualsFailed) { - verifyErrorMessage(message, ae); - } else { - throw ae; - } - } - - private void verifyErrorMessage(String message, AssertionError ae) { - assertTrue(ae.getMessage().contains(message)); - assertTrue(ae.getMessage().startsWith(message)); - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/JSONCompareModeTest.java b/src/test/java/org/skyscreamer/jsonassert/JSONCompareModeTest.java deleted file mode 100644 index df808855..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/JSONCompareModeTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; -import static org.skyscreamer.jsonassert.JSONCompareMode.LENIENT; -import static org.skyscreamer.jsonassert.JSONCompareMode.NON_EXTENSIBLE; -import static org.skyscreamer.jsonassert.JSONCompareMode.STRICT; -import static org.skyscreamer.jsonassert.JSONCompareMode.STRICT_ORDER; - -import org.junit.Test; - -/** - * Unit tests for {@link JSONCompareMode} - */ -public class JSONCompareModeTest { - @Test - public void testWithStrictOrdering() { - assertTrue(LENIENT.withStrictOrdering(true).hasStrictOrder()); - assertTrue(LENIENT.withStrictOrdering(true).isExtensible()); - assertTrue(NON_EXTENSIBLE.withStrictOrdering(true).hasStrictOrder()); - assertFalse(NON_EXTENSIBLE.withStrictOrdering(true).isExtensible()); - - assertEquals(STRICT, STRICT.withStrictOrdering(true)); - assertEquals(STRICT_ORDER, STRICT_ORDER.withStrictOrdering(true)); - } - - @Test - public void testWithoutStrictOrdering() { - assertFalse(STRICT_ORDER.withStrictOrdering(false).hasStrictOrder()); - assertTrue(STRICT_ORDER.withStrictOrdering(false).isExtensible()); - assertFalse(STRICT.withStrictOrdering(false).hasStrictOrder()); - assertFalse(STRICT.withStrictOrdering(false).isExtensible()); - - assertEquals(LENIENT, LENIENT.withStrictOrdering(false)); - assertEquals(NON_EXTENSIBLE, NON_EXTENSIBLE.withStrictOrdering(false)); - } - - @Test - public void testWithExtensibility() { - assertTrue(NON_EXTENSIBLE.withExtensible(true).isExtensible()); - assertFalse(NON_EXTENSIBLE.withExtensible(true).hasStrictOrder()); - assertTrue(STRICT.withExtensible(true).isExtensible()); - assertTrue(STRICT.withExtensible(true).hasStrictOrder()); - - assertEquals(LENIENT, LENIENT.withExtensible(true)); - assertEquals(STRICT_ORDER, STRICT_ORDER.withExtensible(true)); - } - - @Test - public void testWithoutExtensibility() { - assertFalse(STRICT_ORDER.withExtensible(false).isExtensible()); - assertTrue(STRICT_ORDER.withExtensible(false).hasStrictOrder()); - assertFalse(LENIENT.withExtensible(false).isExtensible()); - assertFalse(LENIENT.withExtensible(false).hasStrictOrder()); - - assertEquals(STRICT, STRICT.withExtensible(false)); - assertEquals(NON_EXTENSIBLE, NON_EXTENSIBLE.withExtensible(false)); - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/JSONCompareTest.java b/src/test/java/org/skyscreamer/jsonassert/JSONCompareTest.java deleted file mode 100644 index 3bcb7377..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/JSONCompareTest.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.skyscreamer.jsonassert.JSONCompare.compareJSON; -import static org.skyscreamer.jsonassert.JSONCompareMode.LENIENT; -import static org.skyscreamer.jsonassert.JSONCompareMode.NON_EXTENSIBLE; -import static org.skyscreamer.jsonassert.JSONCompareMode.STRICT; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.junit.Test; -import org.junit.internal.matchers.TypeSafeMatcher; - -/** - * Unit tests for {@code JSONCompare}. - */ -public class JSONCompareTest { - @Test - public void succeedsWithEmptyArrays() { - assertTrue(compareJSON("[]", "[]", LENIENT).passed()); - } - - @Test - public void reportsArraysOfUnequalLength() { - JSONCompareResult result = compareJSON("[4]", "[]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[]: Expected 1 values but got 0"))); - } - - @Test - public void reportsArrayMissingExpectedElement() { - JSONCompareResult result = compareJSON("[4]", "[7]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[]\nExpected: 4\n but none found\n ; []\nUnexpected: 7\n"))); - assertEquals(result.getFieldMissing().size(), 1); - assertEquals(result.getFieldUnexpected().size(), 1); - } - - @Test - public void reportsMismatchedFieldValues() { - JSONCompareResult result = compareJSON("{\"id\": 3}", "{\"id\": 5}", LENIENT); - assertThat(result, failsWithMessage(equalTo("id\nExpected: 3\n got: 5\n"))); - assertThat(result, failsWithMessage(equalTo("id\nExpected: 3\n got: 5\n"))); - } - - @Test - public void reportsMissingField() { - JSONCompareResult result = compareJSON("{\"obj\": {\"id\": 3}}", "{\"obj\": {}}", LENIENT); - assertThat(result, failsWithMessage(equalTo("obj\nExpected: id\n but none found\n"))); - assertEquals(result.getFieldMissing().size(), 1); - } - - @Test - public void reportsUnexpectedArrayWhenExpectingObject() { - JSONCompareResult result = compareJSON("{}", "[]", LENIENT); - assertThat(result, failsWithMessage(equalTo("\nExpected: a JSON object\n got: a JSON array\n"))); - } - - @Test - public void reportsUnexpectedObjectWhenExpectingArray() { - JSONCompareResult result = compareJSON("[]", "{}", LENIENT); - assertThat(result, failsWithMessage(equalTo("\nExpected: a JSON array\n got: a JSON object\n"))); - } - - @Test - public void reportsUnexpectedNull() { - JSONCompareResult result = compareJSON("{\"id\": 3}", "{\"id\": null}", LENIENT); - assertThat(result, failsWithMessage(equalTo("id\nExpected: 3\n got: null\n"))); - } - - @Test - public void reportsUnexpectedNonNull() { - JSONCompareResult result = compareJSON("{\"id\": null}", "{\"id\": \"abc\"}", LENIENT); - assertThat(result, failsWithMessage(equalTo("id\nExpected: null\n got: abc\n"))); - } - - @Test - public void reportsUnexpectedFieldInNonExtensibleMode() { - JSONCompareResult result = compareJSON("{\"obj\": {}}", "{\"obj\": {\"id\": 3}}", NON_EXTENSIBLE); - assertThat(result, failsWithMessage(equalTo("obj\nUnexpected: id\n"))); - assertEquals(result.getFieldUnexpected().size(), 1); - } - - @Test - public void reportsMismatchedTypes() { - JSONCompareResult result = compareJSON("{\"arr\":[]}", "{\"arr\":{}}", LENIENT); - assertThat(result, failsWithMessage(equalTo("arr\nExpected: a JSON array\n got: a JSON object\n"))); - } - - @Test - public void reportsWrongSimpleValueCountInUnorderedArray() { - JSONCompareResult result = compareJSON("[5, 5]", "[5, 7]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[]: Expected 2 occurrence(s) of 5 but got 1 occurrence(s) ; []\nUnexpected: 7\n"))); - assertEquals(result.getFieldUnexpected().size(), 1); - } - - @Test - public void reportsMissingJSONObjectWithUniqueKeyInUnorderedArray() { - JSONCompareResult result = compareJSON("[{\"id\" : 3}]", "[{\"id\" : 5}]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[id=3]\nExpected: a JSON object\n but none found\n ; " + - "[id=5]\nUnexpected: a JSON object\n"))); - assertEquals(result.getFieldMissing().size(), 1); - assertEquals(result.getFieldUnexpected().size(), 1); - } - - @Test - public void reportsUnmatchedJSONObjectInUnorderedArray() { - JSONCompareResult result = compareJSON("[{\"address\" : {\"street\" : \"Acacia Avenue\"}}]", "[{\"age\" : 23}]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[0] Could not find match for element {\"address\":{\"street\":\"Acacia Avenue\"}}"))); - } - - @Test - public void succeedsWithNestedJSONObjectsInUnorderedArray() { - assertTrue(compareJSON("[{\"address\" : {\"street\" : \"Acacia Avenue\"}}, 5]", "[5, {\"address\" : {\"street\" : \"Acacia Avenue\"}}]", LENIENT).passed()); - } - - @Test - public void succeedsWithJSONObjectsWithNonUniqueKeyInUnorderedArray() { - String jsonDocument = "[{\"age\" : 43}, {\"age\" : 43}]"; - assertTrue(compareJSON(jsonDocument, jsonDocument, LENIENT).passed()); - } - - @Test - public void succeedsWithSomeNestedJSONObjectsInUnorderedArray() { - String jsonDocument = "[{\"age\" : 43}, {\"age\" : {\"years\" : 43}}]"; - assertTrue(compareJSON(jsonDocument, jsonDocument, LENIENT).passed()); - } - - @Test - public void reportsUnmatchesIntegerValueInUnorderedArrayContainingJSONObject() { - JSONCompareResult result = compareJSON("[{\"address\" : {\"street\" : \"Acacia Avenue\"}}, 5]", "[{\"address\" : {\"street\" : \"Acacia Avenue\"}}, 2]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[1] Could not find match for element 5"))); - } - - @Test - public void reportsUnmatchedJSONArrayWhereOnlyExpectedContainsJSONObjectWithUniqueKey() { - JSONCompareResult result = compareJSON("[{\"id\": 3}]", "[{}]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[0] Could not find match for element {\"id\":3}"))); - } - - @Test - public void reportsUnmatchedJSONArrayWhereExpectedContainsJSONObjectWithUniqueKeyButActualContainsElementOfOtherType() { - JSONCompareResult result = compareJSON("[{\"id\": 3}]", "[5]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[0] Could not find match for element {\"id\":3}"))); - } - - @Test - public void reportsUnmatchedJSONArrayWhereExpectedContainsNonnullIntegerButActualContainsNullElement() { - JSONCompareResult result = compareJSON("[ 3 ]", "[ null ]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[]\nExpected: 3\n but none found\n ; " + - "[]\nUnexpected: null\n"))); - } - - @Test - public void reportsUnmatchedJSONArrayWhereExpectedContainsNullElementButActualContainsNonnullInteger() { - JSONCompareResult result = compareJSON("[ null ]", "[ 3 ]", LENIENT); - assertThat(result, failsWithMessage(equalTo("[]\nExpected: null\n but none found\n ; " + - "[]\nUnexpected: 3\n"))); - } - - @Test - public void reportsStrictUnmatchedJSONArrayWhereExpectedContainsNonnullIntegerButActualContainsNullElement() { - JSONCompareResult result = compareJSON("[ 3 ]", "[ null ]", STRICT); - assertThat(result, failsWithMessage(equalTo("[0]\nExpected: 3\n got: null\n"))); - } - - @Test - public void reportsStrictUnmatchedJSONArrayWhereExpectedContainsNullButActualContainsNonnullInteger() { - JSONCompareResult result = compareJSON("[ null ]", "[ 3 ]", STRICT); - assertThat(result, failsWithMessage(equalTo("[0]\nExpected: null\n got: 3\n"))); - } - - private Matcher failsWithMessage(final Matcher expectedMessage) { - return new TypeSafeMatcher() { - @Override - public void describeTo(Description description) { - description.appendText("a failed comparison with message ").appendDescriptionOf(expectedMessage); - } - - @Override - public boolean matchesSafely(JSONCompareResult item) { - return item.failed() && expectedMessage.matches(item.getMessage()); - } - }; - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/JSONCustomComparatorTest.java b/src/test/java/org/skyscreamer/jsonassert/JSONCustomComparatorTest.java deleted file mode 100644 index 53546166..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/JSONCustomComparatorTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.junit.Test; -import org.skyscreamer.jsonassert.comparator.CustomComparator; -import org.skyscreamer.jsonassert.comparator.JSONComparator; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.skyscreamer.jsonassert.JSONCompare.compareJSON; - -public class JSONCustomComparatorTest { - - String actual = "{\"first\":\"actual\", \"second\":1}"; - String expected = "{\"first\":\"expected\", \"second\":1}"; - - String deepActual = "{\n" + - " \"outer\":\n" + - " {\n" + - " \"inner\":\n" + - " {\n" + - " \"value\": \"actual\",\n" + - " \"otherValue\": \"foo\"\n" + - " }\n" + - " }\n" + - "}"; - String deepExpected = "{\n" + - " \"outer\":\n" + - " {\n" + - " \"inner\":\n" + - " {\n" + - " \"value\": \"expected\",\n" + - " \"otherValue\": \"foo\"\n" + - " }\n" + - " }\n" + - "}"; - - String simpleWildcardActual = "{\n" + - " \"foo\": {\n" + - " \"bar1\": {\n" + - " \"baz\": \"actual\"\n" + - " },\n" + - " \"bar2\": {\n" + - " \"baz\": \"actual\"\n" + - " }\n" + - " }\n" + - "}"; - String simpleWildcardExpected = "{\n" + - " \"foo\": {\n" + - " \"bar1\": {\n" + - " \"baz\": \"expected\"\n" + - " },\n" + - " \"bar2\": {\n" + - " \"baz\": \"expected\"\n" + - " }\n" + - " }\n" + - "}"; - - String deepWildcardActual = "{\n" + - " \"root\": {\n" + - " \"baz\": \"actual\",\n" + - " \"foo\": {\n" + - " \"baz\": \"actual\",\n" + - " \"bar\": {\n" + - " \"baz\": \"actual\"\n" + - " }\n" + - " }\n" + - " }\n" + - "}"; - String deepWildcardExpected = "{\n" + - " \"root\": {\n" + - " \"baz\": \"expected\",\n" + - " \"foo\": {\n" + - " \"baz\": \"expected\",\n" + - " \"bar\": {\n" + - " \"baz\": \"expected\"\n" + - " }\n" + - " }\n" + - " }\n" + - "}"; - - String rootDeepWildcardActual = "{\n" + - " \"baz\": \"actual\",\n" + - " \"root\": {\n" + - " \"baz\": \"actual\",\n" + - " \"foo\": {\n" + - " \"baz\": \"actual\",\n" + - " \"bar\": {\n" + - " \"baz\": \"actual\"\n" + - " }\n" + - " }\n" + - " }\n" + - "}"; - String rootDeepWildcardExpected = "{\n" + - " \"baz\": \"expected\",\n" + - " \"root\": {\n" + - " \"baz\": \"expected\",\n" + - " \"foo\": {\n" + - " \"baz\": \"expected\",\n" + - " \"bar\": {\n" + - " \"baz\": \"expected\"\n" + - " }\n" + - " }\n" + - " }\n" + - "}"; - - int comparatorCallCount = 0; - ValueMatcher comparator = new ValueMatcher() { - @Override - public boolean equal(Object o1, Object o2) { - comparatorCallCount++; - return o1.toString().equals("actual") && o2.toString().equals("expected"); - } - }; - - @Test - public void whenPathMatchesInCustomizationThenCallCustomMatcher() { - JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("first", comparator)); - JSONCompareResult result = compareJSON(expected, actual, jsonCmp); - assertTrue(result.getMessage(), result.passed()); - assertEquals(1, comparatorCallCount); - } - - @Test - public void whenDeepPathMatchesCallCustomMatcher() { - JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("outer.inner.value", comparator)); - JSONCompareResult result = compareJSON(deepExpected, deepActual, jsonCmp); - assertTrue(result.getMessage(), result.passed()); - assertEquals(1, comparatorCallCount); - } - - @Test - public void whenSimpleWildcardPathMatchesCallCustomMatcher() { - JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("foo.*.baz", comparator)); - JSONCompareResult result = compareJSON(simpleWildcardExpected, simpleWildcardActual, jsonCmp); - assertTrue(result.getMessage(), result.passed()); - assertEquals(2, comparatorCallCount); - } - - @Test - public void whenDeepWildcardPathMatchesCallCustomMatcher() { - JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("root.**.baz", comparator)); - JSONCompareResult result = compareJSON(deepWildcardExpected, deepWildcardActual, jsonCmp); - assertTrue(result.getMessage(), result.passed()); - assertEquals(3, comparatorCallCount); - } - - @Test - public void whenRootDeepWildcardPathMatchesCallCustomMatcher() { - JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("**.baz", comparator)); - JSONCompareResult result = compareJSON(rootDeepWildcardExpected, rootDeepWildcardActual, jsonCmp); - assertTrue(result.getMessage(), result.passed()); - assertEquals(4, comparatorCallCount); - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcherTest.java b/src/test/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcherTest.java deleted file mode 100644 index 18539bc0..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/RegularExpressionValueMatcherTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert; - -import org.junit.Assert; - -import org.junit.Test; -import org.skyscreamer.jsonassert.comparator.CustomComparator; - -/** - * Unit tests for RegularExpressionValueMatcher - * - * @author Duncan Mackinder - * - */ -public class RegularExpressionValueMatcherTest { - private static final String ARRAY_ELEMENT_PREFIX = "d.results[0].__metadata.uri"; - private static final String JSON_STRING_WITH_ARRAY = "{d:{results:[{__metadata:{uri:\"http://localhost:80/Person('1')\",type:Person},id:1}]}}"; - private static final String CONSTANT_URI_REGEX_EXPECTED_JSON = "{d:{results:[{__metadata:{uri:X}}]}}"; - - private void doTest(String jsonPath, String regex, String expectedJSON, - String actualJSON) { - JSONAssert.assertEquals(expectedJSON, actualJSON, new CustomComparator( - JSONCompareMode.STRICT_ORDER, new Customization(jsonPath, - new RegularExpressionValueMatcher(regex)))); - } - - @Test - public void constantRegexWithSimplePathMatchsStringAttribute() { - doTest("a", "v.", "{a:x}", "{a:v1}"); - } - - @Test - public void constantRegexWithThreeLevelPathMatchsStringAttribute() { - doTest("a.b.c", ".*Is.*", "{a:{b:{c:x}}}", "{a:{b:{c:thisIsAString}}}"); - } - - @Test - public void dynamicRegexWithSimplePathMatchsStringAttribute() { - doTest("a", null, "{a:\"v.\"}", "{a:v1}"); - } - - @Test - public void dynamicRegexWithThreeLevelPathMatchsStringAttribute() { - doTest("a.b.c", null, "{a:{b:{c:\".*Is.*\"}}}", - "{a:{b:{c:thisIsAString}}}"); - } - - @Test - public void constantRegexMatchesStringAttributeInsideArray() { - doTest(ARRAY_ELEMENT_PREFIX, "http://localhost:80/Person\\('\\d+'\\)", CONSTANT_URI_REGEX_EXPECTED_JSON, JSON_STRING_WITH_ARRAY); - } - - @Test - public void dynamicRegexMatchesStringAttributeInsideArray() { - doTest(ARRAY_ELEMENT_PREFIX, null, "{d:{results:[{__metadata:{uri:\"http://localhost:80/Person\\\\('\\\\d+'\\\\)\"}}]}}", JSON_STRING_WITH_ARRAY); - } - - @Test - public void dynamicRegexMatchesStringAttributeInsideArrayWithNoArgConstructor() { - JSONAssert.assertEquals("{d:{results:[{__metadata:{uri:\"http://localhost:80/Person\\\\('\\\\d+'\\\\)\"}}]}}", JSON_STRING_WITH_ARRAY, new CustomComparator( - JSONCompareMode.STRICT_ORDER, new Customization(ARRAY_ELEMENT_PREFIX, - new RegularExpressionValueMatcher()))); - } - - @Test - public void failsWhenDynamicRegexInvalid() { - try { - doTest(ARRAY_ELEMENT_PREFIX, null, "{d:{results:[{__metadata:{uri:\"http://localhost:80/Person('\\\\d+'\\\\)\"}}]}}", JSON_STRING_WITH_ARRAY); - } - catch (AssertionError e) { - Assert.assertTrue("Invalid exception message returned: "+ e.getMessage(), e.getMessage().startsWith(ARRAY_ELEMENT_PREFIX + ": Dynamic expected pattern invalid: ")); - } - } - - @Test - public void failsWhenDynamicRegexDoesNotMatchStringAttributeInsideArray() { - try { - doTest(ARRAY_ELEMENT_PREFIX, null, "{d:{results:[{__metadata:{uri:\"http://localhost:80/Person\\\\('\\\\w+'\\\\)\"}}]}}", JSON_STRING_WITH_ARRAY); - } - catch (AssertionError e) { - Assert.assertTrue("Invalid exception message returned: "+ e.getMessage(), e.getMessage().startsWith(ARRAY_ELEMENT_PREFIX + ": Dynamic expected pattern did not match value")); - } - } - - @Test - public void failsWhenConstantRegexInvalid() { - try { - doTest(ARRAY_ELEMENT_PREFIX, "http://localhost:80/Person\\\\['\\\\d+'\\\\)", CONSTANT_URI_REGEX_EXPECTED_JSON, JSON_STRING_WITH_ARRAY); - } - catch (IllegalArgumentException e) { - Assert.assertTrue("Invalid exception message returned: "+ e.getMessage(), e.getMessage().startsWith("Constant expected pattern invalid: ")); - } - } - - @Test - public void failsWhenConstantRegexDoesNotMatchStringAttributeInsideArray() { - try { - doTest(ARRAY_ELEMENT_PREFIX, "http://localhost:80/Person\\\\('\\\\w+'\\\\)", CONSTANT_URI_REGEX_EXPECTED_JSON, JSON_STRING_WITH_ARRAY); - } - catch (AssertionError e) { - Assert.assertTrue("Invalid exception message returned: "+ e.getMessage(), e.getMessage().startsWith(ARRAY_ELEMENT_PREFIX + ": Constant expected pattern did not match value")); - } - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparatorTest.java b/src/test/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparatorTest.java deleted file mode 100644 index 7af97ee5..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/comparator/ArraySizeComparatorTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.text.MessageFormat; - -import org.junit.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; - -/** - * Unit tests for ArraySizeComparator - * - * @author Duncan Mackinder - * - */ -public class ArraySizeComparatorTest { - private static final String twoElementArray = "{a:[b,c]}"; - - private void doTest(String expectedJSON, String actualJSON) - { - JSONAssert.assertEquals(expectedJSON, actualJSON, new ArraySizeComparator(JSONCompareMode.STRICT_ORDER)); - } - - private void doFailingMatchTest(String expectedJSON, String actualJSON, String expectedMessagePattern) { - try { - doTest(expectedJSON, actualJSON); - } - catch (AssertionError e) { - String failureMessage = MessageFormat.format("Exception message ''{0}'', does not match expected pattern ''{1}''", e.getMessage(), expectedMessagePattern); - assertTrue(failureMessage, e.getMessage().matches(expectedMessagePattern)); - return; - } - fail("AssertionError not thrown"); - } - - @Test - public void succeedsWhenExactSizeExpected() { - doTest("{a:[2]}", twoElementArray); - } - - @Test - public void succeedsWhenSizeWithinExpectedRange() { - doTest("{a:[1,3]}", twoElementArray); - } - - @Test - public void succeedsWhenSizeIsMinimumOfExpectedRange() { - doTest("{a:[2,4]}", twoElementArray); - } - - @Test - public void succeedsWhenSizeIsMaximumOfExpectedRange() { - doTest("{a:[1,2]}", twoElementArray); - } - - @Test - public void failsWhenExpectedArrayTooShort() { - doFailingMatchTest("{a:[]}", twoElementArray, "a\\[\\]: invalid expectation: expected array should contain either 1 or 2 elements but contains 0 elements"); - } - - @Test - public void failsWhenExpectedArrayTooLong() { - doFailingMatchTest("{a:[1,2,3]}", twoElementArray, "a\\[\\]: invalid expectation: expected array should contain either 1 or 2 elements but contains 3 elements"); - } - - @Test - public void failsWhenExpectedNotAllSimpleTypes() { - doFailingMatchTest("{a:[{y:1},2]}", twoElementArray, "a\\[\\]: invalid expectation: minimum expected array size '\\{\"y\":1\\}' not a number"); - } - - @Test - public void failsWhenExpectedMinimumTooSmall() { - doFailingMatchTest("{a:[-1,6]}", twoElementArray, "a\\[\\]: invalid expectation: minimum expected array size '-1' negative"); - } - - @Test - public void failsWhenExpectedMaximumTooSmall() { - doFailingMatchTest("{a:[8,6]}", twoElementArray, "a\\[\\]: invalid expectation: maximum expected array size '6' less than minimum expected array size '8'"); - } - - @Test - public void failsWhenExpectedArraySizeNotANumber() { - doFailingMatchTest("{a:[X]}", twoElementArray, "a\\[\\]: invalid expectation: expected array size 'X' not a number"); - } - - @Test - public void failsWhenFirstExpectedArrayElementNotANumber() { - doFailingMatchTest("{a:[MIN,6]}", twoElementArray, "a\\[\\]: invalid expectation: minimum expected array size 'MIN' not a number"); - } - - @Test - public void failsWhenSecondExpectedArrayElementNotANumber() { - doFailingMatchTest("{a:[8,MAX]}", twoElementArray, "a\\[\\]: invalid expectation: maximum expected array size 'MAX' not a number"); - } - - @Test - public void failsWhenActualArrayTooShort() { - doFailingMatchTest("{a:[3]}", twoElementArray, "a\\[\\]\\s*Expected:\\s*array size of 3 elements\\s*got:\\s*2 elements\\s*"); - } - - @Test - public void failsWhenActualArrayLongerThanExpectedLength() { - doFailingMatchTest("{a:[1]}", twoElementArray, "a\\[\\]\\s*Expected:\\s*array size of 1 elements\\s*got:\\s*2 elements\\s*"); - } - - @Test - public void failsWhenActualArrayLongerThanMaxOfExpectedRange() { - doFailingMatchTest("{a:[0,1]}", twoElementArray, "a\\[\\]\\s*Expected:\\s*array size of 0 to 1 elements\\s*got:\\s*2 elements\\s*"); - } - - /* - * Following tests are copied from ArraySizeComparator JavaDoc and are include to ensure code as documented work as expected. - */ - - @Test - public void succeedsWhenActualArrayContainsExactly3Elements() { - JSONAssert.assertEquals("{a:[3]}", "{a:[7, 8, 9]}", new ArraySizeComparator(JSONCompareMode.LENIENT)); - } - - @Test - public void succeedsWhenActualArrayContainsBetween2And6Elements() { - JSONAssert.assertEquals("{a:[2,6]}", "{a:[7, 8, 9]}", new ArraySizeComparator(JSONCompareMode.LENIENT)); - } - -} diff --git a/src/test/java/org/skyscreamer/jsonassert/comparator/CustomComparatorTest.java b/src/test/java/org/skyscreamer/jsonassert/comparator/CustomComparatorTest.java deleted file mode 100644 index b48ffb59..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/comparator/CustomComparatorTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; - -import junit.framework.Assert; -import org.json.JSONArray; -import org.junit.Test; -import org.skyscreamer.jsonassert.JSONCompare; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.skyscreamer.jsonassert.JSONCompareResult; - -/** - * @author Ivan Zaytsev - * 2013-01-04 - */ -public class CustomComparatorTest { - - private static class ArrayOfJsonObjectsComparator extends DefaultComparator { - public ArrayOfJsonObjectsComparator(JSONCompareMode mode) { - super(mode); - } - - @Override - public void compareJSONArray(String prefix, JSONArray expected, JSONArray actual, JSONCompareResult result) { - compareJSONArrayOfJsonObjects(prefix, expected, actual, result); - } - } - - @Test - public void testFullArrayComparison() throws Exception { - JSONCompareResult compareResult = JSONCompare.compareJSON( - "[{id:1}, {id:3}, {id:5}]", - "[{id:1}, {id:3}, {id:6}, {id:7}]", new ArrayOfJsonObjectsComparator(JSONCompareMode.LENIENT) - ); - - Assert.assertTrue(compareResult.failed()); - String message = compareResult.getMessage().replaceAll("\n", ""); - Assert.assertTrue(message, message.matches(".*id=5.*Expected.*id=6.*Unexpected.*id=7.*Unexpected.*")); - } -} diff --git a/src/test/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtilTest.java b/src/test/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtilTest.java deleted file mode 100644 index 65f03b1e..00000000 --- a/src/test/java/org/skyscreamer/jsonassert/comparator/JSONCompareUtilTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.skyscreamer.jsonassert.comparator; - -import junit.framework.Assert; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * Test JSONCompareUtil - * - * @author Carter Page - */ -public class JSONCompareUtilTest { - @Test - public void testGetCardinalityMap() { - final int NUM_A = 76; - final int NUM_B = 3; - final int NUM_C = 0; - final int NUM_D = 1; - final int NUM_E = 2; - - List listToTest = new ArrayList(NUM_A + NUM_B + NUM_C + NUM_D + NUM_E); - for (int i = 0; i < NUM_A; ++i) listToTest.add("A"); - for (int i = 0; i < NUM_B; ++i) listToTest.add("B"); - for (int i = 0; i < NUM_C; ++i) listToTest.add("C"); - for (int i = 0; i < NUM_D; ++i) listToTest.add("D"); - for (int i = 0; i < NUM_E; ++i) listToTest.add("E"); - Collections.shuffle(listToTest); - - Map cardinalityMap = JSONCompareUtil.getCardinalityMap(listToTest); - Assert.assertEquals(NUM_A, cardinalityMap.get("A").intValue()); - Assert.assertEquals(NUM_B, cardinalityMap.get("B").intValue()); - Assert.assertNull(cardinalityMap.get("C")); - Assert.assertEquals(NUM_D, cardinalityMap.get("D").intValue()); - Assert.assertEquals(NUM_E, cardinalityMap.get("E").intValue()); - } -} diff --git a/src/test/resources/case_01_a.json b/src/test/resources/case_01_a.json new file mode 100644 index 00000000..d0fea0b8 --- /dev/null +++ b/src/test/resources/case_01_a.json @@ -0,0 +1,180 @@ +{ + "user": { + "name": "John Doe", + "age": 30, + "isStudent": false, + "email": "johndoe@example.com", + "address": { + "street": "123 Main St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "escapeKey": "{\"name\":\"John Doe\",\"age\":30,\"isStudent\":false,\"email\":\"johndoe@example.com\"}", + "location": { + "x": 37.7749, + "y": -122.4194 + }, + "position": "-300.0,-250.0", + "hobbies": [ + "reading", + "swimming", + "cycling" + ], + "friends": [ + { + "name": "Jane Smith", + "age": 28, + "email": "janesmith@example.com" + }, + { + "name": "Bob Johnson", + "age": 32, + "email": "bobjohnson@example.com" + } + ], + "queryTimestamp": 1672531200 + }, + "ordersStrictOrder": [ + { + "orderId": 123456, + "product": "Smartphone", + "quantity": 1, + "price": 999.99, + "isDelivered": true + }, + { + "orderId": 789012, + "product": "Laptop", + "quantity": 2, + "price": 1499.99, + "isDelivered": false + }, + { + "orderId": 567890, + "product": "Tablet", + "quantity": 3, + "price": 499.99, + "isDelivered": true + }, + { + "orderId": 234567, + "product": "Headphones", + "quantity": 4, + "price": 199.99, + "isDelivered": false + }, + { + "orderId": 678901, + "product": "Keyboard", + "quantity": 1, + "price": 79.99, + "isDelivered": true + }, + { + "orderId": 345678, + "product": "Mouse", + "quantity": 2, + "price": 39.99, + "isDelivered": false + }, + { + "orderId": 789013, + "product": "External Hard Drive", + "quantity": 1, + "price": 129.99, + "isDelivered": true + }, + { + "orderId": 456789, + "product": "Monitor", + "quantity": 1, + "price": 299.99, + "isDelivered": false + }, + { + "orderId": 890123, + "product": "Printer", + "quantity": 1, + "price": 149.99, + "isDelivered": true + }, + { + "orderId": 567891, + "product": "Scanner", + "quantity": 1, + "price": 99.99, + "isDelivered": false + } + ], + "ordersWithoutOrder": [ + { + "product": "Smartphone", + "quantity": 1, + "price": 999.99, + "isDelivered": true + }, + { + "product": "Laptop", + "quantity": 2, + "price": 1499.99, + "isDelivered": false + }, + { + "product": "Tablet", + "quantity": 3, + "price": 499.99, + "isDelivered": true + }, + { + "product": "Headphones", + "quantity": 4, + "price": 199.99, + "isDelivered": false + }, + { + "product": "Keyboard", + "quantity": 1, + "price": 79.99, + "isDelivered": true + }, + { + "product": "Mouse", + "quantity": 2, + "price": 39.99, + "isDelivered": false + }, + { + "product": "External Hard Drive", + "quantity": 1, + "price": 129.99, + "isDelivered": true + }, + { + "product": "Monitor", + "quantity": 1, + "price": 299.99, + "isDelivered": false + }, + { + "product": "Printer", + "quantity": 1, + "price": 149.99, + "isDelivered": true + }, + { + "product": "Scanner", + "quantity": 1, + "price": 99.99, + "isDelivered": false + } + ], + "settings": { + "theme": "dark", + "notifications": { + "email": true, + "sms": false + }, + "language": "en" + } +} \ No newline at end of file diff --git a/src/test/resources/case_01_e.json b/src/test/resources/case_01_e.json new file mode 100644 index 00000000..1b713937 --- /dev/null +++ b/src/test/resources/case_01_e.json @@ -0,0 +1,180 @@ +{ + "user": { + "name": "John Doe", + "age": 30, + "isStudent": false, + "email": "johndoe@example.com", + "address": { + "street": "123 Main St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "escapeKey": "{\"name\":\"John Doe\",\"age\":30,\"isStudent\":false,\"email\":\"johndoe@example.com\"}", + "location": { + "x": 37.7749001, + "y": -122.4194 + }, + "position": "-300.0,-250.0", + "hobbies": [ + "reading", + "swimming", + "cycling" + ], + "friends": [ + { + "name": "Jane Smith", + "age": 28, + "email": "janesmith@example.com" + }, + { + "name": "Bob Johnson", + "age": 32, + "email": "bobjohnson@example.com" + } + ], + "queryTimestamp": 1672531200 + }, + "ordersStrictOrder": [ + { + "orderId": 123456, + "product": "Smartphone", + "quantity": 1, + "price": 999.99, + "isDelivered": true + }, + { + "orderId": 789012, + "product": "Laptop", + "quantity": 2, + "price": 1499.99, + "isDelivered": false + }, + { + "orderId": 567890, + "product": "Tablet", + "quantity": 3, + "price": 499.99, + "isDelivered": true + }, + { + "orderId": 234567, + "product": "Headphones", + "quantity": 4, + "price": 199.99, + "isDelivered": false + }, + { + "orderId": 678901, + "product": "Keyboard", + "quantity": 1, + "price": 79.99, + "isDelivered": true + }, + { + "orderId": 345678, + "product": "Mouse", + "quantity": 2, + "price": 39.99, + "isDelivered": false + }, + { + "orderId": 789013, + "product": "External Hard Drive", + "quantity": 1, + "price": 129.99, + "isDelivered": true + }, + { + "orderId": 456789, + "product": "Monitor", + "quantity": 1, + "price": 299.99, + "isDelivered": false + }, + { + "orderId": 890123, + "product": "Printer", + "quantity": 1, + "price": 149.99, + "isDelivered": true + }, + { + "orderId": 567891, + "product": "Scanner", + "quantity": 1, + "price": 99.99, + "isDelivered": false + } + ], + "ordersWithoutOrder": [ + { + "product": "Smartphone", + "quantity": 1, + "price": 999.99, + "isDelivered": true + }, + { + "product": "Laptop", + "quantity": 2, + "price": 1499.99, + "isDelivered": false + }, + { + "product": "Tablet", + "quantity": 3, + "price": 499.99, + "isDelivered": true + }, + { + "product": "Headphones", + "quantity": 4, + "price": 199.99, + "isDelivered": false + }, + { + "product": "Keyboard", + "quantity": 1, + "price": 79.99, + "isDelivered": true + }, + { + "product": "Mouse", + "quantity": 2, + "price": 39.99, + "isDelivered": false + }, + { + "product": "External Hard Drive", + "quantity": 1, + "price": 129.99, + "isDelivered": true + }, + { + "product": "Monitor", + "quantity": 1, + "price": 299.99, + "isDelivered": false + }, + { + "product": "Printer", + "quantity": 1, + "price": 149.99, + "isDelivered": true + }, + { + "product": "Scanner", + "quantity": 1, + "price": 99.99, + "isDelivered": false + } + ], + "settings": { + "theme": "dark", + "notifications": { + "email": true, + "sms": false + }, + "language": "en" + } +} \ No newline at end of file diff --git a/src/test/resources/case_01_result.json b/src/test/resources/case_01_result.json new file mode 100644 index 00000000..30136d4d --- /dev/null +++ b/src/test/resources/case_01_result.json @@ -0,0 +1 @@ +[{"expected":37.7749,"actual":37.7749001,"diffKey":"location.x","reason":"actual unequals to expected"}] \ No newline at end of file diff --git a/src/test/resources/rule_case01.yaml b/src/test/resources/rule_case01.yaml new file mode 100644 index 00000000..e0a68f07 --- /dev/null +++ b/src/test/resources/rule_case01.yaml @@ -0,0 +1,95 @@ +# you can define multiple subRule +- subRule: + jsonPath: $.user + extensible: true + strictOrder: true + ignoreNull: true + fastFail: false + preProcess: # TODO + removeNode: + jsonPath: "" + escape: + jsonPath: "" + customRules: + - name: NumberPrecise + jsonPath: "**.age" + param: "newScale=3,roundingMode=3" + - name: ArrayWithKey + jsonPath: "$" + param: "key=id" + - name: IngorePath # which path will be ignored + param: "user.queryTimestamp" + - name: ArrayDisorder + jsonPath: "**.ordersWithoutOrder" + - name: ArrayRecursively + jsonPath: + param: + - name: DegreePrecise + jsonPath: + param: "tolerance=10e-1" + - name: RadianPrecise + jsonPath: + param: "tolerance=10e-4" + - name: TolerantValue + jsonPath: "" + param: "tolerance=10e-4" + - name: PercentTolerant + jsonPath: "" + param: "tolerance=10e-4" + - name: ImprecisePosition #eg: {"position": "-300.0,-250.0"} + jsonPath: "" + param: "tolerance=0.01;separator=," + +- subRule: + jsonPath: $.ordersStrictOrder + extensible: true + strictOrder: true + ignoreNull: true + fastFail: false + preProcess: # TODO + removeNode: + jsonPath: "" + escape: + jsonPath: "" + customRules: + - name: ArrayWithKey + jsonPath: "$" + param: "key=orderId" + - name: NumberPrecise + jsonPath: "**user.age" + param: "newScale=3,roundingMode=3" +- subRule: + jsonPath: $.ordersWithoutOrder + extensible: true + strictOrder: false + ignoreNull: true + fastFail: false + preProcess: # TODO + removeNode: + jsonPath: "" + escape: + jsonPath: "" + customRules: + - name: ArrayDisorder + jsonPath: "$" + - name: NumberPrecise + jsonPath: "**user.age" + param: "newScale=3,roundingMode=3" + +# as enum value +- ruleType: + - IngorePath + - ArrayWithKey + - NumberPrecise + - EscapedJson + - ArrayInOrder + - ArrayLength + - DegreePrecise + - RadianPrecise + - ArrayDisorder + - ArrayRecursively + - TolerantValue + - PercentTolerant + - ImprecisePosition + - EmptyValue + From e85756396d5575f47561b99a5d765ac2be58b281 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 06:55:20 +0800 Subject: [PATCH 02/18] Update README.md --- README.md | 121 ++++-------------------------------------------------- 1 file changed, 7 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index 871b1e19..bb05d3bd 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,7 @@ -JSONassert -========== - -Write JSON unit tests in less code. Great for testing REST interfaces. - -Summary -------- - -Write JSON tests as if you are comparing a string. Under the covers, JSONassert converts your string into a JSON object and compares the logical structure and data with the actual JSON. When _strict_ is set to false (recommended), it forgives reordering data and extending results (as long as all the expected elements are there), making tests less brittle. - -Supported test frameworks: - - * [JUnit](http://junit.org) - -Examples --------- - -In JSONassert you write and maintain something like this: - - JSONObject data = getRESTData("/friends/367.json"); - String expected = "{friends:[{id:123,name:\"Corby Page\"},{id:456,name:\"Carter Page\"}]}"; - JSONAssert.assertEquals(expected, data, false); - -instead of all this: - -

-JSONObject data = getRESTData("/friends/367.json");
-Assert.assertTrue(data.has("friends"));
-Object friendsObject = data.get("friends");
-Assert.assertTrue(friendsObject instanceof JSONArray);
-JSONArray friends = (JSONArray) friendsObject;
-Assert.assertEquals(2, friends.length());
-JSONObject friend1Obj = friends.getJSONObject(0);
-Assert.assertTrue(friend1Obj.has("id"));
-Assert.assertTrue(friend1Obj.has("name"));
-JSONObject friend2Obj = friends.getJSONObject(1);
-Assert.assertTrue(friend2Obj.has("id"));
-Assert.assertTrue(friend2Obj.has("name"));
-
-if ("Carter Page".equals(friend1Obj.getString("name"))) {
-    Assert.assertEquals(456, friend1Obj.getInt("id"));
-    Assert.assertEquals("Corby Page", friend2Obj.getString("name"));
-    Assert.assertEquals(123, friend2Obj.getInt("id"));
-}
-else if ("Corby Page".equals(friend1Obj.getString("name"))) {
-    Assert.assertEquals(123, friend1Obj.getInt("id"));
-    Assert.assertEquals("Carter Page", friend2Obj.getString("name"));
-    Assert.assertEquals(456, friend2Obj.getInt("id"));
-}
-else {
-    Assert.fail("Expected either Carter or Corby, Got: " + friend1Obj.getString("name"));
-}
-
- -Error Messages --------------- - -We tried to make error messages easy to understand. This is really important, since it gets hard for the eye to pick out the difference, particularly in long JSON strings. For example: - - String expected = "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"bird\",\"fish\"]}],pets:[]}"; - String actual = "{id:1,name:\"Joe\",friends:[{id:2,name:\"Pat\",pets:[\"dog\"]},{id:3,name:\"Sue\",pets:[\"cat\",\"fish\"]}],pets:[]}" - JSONAssert.assertEquals(expected, actual, false); - -returns the following: - - friends[id=3].pets[]: Expected bird, but not found ; friends[id=3].pets[]: Contains cat, but not expected - -Which tells you that the pets array under the friend where id=3 was supposed to contain "bird", but had "cat" instead. (Maybe the cat ate the bird?) - -* * * - -QuickStart ----------- - -To use, [download the JAR](https://github.com/skyscreamer/JSONassert/releases) or add the following to your project's pom.xml: - - - org.skyscreamer - jsonassert - 2.0-rc1 - test - - -Write tests like this: - -JSONAssert.assertEquals(expectedJSONString, actualJSON, strictMode); - -[More examples in our cookbook](http://jsonassert.skyscreamer.org/cookbook.html) - -* * * - -Who uses JSONassert? --------------------- - + [yoga](https://github.com/skyscreamer/yoga) - A relational REST framework - + [hamcrest-json](https://github.com/hertzsprung/hamcrest-json) - Hamcrest matchers for comparing JSON documents - + [Mule ESB](http://www.mulesoft.org/) - + [GroupDocs](http://groupdocs.com/) - + [Shazam](http://www.shazam.com/) - + [Thucydides](http://thucydides.net/) - + [and over a thousand more](https://mvnrepository.com/artifact/org.skyscreamer/jsonassert)... - -* * * - -org.json --------- - -As of v2, JSONAssert uses @stleary's [JSON-java](https://github.com/stleary/JSON-java) implementation of org.json, the -most commonly used reference implementation for JSON in Java. - -Resources ---------- - -[JavaDoc](http://jsonassert.skyscreamer.org/apidocs/index.html) - +A powerful jsondiff tool for develop and test engineer +compare the older version of +1. yaml file instead of json file +2. customized diff rule +3. you add new rule easily +4. faster for huge json object, add jsonpath selector to improve performance +etc. From 434ef6c7f69befc55f391b60d991acaed36136f7 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 06:59:31 +0800 Subject: [PATCH 03/18] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb05d3bd..5e9de79c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ +# What's this A powerful jsondiff tool for develop and test engineer -compare the older version of +refer the struct from https://github.com/skyscreamer/JSONassert +skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose 1. yaml file instead of json file 2. customized diff rule 3. you add new rule easily From 6f7e84566aca1218655aaf00b9bc26921de89f12 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:00:07 +0800 Subject: [PATCH 04/18] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5e9de79c..04730c8b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # What's this -A powerful jsondiff tool for develop and test engineer -refer the struct from https://github.com/skyscreamer/JSONassert -skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose +* A powerful jsondiff tool for develop and test engineer +* refer to the struct from https://github.com/skyscreamer/JSONassert +* skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose 1. yaml file instead of json file 2. customized diff rule 3. you add new rule easily From b117bda4612b73419a131166f7fe839238f63f1a Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:01:43 +0800 Subject: [PATCH 05/18] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 04730c8b..ea16e4fb 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ * A powerful jsondiff tool for develop and test engineer * refer to the struct from https://github.com/skyscreamer/JSONassert * skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose -1. yaml file instead of json file +1. yaml file to define diff rules 2. customized diff rule -3. you add new rule easily +3. Easier to rewrite and expand new rules 4. faster for huge json object, add jsonpath selector to improve performance etc. From 282eda4038802b31722858d2452c0c59dcfe3751 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:02:30 +0800 Subject: [PATCH 06/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ea16e4fb..caccb954 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# What's this +# What's this UJD(UtraJSONDiff) * A powerful jsondiff tool for develop and test engineer * refer to the struct from https://github.com/skyscreamer/JSONassert * skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose From e515bcde35ef39e4be1e06a26b3842aea362013a Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:07:34 +0800 Subject: [PATCH 07/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index caccb954..88939c00 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # What's this UJD(UtraJSONDiff) * A powerful jsondiff tool for develop and test engineer -* refer to the struct from https://github.com/skyscreamer/JSONassert +* rewrite some modules of https://github.com/skyscreamer/JSONassert * skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose 1. yaml file to define diff rules 2. customized diff rule From e404735fe68a68450ba0306408829f7ab59e5983 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:08:13 +0800 Subject: [PATCH 08/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88939c00..afc0cfa0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # What's this UJD(UtraJSONDiff) * A powerful jsondiff tool for develop and test engineer * rewrite some modules of https://github.com/skyscreamer/JSONassert -* skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff is just for diff purpose +* skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff experts in JSONDiff 1. yaml file to define diff rules 2. customized diff rule 3. Easier to rewrite and expand new rules From 5c5db4070cb7516d2bd365d6688d65a1dddac382 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:16:53 +0800 Subject: [PATCH 09/18] Update CHANGELOG.md --- CHANGELOG.md | 98 ++-------------------------------------------------- 1 file changed, 3 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b33ee64..1c502176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,99 +1,7 @@ Changelog ========= -Version 2.0-rc1 - 7/28/2024 +Version 1.0.0 - 03/02/2025 ------------------- - - Release candidate - - ** Switches JSON implementation to use org.json:json:20240303 ** - - Deployment still built with Java version 8 to maximize compatibility - - Cannot insert null directly into JSONArray without casting. Recommend to use JSONObject.Null - - JSONException is now a RuntimeException. Is not defined as thrown in method signatures anynmore. - -Version 1.5.3 - 6/28/2024 -------------------------- - - Revert Java release version from 21 to 8 due to breaking older compilers. - -Version 1.5.2 - 6/14/2024 -------------------------- - - Fix CVE-2020-15250 JUnit vulnerability (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15250). Bump - dependencies. - - Add gitIgnore file - - README syntax error fix - - Accidentally upgraded release to Java version 21 - -Version 1.5.1 - 7/4/2022 ------------------------- -Going to try to catch up on some ancient PRs, mainly around security and cleanup. Starting with accepted PRs that -didn't get released yet. To be followed hopefully shortly with another release. - - Added convenience methods for JSONObject comparison using a custom JSONComparator (thanks jakob-o@!) - - Fix issue #105: Issue when comparing JSONArray if any value is null (thanks suraj1291993@!) - - Fixes security vulnerability associated with older version of junit - -Version 1.5.0 - 3/19/2017 -------------------------- - - JSONassert now supports user-supplied error messages (thanks yasin3061@!) - - Some refactoring / code health cleanup (thanks picimako@!) - - License headers on individual files - - Java 8 friendly javadocs - -Version 1.4.0 - 10/30/2016 --------------------------- - - Change the implementation for org.json to one with a more open license - - Fix null pointer exception (issue #48) - - Support wildcards in Customization.path - -Version 1.3.0 - 12/16/2015 --------------------------- - - Fix & improve ArrayValueMatcher JavaDoc (thanks dmackinder@!) - Fix final JavaDoc example and add new example showing how to verify - every array element using a custom comparator - - Fix URL in pom.xml (aukevanleeuwen@) - - Update JSONCompareResult.java adding 2 new lists for missing and unexpected fileds (thanks riccorazza@!) - - Includes missing imports in test class (thanks javierseixas@!) - -Version 1.2.3 - 2/5/2014 ------------------------- - - This edition brought to you by dmackinder (thanks dmackinder!) - - Added array size comparator enhancements. - - Added ArrayValueMatcher to simplify verification of range of array elements. - - Improve diagnostics from RegularExpressionValueMatcher. - - Deprecated former Customization.matches() signature - -Version 1.2.2 - 12/31/2013 --------------------------- - - Add support for JSONString - -Version 1.2.1 - 10/24/2013 --------------------------- - - Remove commons-collection dependency - - Updated Customization class to allow path-matching, and matching of expected and actual values with user-provided - EqualityComparator. - - Added AssertNotEquals - -Version 1.2.0 - 3/17/2013 -------------------------- - - Fixed handling comparison of equivalent values across long, int, and double - - Add JSONCompareMode to asserts to allow for more options than strict/not-strict - - Added hooks to override/extend comparison behavior via JSONComparator - -Version 1.1.1 - 10/15/2012 --------------------------- - - Return diagnostics (instead of throwing an exception) when comparing JSONObject and JSONArray - - Expose field comparison results as a list in JSONCompareResult - - Fix bug where actual JSON array doesn't contain JSONObjects with unique keys - - Improve diagnostics - - Unify some diagnostics - - Fix handling of arrays of booleans - -Version 1.1.0 - 9/3/2012 ------------------------- - - Added withStrictOrdering() and withExtensible() to JSONCompareMode - - Javadoc fixes - - Fix bug where expected and actual were reversed - - Fix bug where nulls gave false positives in some cases - - Simplified publishing Javadocs - -Version 1.0.0 - 4/5/2012 ------------------------- -Initial release! - + - create repo + - first version of UJD From a50d7757faf5d6ce2341d2d36a07bb3e057ab596 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:17:10 +0800 Subject: [PATCH 10/18] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cc8b3e3b..606e8238 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.nezha UltraJSONDiff - 1.0-rc1 + 1.0。0 jar UltraJSONDiff From 8a3b896ef78711f299e18bc8b10621c43fc5bff5 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 2 Mar 2025 07:18:24 +0800 Subject: [PATCH 11/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afc0cfa0..67d21abf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # What's this UJD(UtraJSONDiff) -* A powerful jsondiff tool for develop and test engineer +* A powerful jsondiff tool for developer and test engineer * rewrite some modules of https://github.com/skyscreamer/JSONassert * skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff experts in JSONDiff 1. yaml file to define diff rules From 4786df1ce6e468af2039e834289ae066ff55140d Mon Sep 17 00:00:00 2001 From: shendiao Date: Sun, 2 Mar 2025 08:42:36 +0800 Subject: [PATCH 12/18] modify package name to testtools --- .../testtools}/jsondiff/CompareContext.java | 2 +- .../testtools}/jsondiff/CompareMatcherItem.java | 2 +- .../testtools}/jsondiff/CompareRule.java | 4 ++-- .../testtools}/jsondiff/CompareRules.java | 2 +- .../jsondiff/CompareRulesTransformer.java | 6 +++--- .../testtools}/jsondiff/CustomCompareRule.java | 2 +- .../testtools}/jsondiff/Customization.java | 12 ++++++------ .../testtools}/jsondiff/FailureField.java | 2 +- .../jsondiff/FieldComparisonFailure.java | 2 +- .../testtools}/jsondiff/JSONCompare.java | 8 ++++---- .../testtools}/jsondiff/JSONCompareConf.java | 2 +- .../jsondiff/JSONCompareDeepDetailResult.java | 2 +- .../jsondiff/JSONCompareDetailResult.java | 4 ++-- .../testtools}/jsondiff/JSONCompareResult.java | 2 +- .../testtools}/jsondiff/JSONCompareResultUtil.java | 2 +- .../jsondiff/JSONCompareSimpleResult.java | 2 +- .../testtools}/jsondiff/JSONParser.java | 2 +- .../testtools}/jsondiff/PreProcessItem.java | 2 +- .../jsondiff/comparator/AbstractComparator.java | 6 +++--- .../jsondiff/comparator/ArraySizeComparator.java | 6 +++--- .../jsondiff/comparator/CustomComparator.java | 10 +++++----- .../jsondiff/comparator/DefaultComparator.java | 10 +++++----- .../jsondiff/comparator/JSONComparator.java | 6 +++--- .../jsondiff/comparator/JSONCompareUtil.java | 2 +- .../testtools}/jsondiff/constant/Param.java | 2 +- .../jsondiff/matcher/ArrayDisorderMatcher.java | 8 ++++---- .../jsondiff/matcher/ArrayInOrderMatcher.java | 8 ++++---- .../jsondiff/matcher/ArrayLengthMatcher.java | 8 ++++---- .../jsondiff/matcher/ArrayRecursivelyMatcher.java | 8 ++++---- .../jsondiff/matcher/ArrayValueMatcher.java | 8 ++++---- .../jsondiff/matcher/ArrayWithKeyMatcher.java | 14 +++++++------- .../jsondiff/matcher/ComparatorValueMatcher.java | 10 +++++----- .../jsondiff/matcher/CustomValueMatcher.java | 6 +++--- .../jsondiff/matcher/DegreePreciseMatcher.java | 6 +++--- .../jsondiff/matcher/EmptyValueMatcher.java | 6 +++--- .../jsondiff/matcher/EscapedJsonMatcher.java | 10 +++++----- .../jsondiff/matcher/ImprecisePositionMatcher.java | 6 +++--- .../jsondiff/matcher/IngorePathMatcher.java | 4 ++-- .../matcher/LocationAwareValueMatcher.java | 4 ++-- .../jsondiff/matcher/NumberPreciseMatcher.java | 6 +++--- .../jsondiff/matcher/PercentTolerantMatcher.java | 6 +++--- .../jsondiff/matcher/RadianPreciseMatcher.java | 6 +++--- .../matcher/RegularExpressionValueMatcher.java | 4 ++-- .../jsondiff/matcher/TolerantValueMatcher.java | 6 +++--- .../testtools}/jsondiff/matcher/ValueMatcher.java | 4 ++-- .../jsondiff/matcher/ValueMatcherException.java | 2 +- .../java/jsondiff/JSONCompareYamlResultTest.java | 4 ++-- 47 files changed, 123 insertions(+), 123 deletions(-) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CompareContext.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CompareMatcherItem.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CompareRule.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CompareRules.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CompareRulesTransformer.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/CustomCompareRule.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/Customization.java (95%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/FailureField.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/FieldComparisonFailure.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompare.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareConf.java (99%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareDeepDetailResult.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareDetailResult.java (99%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareResult.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareResultUtil.java (99%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONCompareSimpleResult.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/JSONParser.java (99%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/PreProcessItem.java (95%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/AbstractComparator.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/ArraySizeComparator.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/CustomComparator.java (91%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/DefaultComparator.java (94%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/JSONComparator.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/comparator/JSONCompareUtil.java (99%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/constant/Param.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayDisorderMatcher.java (91%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayInOrderMatcher.java (91%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayLengthMatcher.java (91%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayRecursivelyMatcher.java (96%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayValueMatcher.java (98%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ArrayWithKeyMatcher.java (91%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ComparatorValueMatcher.java (86%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/CustomValueMatcher.java (93%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/DegreePreciseMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/EmptyValueMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/EscapedJsonMatcher.java (89%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ImprecisePositionMatcher.java (95%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/IngorePathMatcher.java (90%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/LocationAwareValueMatcher.java (95%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/NumberPreciseMatcher.java (93%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/PercentTolerantMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/RadianPreciseMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/RegularExpressionValueMatcher.java (97%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/TolerantValueMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ValueMatcher.java (92%) rename src/main/java/{com/nezha => org/testtools}/jsondiff/matcher/ValueMatcherException.java (98%) diff --git a/src/main/java/com/nezha/jsondiff/CompareContext.java b/src/main/java/org/testtools/jsondiff/CompareContext.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/CompareContext.java rename to src/main/java/org/testtools/jsondiff/CompareContext.java index b4759243..b7e6da1a 100644 --- a/src/main/java/com/nezha/jsondiff/CompareContext.java +++ b/src/main/java/org/testtools/jsondiff/CompareContext.java @@ -1,4 +1,4 @@ -package com.nezha.jsondiff; +package org.testtools.jsondiff; public class CompareContext { private Boolean extensible = true; diff --git a/src/main/java/com/nezha/jsondiff/CompareMatcherItem.java b/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/CompareMatcherItem.java rename to src/main/java/org/testtools/jsondiff/CompareMatcherItem.java index 9216ccd1..775c87f1 100644 --- a/src/main/java/com/nezha/jsondiff/CompareMatcherItem.java +++ b/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java @@ -1,4 +1,4 @@ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import java.util.Map; diff --git a/src/main/java/com/nezha/jsondiff/CompareRule.java b/src/main/java/org/testtools/jsondiff/CompareRule.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/CompareRule.java rename to src/main/java/org/testtools/jsondiff/CompareRule.java index d484adfd..1e66ba1c 100644 --- a/src/main/java/com/nezha/jsondiff/CompareRule.java +++ b/src/main/java/org/testtools/jsondiff/CompareRule.java @@ -1,6 +1,6 @@ -package com.nezha.jsondiff; +package org.testtools.jsondiff; -import com.nezha.jsondiff.constant.Param; +import org.testtools.jsondiff.constant.Param; import java.util.List; import java.util.Map; diff --git a/src/main/java/com/nezha/jsondiff/CompareRules.java b/src/main/java/org/testtools/jsondiff/CompareRules.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/CompareRules.java rename to src/main/java/org/testtools/jsondiff/CompareRules.java index bd3c4735..43dd47a9 100644 --- a/src/main/java/com/nezha/jsondiff/CompareRules.java +++ b/src/main/java/org/testtools/jsondiff/CompareRules.java @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java b/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java rename to src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java index 74f5b271..34fb7792 100644 --- a/src/main/java/com/nezha/jsondiff/CompareRulesTransformer.java +++ b/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java @@ -13,12 +13,12 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.nezha.jsondiff.comparator.CustomComparator; -import com.nezha.jsondiff.matcher.ValueMatcher; +import org.testtools.jsondiff.comparator.CustomComparator; +import org.testtools.jsondiff.matcher.ValueMatcher; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/com/nezha/jsondiff/CustomCompareRule.java b/src/main/java/org/testtools/jsondiff/CustomCompareRule.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/CustomCompareRule.java rename to src/main/java/org/testtools/jsondiff/CustomCompareRule.java index 75fb5e89..fce77c38 100644 --- a/src/main/java/com/nezha/jsondiff/CustomCompareRule.java +++ b/src/main/java/org/testtools/jsondiff/CustomCompareRule.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; public class CustomCompareRule { String path; diff --git a/src/main/java/com/nezha/jsondiff/Customization.java b/src/main/java/org/testtools/jsondiff/Customization.java similarity index 95% rename from src/main/java/com/nezha/jsondiff/Customization.java rename to src/main/java/org/testtools/jsondiff/Customization.java index b87491d7..3791382e 100644 --- a/src/main/java/com/nezha/jsondiff/Customization.java +++ b/src/main/java/org/testtools/jsondiff/Customization.java @@ -12,14 +12,14 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; -import com.nezha.jsondiff.comparator.JSONComparator; -import com.nezha.jsondiff.matcher.CustomValueMatcher; -import com.nezha.jsondiff.matcher.LocationAwareValueMatcher; -import com.nezha.jsondiff.matcher.ValueMatcher; -import com.nezha.jsondiff.matcher.ValueMatcherException; +import org.testtools.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.matcher.CustomValueMatcher; +import org.testtools.jsondiff.matcher.LocationAwareValueMatcher; +import org.testtools.jsondiff.matcher.ValueMatcher; +import org.testtools.jsondiff.matcher.ValueMatcherException; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/com/nezha/jsondiff/FailureField.java b/src/main/java/org/testtools/jsondiff/FailureField.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/FailureField.java rename to src/main/java/org/testtools/jsondiff/FailureField.java index d060e09e..f8b3e530 100644 --- a/src/main/java/com/nezha/jsondiff/FailureField.java +++ b/src/main/java/org/testtools/jsondiff/FailureField.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; public class FailureField { private final Object expected; diff --git a/src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java b/src/main/java/org/testtools/jsondiff/FieldComparisonFailure.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java rename to src/main/java/org/testtools/jsondiff/FieldComparisonFailure.java index 33c24ec3..327b9a76 100644 --- a/src/main/java/com/nezha/jsondiff/FieldComparisonFailure.java +++ b/src/main/java/org/testtools/jsondiff/FieldComparisonFailure.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; /** * Models a failure when comparing two fields. diff --git a/src/main/java/com/nezha/jsondiff/JSONCompare.java b/src/main/java/org/testtools/jsondiff/JSONCompare.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/JSONCompare.java rename to src/main/java/org/testtools/jsondiff/JSONCompare.java index 56ce03c1..b2ffc821 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompare.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompare.java @@ -12,14 +12,14 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; -import com.nezha.jsondiff.comparator.CustomComparator; -import com.nezha.jsondiff.comparator.DefaultComparator; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.comparator.CustomComparator; +import org.testtools.jsondiff.comparator.DefaultComparator; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareConf.java b/src/main/java/org/testtools/jsondiff/JSONCompareConf.java similarity index 99% rename from src/main/java/com/nezha/jsondiff/JSONCompareConf.java rename to src/main/java/org/testtools/jsondiff/JSONCompareConf.java index c1aa6de4..ba786e53 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareConf.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareConf.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import org.yaml.snakeyaml.Yaml; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java b/src/main/java/org/testtools/jsondiff/JSONCompareDeepDetailResult.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java rename to src/main/java/org/testtools/jsondiff/JSONCompareDeepDetailResult.java index 581e397b..f3673609 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareDeepDetailResult.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareDeepDetailResult.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java b/src/main/java/org/testtools/jsondiff/JSONCompareDetailResult.java similarity index 99% rename from src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java rename to src/main/java/org/testtools/jsondiff/JSONCompareDetailResult.java index 7226814a..0690c5dd 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareDetailResult.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareDetailResult.java @@ -12,9 +12,9 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; -import com.nezha.jsondiff.matcher.ValueMatcherException; +import org.testtools.jsondiff.matcher.ValueMatcherException; import org.json.JSONArray; import org.json.JSONObject; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareResult.java b/src/main/java/org/testtools/jsondiff/JSONCompareResult.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/JSONCompareResult.java rename to src/main/java/org/testtools/jsondiff/JSONCompareResult.java index 1b9805dc..fc200aa3 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareResult.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareResult.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java b/src/main/java/org/testtools/jsondiff/JSONCompareResultUtil.java similarity index 99% rename from src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java rename to src/main/java/org/testtools/jsondiff/JSONCompareResultUtil.java index 3512f1a9..1e7cc57d 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareResultUtil.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareResultUtil.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import org.json.JSONArray; import org.json.JSONException; diff --git a/src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java b/src/main/java/org/testtools/jsondiff/JSONCompareSimpleResult.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java rename to src/main/java/org/testtools/jsondiff/JSONCompareSimpleResult.java index 36a5bbc0..ceb9b55a 100644 --- a/src/main/java/com/nezha/jsondiff/JSONCompareSimpleResult.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareSimpleResult.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/nezha/jsondiff/JSONParser.java b/src/main/java/org/testtools/jsondiff/JSONParser.java similarity index 99% rename from src/main/java/com/nezha/jsondiff/JSONParser.java rename to src/main/java/org/testtools/jsondiff/JSONParser.java index 883cc48a..1a93870b 100644 --- a/src/main/java/com/nezha/jsondiff/JSONParser.java +++ b/src/main/java/org/testtools/jsondiff/JSONParser.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; import org.apache.commons.lang.StringEscapeUtils; import org.json.JSONArray; diff --git a/src/main/java/com/nezha/jsondiff/PreProcessItem.java b/src/main/java/org/testtools/jsondiff/PreProcessItem.java similarity index 95% rename from src/main/java/com/nezha/jsondiff/PreProcessItem.java rename to src/main/java/org/testtools/jsondiff/PreProcessItem.java index c4947193..5eae4f0c 100644 --- a/src/main/java/com/nezha/jsondiff/PreProcessItem.java +++ b/src/main/java/org/testtools/jsondiff/PreProcessItem.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff; +package org.testtools.jsondiff; public class PreProcessItem { String path; diff --git a/src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java b/src/main/java/org/testtools/jsondiff/comparator/AbstractComparator.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java rename to src/main/java/org/testtools/jsondiff/comparator/AbstractComparator.java index 89a12df2..079993b4 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/AbstractComparator.java +++ b/src/main/java/org/testtools/jsondiff/comparator/AbstractComparator.java @@ -12,9 +12,9 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; -import com.nezha.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -23,7 +23,7 @@ import java.util.Map; import java.util.Set; -import static com.nezha.jsondiff.comparator.JSONCompareUtil.*; +import static org.testtools.jsondiff.comparator.JSONCompareUtil.*; /** * This class provides a skeletal implementation of the {@link JSONComparator} diff --git a/src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java b/src/main/java/org/testtools/jsondiff/comparator/ArraySizeComparator.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java rename to src/main/java/org/testtools/jsondiff/comparator/ArraySizeComparator.java index f7b5afe9..904e905a 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/ArraySizeComparator.java +++ b/src/main/java/org/testtools/jsondiff/comparator/ArraySizeComparator.java @@ -12,10 +12,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; import org.json.JSONException; diff --git a/src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java b/src/main/java/org/testtools/jsondiff/comparator/CustomComparator.java similarity index 91% rename from src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java rename to src/main/java/org/testtools/jsondiff/comparator/CustomComparator.java index ab467b57..5fe13e71 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/CustomComparator.java +++ b/src/main/java/org/testtools/jsondiff/comparator/CustomComparator.java @@ -12,12 +12,12 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.Customization; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.matcher.ValueMatcherException; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.Customization; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.matcher.ValueMatcherException; import org.json.JSONException; import java.util.Arrays; diff --git a/src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java b/src/main/java/org/testtools/jsondiff/comparator/DefaultComparator.java similarity index 94% rename from src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java rename to src/main/java/org/testtools/jsondiff/comparator/DefaultComparator.java index c85a2718..fd0f898b 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/DefaultComparator.java +++ b/src/main/java/org/testtools/jsondiff/comparator/DefaultComparator.java @@ -12,16 +12,16 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import static com.nezha.jsondiff.comparator.JSONCompareUtil.allJSONObjects; -import static com.nezha.jsondiff.comparator.JSONCompareUtil.allSimpleValues; +import static org.testtools.jsondiff.comparator.JSONCompareUtil.allJSONObjects; +import static org.testtools.jsondiff.comparator.JSONCompareUtil.allSimpleValues; /** * This class is the default json comparator implementation. diff --git a/src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java b/src/main/java/org/testtools/jsondiff/comparator/JSONComparator.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java rename to src/main/java/org/testtools/jsondiff/comparator/JSONComparator.java index 3c970f46..06ac7c64 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/JSONComparator.java +++ b/src/main/java/org/testtools/jsondiff/comparator/JSONComparator.java @@ -12,10 +12,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java b/src/main/java/org/testtools/jsondiff/comparator/JSONCompareUtil.java similarity index 99% rename from src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java rename to src/main/java/org/testtools/jsondiff/comparator/JSONCompareUtil.java index cdb4ecd7..a531a366 100644 --- a/src/main/java/com/nezha/jsondiff/comparator/JSONCompareUtil.java +++ b/src/main/java/org/testtools/jsondiff/comparator/JSONCompareUtil.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff.comparator; +package org.testtools.jsondiff.comparator; import org.apache.commons.lang.StringUtils; import org.json.JSONArray; diff --git a/src/main/java/com/nezha/jsondiff/constant/Param.java b/src/main/java/org/testtools/jsondiff/constant/Param.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/constant/Param.java rename to src/main/java/org/testtools/jsondiff/constant/Param.java index eb674986..8791c797 100644 --- a/src/main/java/com/nezha/jsondiff/constant/Param.java +++ b/src/main/java/org/testtools/jsondiff/constant/Param.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff.constant; +package org.testtools.jsondiff.constant; public class Param { public static final String STRICT_ORDER = "strictOrder"; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayDisorderMatcher.java similarity index 91% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayDisorderMatcher.java index 7d16c0b8..e9affafb 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayDisorderMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayDisorderMatcher.java @@ -12,16 +12,16 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Function: * */ -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONArray; import org.json.JSONException; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayInOrderMatcher.java similarity index 91% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayInOrderMatcher.java index 5b327d96..d55ad624 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayInOrderMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayInOrderMatcher.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Function: @@ -19,9 +19,9 @@ * */ -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONArray; import org.json.JSONException; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayLengthMatcher.java similarity index 91% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayLengthMatcher.java index fca10c43..38f56605 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayLengthMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayLengthMatcher.java @@ -12,14 +12,14 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** */ -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONArray; import org.json.JSONException; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayRecursivelyMatcher.java similarity index 96% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayRecursivelyMatcher.java index 08e16370..12341945 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayRecursivelyMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayRecursivelyMatcher.java @@ -12,16 +12,16 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Function: * */ -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayValueMatcher.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayValueMatcher.java index dd76f88b..2d431e8b 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayValueMatcher.java @@ -12,15 +12,15 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; import java.text.MessageFormat; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.CompareContext; import org.json.JSONArray; import org.json.JSONException; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.comparator.JSONComparator; /** *

A value matcher for arrays. This operates like STRICT_ORDER array match, diff --git a/src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ArrayWithKeyMatcher.java similarity index 91% rename from src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ArrayWithKeyMatcher.java index 0d815b33..aa6eac75 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ArrayWithKeyMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ArrayWithKeyMatcher.java @@ -12,22 +12,22 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.comparator.JSONComparator; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.Map; -import static com.nezha.jsondiff.comparator.JSONCompareUtil.arrayOfJsonObjectToMap; -import static com.nezha.jsondiff.comparator.JSONCompareUtil.formatUniqueKey; +import static org.testtools.jsondiff.comparator.JSONCompareUtil.arrayOfJsonObjectToMap; +import static org.testtools.jsondiff.comparator.JSONCompareUtil.formatUniqueKey; /** *

A value matcher for arrays of JsonObjects. This operates like diff --git a/src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ComparatorValueMatcher.java similarity index 86% rename from src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ComparatorValueMatcher.java index 30982f61..35fdfa26 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ComparatorValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ComparatorValueMatcher.java @@ -13,12 +13,12 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.comparator.DefaultComparator; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.DefaultComparator; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONException; /** diff --git a/src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java similarity index 93% rename from src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java index 2e66e96d..6fd276d1 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/CustomValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.JSONComparator; /** * Function: diff --git a/src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/DegreePreciseMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/DegreePreciseMatcher.java index 5896fbd6..81f257e3 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/DegreePreciseMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/DegreePreciseMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.util.Objects; diff --git a/src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/EmptyValueMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/EmptyValueMatcher.java index 913c0563..be273672 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/EmptyValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/EmptyValueMatcher.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Function: @@ -20,8 +20,8 @@ * */ -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import org.json.JSONArray; import org.json.JSONObject; diff --git a/src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java similarity index 89% rename from src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java index f4ea71b0..64a84c0e 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/EscapedJsonMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java @@ -12,17 +12,17 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Function: * */ -import com.nezha.jsondiff.JSONCompareDetailResult; -import com.nezha.jsondiff.JSONParser; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.JSONParser; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONComparator; import org.json.JSONException; import java.text.MessageFormat; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ImprecisePositionMatcher.java similarity index 95% rename from src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ImprecisePositionMatcher.java index c558cdc4..bb616140 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ImprecisePositionMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ImprecisePositionMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.util.Objects; diff --git a/src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java similarity index 90% rename from src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java index 0326dd30..7320a22a 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/IngorePathMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java @@ -12,9 +12,9 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; +import org.testtools.jsondiff.CompareContext; /** * Function: diff --git a/src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/LocationAwareValueMatcher.java similarity index 95% rename from src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/LocationAwareValueMatcher.java index c3b0084a..17cd5bfe 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/LocationAwareValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/LocationAwareValueMatcher.java @@ -15,9 +15,9 @@ /** * */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.JSONCompareDetailResult; /** * A ValueMatcher extension that provides location in form of prefix to the equals method. diff --git a/src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/NumberPreciseMatcher.java similarity index 93% rename from src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/NumberPreciseMatcher.java index ac683223..c6912f60 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/NumberPreciseMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/NumberPreciseMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.math.RoundingMode; diff --git a/src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/PercentTolerantMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/PercentTolerantMatcher.java index e8714cc3..3e429590 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/PercentTolerantMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/PercentTolerantMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.util.Objects; diff --git a/src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/RadianPreciseMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/RadianPreciseMatcher.java index 1cd4b097..5717c383 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/RadianPreciseMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/RadianPreciseMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.util.Objects; diff --git a/src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/RegularExpressionValueMatcher.java similarity index 97% rename from src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/RegularExpressionValueMatcher.java index 0a8f0567..cdc81262 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/RegularExpressionValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/RegularExpressionValueMatcher.java @@ -12,9 +12,9 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; +import org.testtools.jsondiff.CompareContext; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; diff --git a/src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java index 5b37dea8..b65e200c 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/TolerantValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java @@ -13,10 +13,10 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; -import com.nezha.jsondiff.comparator.JSONCompareUtil; +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.comparator.JSONCompareUtil; import java.math.BigDecimal; import java.util.Objects; diff --git a/src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/ValueMatcher.java similarity index 92% rename from src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java rename to src/main/java/org/testtools/jsondiff/matcher/ValueMatcher.java index 0434572d..914e1bd6 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ValueMatcher.java @@ -12,9 +12,9 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; -import com.nezha.jsondiff.CompareContext; +import org.testtools.jsondiff.CompareContext; /** * Represents a value matcher that can compare two objects for equality. diff --git a/src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java b/src/main/java/org/testtools/jsondiff/matcher/ValueMatcherException.java similarity index 98% rename from src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java rename to src/main/java/org/testtools/jsondiff/matcher/ValueMatcherException.java index 470e923e..50df4c1c 100644 --- a/src/main/java/com/nezha/jsondiff/matcher/ValueMatcherException.java +++ b/src/main/java/org/testtools/jsondiff/matcher/ValueMatcherException.java @@ -12,7 +12,7 @@ * limitations under the License. */ -package com.nezha.jsondiff.matcher; +package org.testtools.jsondiff.matcher; /** * Exception that may be thrown by ValueMatcher subclasses to provide more detail on why matches method failed. diff --git a/src/test/java/jsondiff/JSONCompareYamlResultTest.java b/src/test/java/jsondiff/JSONCompareYamlResultTest.java index 01f36add..e5bea708 100644 --- a/src/test/java/jsondiff/JSONCompareYamlResultTest.java +++ b/src/test/java/jsondiff/JSONCompareYamlResultTest.java @@ -16,8 +16,8 @@ package jsondiff; import com.fasterxml.jackson.databind.ObjectMapper; -import com.nezha.jsondiff.JSONCompare; -import com.nezha.jsondiff.JSONCompareResult; +import org.testtools.jsondiff.JSONCompare; +import org.testtools.jsondiff.JSONCompareResult; import org.junit.Test; import java.io.File; From cb987c47e20e9ff31e87410898a6807a056061e3 Mon Sep 17 00:00:00 2001 From: liuge Date: Sat, 19 Jul 2025 11:54:24 +0800 Subject: [PATCH 13/18] update code add description --- README.md | 286 +++++++++++++++++- .../jsondiff/CompareMatcherItem.java | 11 +- .../org/testtools/jsondiff/CompareRule.java | 77 +++-- .../jsondiff/CompareRulesTransformer.java | 268 ++++++++++++++-- .../testtools/jsondiff/JSONCompareConf.java | 130 ++++---- .../jsondiff/matcher/CustomValueMatcher.java | 80 ++--- .../matcher/TolerantValueMatcher.java | 4 +- .../jsondiff/CompareRulesTransformerTest.java | 104 +++++++ src/test/java/jsondiff/FileUtil.java | 53 +++- .../jsondiff/JSONCompareYamlResultTest.java | 213 +++++++++++-- src/test/resources/rule_case01.yaml | 18 ++ 11 files changed, 1058 insertions(+), 186 deletions(-) create mode 100644 src/test/java/jsondiff/CompareRulesTransformerTest.java diff --git a/README.md b/README.md index 67d21abf..31ca4006 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,279 @@ -# What's this UJD(UtraJSONDiff) +# What's this UJD(UltraJSONDiff) * A powerful jsondiff tool for developer and test engineer -* rewrite some modules of https://github.com/skyscreamer/JSONassert -* skyscreamer/JSONassert is a tool for Assert but UtraJSONDiff experts in JSONDiff -1. yaml file to define diff rules -2. customized diff rule -3. Easier to rewrite and expand new rules -4. faster for huge json object, add jsonpath selector to improve performance -etc. +* rewrite some modules of https://github.com/skyscreamer/JSONassert which is a tool for Test Assert but UltraJSONDiff experts in JSONDiff +# Core Advantages +1. Use yaml file to define complex json comparison rules +2. Can customize rules +3. Can easily extend new comparison rules based on existing source code, Easier to rewrite and expand new rules +4. For huge json files, such as json files over several megabytes, has better performance, with jsonpath selector to improve performance + +# Configuration Example + +## SubRule Configuration + +The following example demonstrates how to configure a subRule for comparing JSON data: + +```yaml +- subRule: + # JSONPath expression to specify which part of the JSON to apply this rule to + jsonPath: $.user + # Whether the target JSON can have additional fields not present in the expected JSON + extensible: true + # Whether arrays should be compared in strict order (true) or allow reordering (false) + strictOrder: true + # Whether to ignore null values during comparison + ignoreNull: true + # Whether to stop comparison immediately when first difference is found + fastFail: false + preProcess: # TODO + # Remove specific nodes from JSON before comparison + removeNode: + jsonPath: "" + # Escape special characters in JSON values + escape: + jsonPath: "" + # Custom comparison rules to apply to this JSONPath + customRules: + # Apply number precision comparison to all age fields (3 decimal places, rounding mode 3) + - name: NumberPrecise + jsonPath: "**.age" + param: "newScale=3,roundingMode=3" + # Compare arrays using a specific key field for matching elements + - name: ArrayWithKey + jsonPath: "$" + param: "key=id" + # Ignore specific paths during comparison + - name: IngorePath + param: "user.queryTimestamp" + # Allow array elements to be in any order + - name: ArrayDisorder + jsonPath: "**.ordersWithoutOrder" + # Recursively compare array elements + - name: ArrayRecursively + jsonPath: + param: + # Compare degree values with specified tolerance + - name: DegreePrecise + jsonPath: + param: "tolerance=10e-1" + # Compare radian values with specified tolerance + - name: RadianPrecise + jsonPath: + param: "tolerance=10e-4" + # Compare values with tolerance for floating point differences + - name: TolerantValue + jsonPath: "" + param: "tolerance=10e-4" + # Compare values with percentage-based tolerance + - name: PercentTolerant + jsonPath: "" + param: "tolerance=10e-4" + # Compare position values with tolerance (e.g., {"position": "-300.0,-250.0"}) + - name: ImprecisePosition + jsonPath: "" + param: "tolerance=0.01;separator=," + +### Configuration Parameters Explained + +- **jsonPath**: Specifies the JSON path to which this rule applies (e.g., `$.user` targets the user object) +- **extensible**: When `true`, allows the target JSON to contain additional fields not present in the expected JSON +- **strictOrder**: When `true`, arrays must be in the exact same order; when `false`, array elements can be reordered +- **ignoreNull**: When `true`, null values are ignored during comparison +- **fastFail**: When `true`, comparison stops immediately when the first difference is found +- **preProcess**: Pre-processing options for removing nodes or escaping characters before comparison +- **customRules**: Array of custom comparison rules with specific behaviors: + - **NumberPrecise**: Compares numbers with specified precision and rounding mode + - **ArrayWithKey**: Compares arrays using a specific key field for element matching + - **IngorePath**: Ignores specific JSON paths during comparison + - **ArrayDisorder**: Allows array elements to be in any order + - **ArrayRecursively**: Recursively compares array elements + - **DegreePrecise**: Compares degree values with tolerance + - **RadianPrecise**: Compares radian values with tolerance + - **TolerantValue**: Compares values with tolerance for floating point differences + - **PercentTolerant**: Compares values with percentage-based tolerance + - **ImprecisePosition**: Compares position values with tolerance + +## Creating Custom Matcher Classes + +UltraJSONDiff provides a flexible framework for creating custom matcher classes to handle specific comparison requirements. This section explains how to create and integrate custom matchers. + +### Matcher Interface Types + +There are three main interfaces you can implement for custom matchers: + +1. **ValueMatcher**: Basic interface for simple value comparison +2. **CustomValueMatcher**: Extended interface for complex comparison with detailed failure reporting +3. **LocationAwareValueMatcher**: Interface for matchers that need access to JSON path information + +### Basic Custom Matcher Example + +Here's an example of creating a simple custom matcher that compares date strings in a specific format: + +```java +package org.testtools.jsondiff.matcher; + +import org.testtools.jsondiff.CompareContext; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Custom matcher for comparing date strings in YYYY-MM-DD format + */ +public class DateStringMatcher implements ValueMatcher { + private DateTimeFormatter formatter; + + public DateStringMatcher() { + this.formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + } + + @Override + public boolean equal(T actual, T expected) { + try { + String actualStr = actual.toString(); + String expectedStr = expected.toString(); + + LocalDate actualDate = LocalDate.parse(actualStr, formatter); + LocalDate expectedDate = LocalDate.parse(expectedStr, formatter); + + return actualDate.equals(expectedDate); + } catch (Exception e) { + // If parsing fails, fall back to string comparison + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + // Parse custom date format from parameter if provided + if (param != null && !param.trim().isEmpty()) { + try { + this.formatter = DateTimeFormatter.ofPattern(param.trim()); + } catch (Exception e) { + // Keep default format if parameter is invalid + } + } + } +} +``` + +### Advanced Custom Matcher Example + +For more complex scenarios requiring detailed failure reporting, implement `CustomValueMatcher`: + +```java +package org.testtools.jsondiff.matcher; + +import org.testtools.jsondiff.CompareContext; +import org.testtools.jsondiff.JSONCompareDetailResult; +import org.testtools.jsondiff.comparator.JSONComparator; +import org.testtools.jsondiff.comparator.JSONCompareUtil; +import java.math.BigDecimal; +import java.util.Objects; + +/** + * Custom matcher for comparing numeric ranges with percentage tolerance + */ +public class RangePercentageMatcher implements CustomValueMatcher { + private double percentageTolerance; + + public RangePercentageMatcher() { + this.percentageTolerance = 5.0; // Default 5% tolerance + } + + @Override + public boolean equal(T actual, T expected) { + // Basic implementation for simple comparison + return equal(null, actual, expected, null, null); + } + + @Override + public boolean equal(String prefix, T actual, T expected, + JSONCompareDetailResult result, JSONComparator comparator) + throws ValueMatcherException { + try { + BigDecimal actualNum = new BigDecimal(actual.toString()); + BigDecimal expectedNum = new BigDecimal(expected.toString()); + + // Calculate percentage difference + BigDecimal diff = actualNum.subtract(expectedNum).abs(); + BigDecimal percentageDiff = diff.divide(expectedNum, 4, BigDecimal.ROUND_HALF_UP) + .multiply(BigDecimal.valueOf(100)); + + boolean isWithinTolerance = percentageDiff.compareTo(BigDecimal.valueOf(percentageTolerance)) <= 0; + + if (!isWithinTolerance && result != null) { + // Add detailed failure information + result.fail(prefix, + String.format("Expected value within %.2f%% tolerance", percentageTolerance), + String.format("Actual: %s, Expected: %s, Difference: %.2f%%", + actual, expected, percentageDiff.doubleValue())); + } + + return isWithinTolerance; + } catch (NumberFormatException e) { + // Fall back to exact comparison for non-numeric values + return actual.equals(expected); + } + } + + @Override + public void matcherInit(String param, CompareContext compareContext) { + if (param != null && !param.trim().isEmpty()) { + try { + this.percentageTolerance = Double.parseDouble( + Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + } catch (Exception e) { + // Keep default tolerance if parameter is invalid + } + } + } +} +``` + +### Integration Steps + +1. **Create the Matcher Class**: Implement one of the matcher interfaces in the `org.testtools.jsondiff.matcher` package. + +2. **Follow Naming Convention**: Your class name must end with `Matcher` (e.g., `DateStringMatcher`, `RangePercentageMatcher`). + +3. **Implement Required Methods**: + - `equal(T actual, T expected)`: Basic comparison method + - `matcherInit(String param, CompareContext compareContext)`: Initialization method called by the framework + - For `CustomValueMatcher`: Implement `equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator)` + +4. **Use in YAML Configuration**: Reference your matcher by name (without the "Matcher" suffix): + +```yaml +- subRule: + jsonPath: "$.dates" + customRules: + - name: DateString + jsonPath: "**.date" + param: "yyyy-MM-dd" + - name: RangePercentage + jsonPath: "**.score" + param: "tolerance=10.0" +``` + +### Best Practices + +1. **Parameter Validation**: Always validate parameters in `matcherInit()` method and provide sensible defaults. + +2. **Error Handling**: Implement proper error handling and fallback behavior for invalid inputs. + +3. **Performance**: Keep matcher logic efficient, especially for large JSON documents. + +4. **Documentation**: Provide clear documentation for your matcher's behavior and parameter format. + +5. **Testing**: Create comprehensive tests for your custom matcher to ensure reliability. + +### Framework Integration + +The framework automatically discovers and instantiates your matcher class using reflection. The class must: +- Be in the `org.testtools.jsondiff.matcher` package +- Have a public default constructor +- Follow the naming convention: `{YourMatcherName}Matcher` +- Implement the required interface methods + +Your custom matcher will be automatically available for use in YAML configuration files without any additional registration steps. + diff --git a/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java b/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java index 775c87f1..98dac2cc 100644 --- a/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java +++ b/src/main/java/org/testtools/jsondiff/CompareMatcherItem.java @@ -1,27 +1,22 @@ package org.testtools.jsondiff; -import java.util.Map; - public class CompareMatcherItem { private String name; private String jsonPath; private String param; - private Map pararms; - //创建构造函数 public CompareMatcherItem(String name, String jsonPath, String param) { this.name = name; this.jsonPath = jsonPath; this.param = param; } - // Getter and Setter for path public String getJsonPath() { return jsonPath; } - public void setJsonPath(String path) { - this.jsonPath = path; + public void setJsonPath(String jsonPath) { + this.jsonPath = jsonPath; } public String getName() { @@ -33,7 +28,7 @@ public void setName(String name) { } public String getParam() { - return this.param; + return param; } public void setParam(String param) { diff --git a/src/main/java/org/testtools/jsondiff/CompareRule.java b/src/main/java/org/testtools/jsondiff/CompareRule.java index 1e66ba1c..1a3b9596 100644 --- a/src/main/java/org/testtools/jsondiff/CompareRule.java +++ b/src/main/java/org/testtools/jsondiff/CompareRule.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; - +import java.util.ArrayList; public class CompareRule { private final CompareContext compareContext; @@ -14,41 +14,77 @@ public class CompareRule { private List preProcesses; private List customRules; - public CompareRule(Map rule) { - // Default constructor - this.jsonPath = (String) rule.get(Param.JSON_PATH_KEY); - boolean extensible = (Boolean) rule.get(Param.EXTENSIBLE_KEY); - boolean strictOrder = (Boolean) rule.get(Param.STRICT_ORDER); - boolean fastFail = (Boolean) rule.get(Param.FAST_FAIL_KEY); - boolean ignoreNull = (Boolean) rule.get(Param.IGNORE_NULL_KEY); + // Handle jsonPath with null safety + Object jsonPathObj = rule.get(Param.JSON_PATH_KEY); + this.jsonPath = jsonPathObj != null ? String.valueOf(jsonPathObj) : null; + + // Provide default values for Boolean fields to prevent NullPointerException + boolean extensible = getBooleanValue(rule, Param.EXTENSIBLE_KEY, true); + boolean strictOrder = getBooleanValue(rule, Param.STRICT_ORDER, true); + boolean fastFail = getBooleanValue(rule, Param.FAST_FAIL_KEY, false); + boolean ignoreNull = getBooleanValue(rule, Param.IGNORE_NULL_KEY, false); + this.compareContext = new CompareContext(extensible, strictOrder, ignoreNull, fastFail); -// Map preProcess = (Map) rule.get(Param.PRE_PROCESS_KEY); List> customRulesMaps = (List>) rule.get(Param.CUSTOM_RULES_KEY); - //conver customRulesMap to CompareMatcherItem - this.customRules = customRulesMaps.stream() - .map(ruleMap -> { - return new CompareMatcherItem((String) ruleMap.get(Param.NAME_KEY), - (String) ruleMap.get(Param.JSON_PATH_KEY), - (String) ruleMap.get(Param.PARAM_KEY)); - }) - .collect(Collectors.toList()); + // Convert customRulesMap to CompareMatcherItem + if (customRulesMaps != null) { + this.customRules = customRulesMaps.stream() + .map(ruleMap -> new CompareMatcherItem( + getStringValue(ruleMap, Param.NAME_KEY, ""), + getStringValue(ruleMap, Param.JSON_PATH_KEY, ""), + getStringValue(ruleMap, Param.PARAM_KEY, ""))) + .collect(Collectors.toList()); + } else { + this.customRules = new ArrayList<>(); + } + } + + /** + * Safely extracts a Boolean value from a map with a default fallback. + * + * @param map the map to extract from + * @param key the key to look for + * @param defaultValue the default value if the key is not found or value is null + * @return the Boolean value or the default value + */ + private boolean getBooleanValue(Map map, String key, boolean defaultValue) { + Object value = map.get(key); + if (value instanceof Boolean) { + return (Boolean) value; + } + return defaultValue; + } + + /** + * Safely extracts a String value from a map with a default fallback. + * + * @param map the map to extract from + * @param key the key to look for + * @param defaultValue the default value if the key is not found or value is null + * @return the String value or the default value + */ + private String getStringValue(Map map, String key, String defaultValue) { + Object value = map.get(key); + if (value instanceof String) { + return (String) value; + } + return defaultValue; } public CompareContext getCompareContext() { - return this.compareContext; + return compareContext; } public String getJsonPath() { - return this.jsonPath; + return jsonPath; } public void setJsonPath(String jsonPath) { this.jsonPath = jsonPath; } - // Getter and Setter for preProcesses public List getPreProcesses() { return preProcesses; } @@ -57,7 +93,6 @@ public void setPreProcesses(List preProcesses) { this.preProcesses = preProcesses; } - // Getter and Setter for customRules public List getCustomRules() { return customRules; } diff --git a/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java b/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java index 34fb7792..eda448f5 100644 --- a/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java +++ b/src/main/java/org/testtools/jsondiff/CompareRulesTransformer.java @@ -25,59 +25,263 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; - +/** + * Transformer for converting comparison rules to comparators. + * Provides utility methods for creating CustomComparator instances from various rule formats. + */ public final class CompareRulesTransformer { + + private static final Logger LOGGER = Logger.getLogger(CompareRulesTransformer.class.getName()); + private static final String MATCHER_PACKAGE = "org.testtools.jsondiff.matcher."; + private static final String MATCHER_SUFFIX = "Matcher"; + private static final String MATCHER_INIT_METHOD = "matcherInit"; + + // Cache for reflection operations to improve performance + private static final ConcurrentHashMap> CLASS_CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap METHOD_CACHE = new ConcurrentHashMap<>(); + + // Reusable ObjectMapper instance + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private CompareRulesTransformer() { + // Utility class, prevent instantiation } + /** + * Converts a JSON string representation of comparison rules to a CompareRules object. + * + * @param rulesInJsonStr JSON string containing comparison rules + * @return CompareRules object, or empty CompareRules if parsing fails + * @throws IllegalArgumentException if rulesInJsonStr is null + */ public static CompareRules stringToCompareRules(final String rulesInJsonStr) { - final ObjectMapper mapper = new ObjectMapper(); + if (rulesInJsonStr == null) { + throw new IllegalArgumentException("Rules JSON string cannot be null"); + } + try { - return mapper.readValue(rulesInJsonStr, CompareRules.class); + return OBJECT_MAPPER.readValue(rulesInJsonStr, CompareRules.class); } catch (final JsonProcessingException e) { - e.printStackTrace(); + LOGGER.log(Level.WARNING, "Failed to parse rules JSON string: {0}", e.getMessage()); return new CompareRules(); } } - public static CustomComparator getComparator(final CompareRule compareRule) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { - final List customizations = getCustomizationsRe(compareRule); - final int size = customizations.size(); - return new CustomComparator(compareRule.getCompareContext(), - customizations.toArray(new Customization[size])); - + /** + * Creates a CustomComparator from a CompareRule. + * + * @param compareRule the comparison rule to convert + * @return CustomComparator instance + * @throws IllegalArgumentException if compareRule is null + * @throws RuntimeException if comparator creation fails + */ + public static CustomComparator getComparator(final CompareRule compareRule) { + if (compareRule == null) { + throw new IllegalArgumentException("CompareRule cannot be null"); + } + + try { + final List customizations = getCustomizations(compareRule); + return new CustomComparator(compareRule.getCompareContext(), + customizations.toArray(new Customization[0])); + } catch (Exception e) { + throw new RuntimeException("Failed to create comparator from CompareRule", e); + } } + /** + * Creates a CustomComparator from a JSON string representation of comparison rules. + * + * @param compareRules JSON string containing comparison rules + * @return CustomComparator instance + * @throws IllegalArgumentException if compareRules is null or empty + * @throws RuntimeException if comparator creation fails + */ public static CustomComparator getComparator(final String compareRules) { - return getComparator(String.valueOf(stringToCompareRules(compareRules).getCustomRules().get(0))); + if (compareRules == null || compareRules.trim().isEmpty()) { + throw new IllegalArgumentException("Compare rules string cannot be null or empty"); + } + + try { + CompareRules rules = stringToCompareRules(compareRules); + List customRules = rules.getCustomRules(); + + if (customRules.isEmpty()) { + // If no custom rules, create a default comparator + CompareContext defaultContext = new CompareContext(true, true, false, false); + return new CustomComparator(defaultContext); + } + + // Convert the first custom rule to a CompareRule format + return getComparator(convertToCompareRule(customRules.get(0))); + } catch (Exception e) { + throw new RuntimeException("Failed to create comparator from rules string", e); + } } - private static List getCustomizationsRe(final CompareRule compareRule) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - CompareContext compareContext = compareRule.getCompareContext(); - List customRules = compareRule.getCustomRules(); - - final List customizationList = new ArrayList(); - for (CompareMatcherItem rule : customRules) { - //根据获取到类,调用构造函数 - String path = rule.getJsonPath(); - String param = rule.getParam(); - String ruleName = rule.getName(); - String matchClassName = ruleName + "Matcher"; - //使用反射从ruleName获取到实际的matcher类,ruleName为类名称,matcher的package为com.nezha.jsondiff.matcher - Class clazz = Class.forName("com.nezha.jsondiff.matcher." + matchClassName); - Constructor constructor = clazz.getConstructor(); + /** + * Converts a CompareRule to a list of Customization objects. + * + * @param compareRule the comparison rule to convert + * @return List of Customization objects + * @throws ClassNotFoundException if matcher class cannot be found + * @throws NoSuchMethodException if matcherInit method cannot be found + * @throws InvocationTargetException if matcherInit method invocation fails + * @throws InstantiationException if matcher instantiation fails + * @throws IllegalAccessException if matcher method access is denied + */ + private static List getCustomizations(final CompareRule compareRule) + throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + InstantiationException, IllegalAccessException { + + if (compareRule.getCustomRules() == null || compareRule.getCustomRules().isEmpty()) { + return new ArrayList<>(); + } + + final List customizationList = new ArrayList<>(); + final CompareContext compareContext = compareRule.getCompareContext(); + + for (CompareMatcherItem rule : compareRule.getCustomRules()) { + try { + ValueMatcher matcher = createMatcher(rule, compareContext); + customizationList.add(new Customization(rule.getJsonPath(), matcher)); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Failed to create matcher for rule {0}: {1}", + new Object[]{rule.getName(), e.getMessage()}); + // Continue with other rules instead of failing completely + } + } + + return customizationList; + } - Object matcher = constructor.newInstance(); - // 调用matcherInit方法 - Method matcherInitMethod = clazz.getMethod("matcherInit", String.class, CompareContext.class); - matcherInitMethod.invoke(matcher, param, compareContext); - // 将matcher添加到customizationList中 - customizationList.add(new Customization(path, (ValueMatcher) matcher)); + /** + * Creates a ValueMatcher instance for the given rule. + * + * @param rule the matcher rule + * @param compareContext the comparison context + * @return ValueMatcher instance + * @throws ClassNotFoundException if matcher class cannot be found + * @throws NoSuchMethodException if matcherInit method cannot be found + * @throws InvocationTargetException if matcherInit method invocation fails + * @throws InstantiationException if matcher instantiation fails + * @throws IllegalAccessException if matcher method access is denied + */ + private static ValueMatcher createMatcher(CompareMatcherItem rule, CompareContext compareContext) + throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + InstantiationException, IllegalAccessException { + + String ruleName = rule.getName(); + String param = rule.getParam(); + + if (ruleName == null || ruleName.trim().isEmpty()) { + throw new IllegalArgumentException("Rule name cannot be null or empty"); + } + + // Ensure param is not null + if (param == null) { + param = ""; + } + + String matcherClassName = MATCHER_PACKAGE + ruleName + MATCHER_SUFFIX; + + // Get or create class from cache + Class clazz = CLASS_CACHE.computeIfAbsent(matcherClassName, className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Matcher class not found: " + className, e); + } + }); + + // Get or create constructor from cache + Constructor constructor = CONSTRUCTOR_CACHE.computeIfAbsent(matcherClassName, className -> { + try { + return clazz.getConstructor(); + } catch (NoSuchMethodException e) { + throw new RuntimeException("No default constructor found for: " + className, e); + } + }); + + // Create matcher instance + Object matcher = constructor.newInstance(); + + // Get or create matcherInit method from cache + Method matcherInitMethod = METHOD_CACHE.computeIfAbsent(matcherClassName, className -> { + try { + return clazz.getMethod(MATCHER_INIT_METHOD, String.class, CompareContext.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException("matcherInit method not found for: " + className, e); + } + }); + + // Initialize matcher + matcherInitMethod.invoke(matcher, param, compareContext); + + return (ValueMatcher) matcher; + } + /** + * Converts a CustomCompareRule to a CompareRule. + * This method creates a CompareRule with default context and converts the matcher array + * to CompareMatcherItem objects. + * + * @param customRule the custom compare rule to convert + * @return CompareRule instance + */ + private static CompareRule convertToCompareRule(CustomCompareRule customRule) { + if (customRule == null) { + throw new IllegalArgumentException("CustomCompareRule cannot be null"); } - return customizationList; + + // Create a default CompareContext + CompareContext compareContext = new CompareContext(true, true, false, false); + + // Convert matcher array to CompareMatcherItem list + List compareMatcherItems = new ArrayList<>(); + if (customRule.getMatcher() != null) { + for (String matcherName : customRule.getMatcher()) { + if (matcherName != null && !matcherName.trim().isEmpty()) { + // Create a CompareMatcherItem with the matcher name as the rule name + // and the path from the custom rule + CompareMatcherItem item = new CompareMatcherItem( + matcherName.trim(), + customRule.getPath(), + "" // Default empty parameter + ); + compareMatcherItems.add(item); + } + } + } + + // Create a temporary map to simulate the rule structure + // This is a workaround since CompareRule constructor expects a Map + // In a real implementation, you might want to add a constructor to CompareRule + // that accepts individual parameters + java.util.Map ruleMap = new java.util.HashMap<>(); + ruleMap.put(org.testtools.jsondiff.constant.Param.JSON_PATH_KEY, customRule.getPath()); + ruleMap.put(org.testtools.jsondiff.constant.Param.EXTENSIBLE_KEY, true); + ruleMap.put(org.testtools.jsondiff.constant.Param.STRICT_ORDER, true); + ruleMap.put(org.testtools.jsondiff.constant.Param.FAST_FAIL_KEY, false); + ruleMap.put(org.testtools.jsondiff.constant.Param.IGNORE_NULL_KEY, false); + + // Convert CompareMatcherItems to the format expected by CompareRule constructor + List> customRulesMaps = new ArrayList<>(); + for (CompareMatcherItem item : compareMatcherItems) { + java.util.Map ruleItemMap = new java.util.HashMap<>(); + ruleItemMap.put(org.testtools.jsondiff.constant.Param.NAME_KEY, item.getName()); + ruleItemMap.put(org.testtools.jsondiff.constant.Param.JSON_PATH_KEY, item.getJsonPath()); + ruleItemMap.put(org.testtools.jsondiff.constant.Param.PARAM_KEY, item.getParam()); + customRulesMaps.add(ruleItemMap); + } + ruleMap.put(org.testtools.jsondiff.constant.Param.CUSTOM_RULES_KEY, customRulesMaps); + + return new CompareRule(ruleMap); } } diff --git a/src/main/java/org/testtools/jsondiff/JSONCompareConf.java b/src/main/java/org/testtools/jsondiff/JSONCompareConf.java index ba786e53..6405f7ac 100644 --- a/src/main/java/org/testtools/jsondiff/JSONCompareConf.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompareConf.java @@ -20,77 +20,95 @@ import java.util.List; import java.util.Map; +/** + * Configuration class for JSON comparison rules loaded from YAML. + * Handles parsing YAML configuration and converting it to CompareRule objects. + */ public class JSONCompareConf { - List> yamlData = new ArrayList>(); - List compareRules = new ArrayList(); - - private static void processSubRule(Map subRule) { - String forPath = (String) subRule.get("forPath"); - String type = (String) subRule.get("type"); - List> customRules = (List>) subRule.get("customRules"); - Map preProcess = (Map) subRule.get("preProcess"); - Map postProcess = (Map) subRule.get("postProcess"); - - System.out.println("forPath: " + forPath); - System.out.println("type: " + type); - - System.out.println("Custom Rules:"); - for (Map rule : customRules) { - for (Map.Entry entry : rule.entrySet()) { - System.out.println(" Rule Type: " + entry.getKey()); - Map ruleDetails = (Map) entry.getValue(); - for (Map.Entry detail : ruleDetails.entrySet()) { - System.out.println(" " + detail.getKey() + ": " + detail.getValue()); - } - } - } - - System.out.println("Pre Process:"); - for (Map.Entry entry : preProcess.entrySet()) { - System.out.println(" " + entry.getKey() + ": " + entry.getValue()); - } - - System.out.println("Post Process:"); - for (Map.Entry entry : postProcess.entrySet()) { - System.out.println(" " + entry.getKey() + ": " + entry.getValue()); - } - } - + + private final List> yamlData = new ArrayList<>(); + private final List compareRules = new ArrayList<>(); + + /** + * Gets the parsed YAML data. + * + * @return List of parsed YAML data as maps + */ public List> getYamlData() { - return yamlData; + return new ArrayList<>(yamlData); } - public void readNodeFromYaml(String yamlString) throws Exception { - // 验证 YAML 字符串是否为空 - if (yamlString == null || yamlString.trim().isEmpty()) { - throw new IllegalArgumentException("YAML string cannot be null or empty"); - } + /** + * Gets the converted comparison rules. + * + * @return List of CompareRule objects + */ + public List getCompareRules() { + return new ArrayList<>(compareRules); + } + /** + * Reads and parses YAML configuration from a string. + * + * @param yamlString The YAML configuration string + * @throws IllegalArgumentException if the YAML string is null or empty + * @throws RuntimeException if YAML parsing fails + */ + public void readNodeFromYaml(String yamlString) { + validateYamlString(yamlString); + try { Yaml yaml = new Yaml(); - this.yamlData = yaml.load(yamlString); - for (Map rule : this.yamlData) { - if (rule.containsKey("subRule")) { - Map subRule = (Map) rule.get("subRule"); - compareRules.add(new CompareRule(subRule)); - } - + List> parsedData = yaml.load(yamlString); + + if (parsedData == null) { + throw new RuntimeException("YAML parsing resulted in null data"); } - + + yamlData.clear(); + yamlData.addAll(parsedData); + + convertToCompareRules(); + } catch (Exception e) { - throw new Exception("Failed to parse or process YAML string", e); + throw new RuntimeException("Failed to parse or process YAML string", e); } } - public void convertToCompareMatcher() { + /** + * Converts YAML data to CompareRule objects. + * This method processes both direct rules and sub-rules. + */ + public void convertToCompareRules() { + compareRules.clear(); + for (Map rule : yamlData) { - compareRules.add(new CompareRule(rule)); + if (rule == null) { + continue; + } + + // Handle sub-rule case + if (rule.containsKey("subRule")) { + Map subRule = (Map) rule.get("subRule"); + if (subRule != null) { + compareRules.add(new CompareRule(subRule)); + } + } else { + // Handle direct rule case + compareRules.add(new CompareRule(rule)); + } } } - public List getCompareRules() { - return compareRules; + /** + * Validates that the YAML string is not null or empty. + * + * @param yamlString The YAML string to validate + * @throws IllegalArgumentException if the string is null or empty + */ + private void validateYamlString(String yamlString) { + if (yamlString == null || yamlString.trim().isEmpty()) { + throw new IllegalArgumentException("YAML string cannot be null or empty"); + } } - - } diff --git a/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java index 6fd276d1..c42eb736 100644 --- a/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/CustomValueMatcher.java @@ -14,44 +14,44 @@ * limitations under the License. */ -package org.testtools.jsondiff.matcher; + package org.testtools.jsondiff.matcher; -import org.testtools.jsondiff.JSONCompareDetailResult; -import org.testtools.jsondiff.comparator.JSONComparator; - -/** - * Function: - * - */ -public interface CustomValueMatcher extends ValueMatcher { - /** - * Match actual value with expected value. If match fails any of the - * following may occur, return false, pass failure details to specified - * JSONCompareDetailResult and return true, or throw ValueMatcherException - * containing failure details. Passing failure details to JSONCompareDetailResult - * or returning via ValueMatcherException enables more useful failure - * description for cases where expected value depends entirely or in part on - * configuration of the ValueMatcher and therefore expected value passed to - * this method will not give a useful indication of expected value. - * - * @param prefix - * JSON path of the JSON item being tested - * @param actual - * JSON value being tested - * @param expected - * expected JSON value - * @param result - * JSONCompareDetailResult to which match failure may be passed - * @param comparator - * JSONComparator use to compare elements - * @return true if expected and actual equal or any difference has already - * been passed to specified result instance, false otherwise. - * @throws ValueMatcherException - * if expected and actual values not equal and ValueMatcher - * needs to override default comparison failure message that - * would be generated if this method returned false. - */ - boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, - JSONComparator comparator) throws ValueMatcherException; - -} + import org.testtools.jsondiff.JSONCompareDetailResult; + import org.testtools.jsondiff.comparator.JSONComparator; + + /** + * Function: + * + */ + public interface CustomValueMatcher extends ValueMatcher { + /** + * Match actual value with expected value. If match fails any of the + * following may occur, return false, pass failure details to specified + * JSONCompareDetailResult and return true, or throw ValueMatcherException + * containing failure details. Passing failure details to JSONCompareDetailResult + * or returning via ValueMatcherException enables more useful failure + * description for cases where expected value depends entirely or in part on + * configuration of the ValueMatcher and therefore expected value passed to + * this method will not give a useful indication of expected value. + * + * @param prefix + * JSON path of the JSON item being tested + * @param actual + * JSON value being tested + * @param expected + * expected JSON value + * @param result + * JSONCompareDetailResult to which match failure may be passed + * @param comparator + * JSONComparator use to compare elements + * @return true if expected and actual equal or any difference has already + * been passed to specified result instance, false otherwise. + * @throws ValueMatcherException + * if expected and actual values not equal and ValueMatcher + * needs to override default comparison failure message that + * would be generated if this method returned false. + */ + boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, + JSONComparator comparator) throws ValueMatcherException; + + } \ No newline at end of file diff --git a/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java index b65e200c..90a2b698 100644 --- a/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/TolerantValueMatcher.java @@ -43,9 +43,9 @@ public boolean equal(T actual, T expected){ return actual.equals(expected); } } + @Override - public void matcherInit(String param, CompareContext compareContext) {tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); + public void matcherInit(String param, CompareContext compareContext) { tolerance = Double.parseDouble(Objects.requireNonNull(JSONCompareUtil.getParamValue(param))); - } } diff --git a/src/test/java/jsondiff/CompareRulesTransformerTest.java b/src/test/java/jsondiff/CompareRulesTransformerTest.java new file mode 100644 index 00000000..338a8ba2 --- /dev/null +++ b/src/test/java/jsondiff/CompareRulesTransformerTest.java @@ -0,0 +1,104 @@ +package jsondiff; + +import org.junit.Test; +import org.testtools.jsondiff.CompareRule; +import org.testtools.jsondiff.CompareRules; +import org.testtools.jsondiff.CompareRulesTransformer; +import org.testtools.jsondiff.comparator.CustomComparator; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * Test class for CompareRulesTransformer optimizations + */ +public class CompareRulesTransformerTest { + + @Test + public void testStringToCompareRulesWithNullInput() { + try { + CompareRulesTransformer.stringToCompareRules(null); + fail("Should throw IllegalArgumentException for null input"); + } catch (IllegalArgumentException e) { + assertEquals("Rules JSON string cannot be null", e.getMessage()); + } + } + + @Test + public void testGetComparatorWithNullCompareRule() { + try { + CompareRulesTransformer.getComparator((CompareRule) null); + fail("Should throw IllegalArgumentException for null CompareRule"); + } catch (IllegalArgumentException e) { + assertEquals("CompareRule cannot be null", e.getMessage()); + } + } + + @Test + public void testGetComparatorWithNullString() { + try { + CompareRulesTransformer.getComparator((String) null); + fail("Should throw IllegalArgumentException for null string"); + } catch (IllegalArgumentException e) { + assertEquals("Compare rules string cannot be null or empty", e.getMessage()); + } + } + + @Test + public void testGetComparatorWithEmptyString() { + try { + CompareRulesTransformer.getComparator(""); + fail("Should throw IllegalArgumentException for empty string"); + } catch (IllegalArgumentException e) { + assertEquals("Compare rules string cannot be null or empty", e.getMessage()); + } + } + + @Test + public void testCompareRuleWithMissingBooleanFields() { + // Test that CompareRule can handle missing Boolean fields without throwing NullPointerException + Map ruleMap = new HashMap<>(); + ruleMap.put("jsonPath", "$.test"); + // Don't add Boolean fields to test default values + + try { + CompareRule rule = new CompareRule(ruleMap); + assertNotNull("CompareRule should be created successfully", rule); + assertNotNull("CompareContext should be created", rule.getCompareContext()); + assertEquals("jsonPath should be set correctly", "$.test", rule.getJsonPath()); + } catch (Exception e) { + fail("CompareRule creation should not throw exception: " + e.getMessage()); + } + } + + @Test + public void testCompareRuleWithNullCustomRules() { + // Test that CompareRule can handle null customRules + Map ruleMap = new HashMap<>(); + ruleMap.put("jsonPath", "$.test"); + ruleMap.put("extensible", true); + ruleMap.put("strictOrder", true); + ruleMap.put("fastFail", false); + ruleMap.put("ignoreNull", false); + // Don't add customRules to test null handling + + try { + CompareRule rule = new CompareRule(ruleMap); + assertNotNull("CompareRule should be created successfully", rule); + assertNotNull("customRules should be initialized as empty list", rule.getCustomRules()); + assertTrue("customRules should be empty", rule.getCustomRules().isEmpty()); + } catch (Exception e) { + fail("CompareRule creation should not throw exception: " + e.getMessage()); + } + } + + @Test + public void testStringToCompareRulesWithInvalidJson() { + // Test that invalid JSON returns empty CompareRules instead of throwing exception + CompareRules result = CompareRulesTransformer.stringToCompareRules("invalid json"); + assertNotNull("Result should not be null", result); + assertNotNull("Custom rules should be initialized", result.getCustomRules()); + } +} \ No newline at end of file diff --git a/src/test/java/jsondiff/FileUtil.java b/src/test/java/jsondiff/FileUtil.java index 120871cb..9743dea4 100644 --- a/src/test/java/jsondiff/FileUtil.java +++ b/src/test/java/jsondiff/FileUtil.java @@ -26,9 +26,21 @@ public class FileUtil { public FileUtil() { } + /** + * 读取文件内容 + * @param fileName 文件路径,可以是相对路径或绝对路径 + * @return 文件内容字符串 + */ public static String readFile(String fileName) { try{ - String path = DIR_PATH + fileName; + String path; + // 如果是绝对路径,直接使用;否则拼接工作目录 + if (new File(fileName).isAbsolute()) { + path = fileName; + } else { + path = DIR_PATH + fileName; + } + File file = new File(path); FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); @@ -44,9 +56,46 @@ public static String readFile(String fileName) { fr.close(); return sb.toString(); } catch (IOException e) { - e.printStackTrace();; + e.printStackTrace(); return null; } + } + + /** + * 获取文件的绝对路径 + * @param filePath 文件路径,可以是相对路径或绝对路径 + * @return 文件的绝对路径 + */ + public static String getAbsolutePath(String filePath) { + File file = new File(filePath); + if (file.isAbsolute()) { + return file.getAbsolutePath(); + } else { + return new File(DIR_PATH, filePath).getAbsolutePath(); + } + } + + /** + * 检查文件是否存在 + * @param filePath 文件路径 + * @return 如果文件存在返回true,否则返回false + */ + public static boolean fileExists(String filePath) { + String path; + if (new File(filePath).isAbsolute()) { + path = filePath; + } else { + path = DIR_PATH + filePath; + } + return new File(path).exists(); + } + /** + * 获取文件所在目录的绝对路径 + * @param filePath 文件路径 + * @return 文件所在目录的绝对路径 + */ + public static String getParentPath(String filePath) { + return new File(getAbsolutePath(filePath)).getParent(); } } diff --git a/src/test/java/jsondiff/JSONCompareYamlResultTest.java b/src/test/java/jsondiff/JSONCompareYamlResultTest.java index e5bea708..ae5541fa 100644 --- a/src/test/java/jsondiff/JSONCompareYamlResultTest.java +++ b/src/test/java/jsondiff/JSONCompareYamlResultTest.java @@ -1,5 +1,5 @@ /* - * ArrayObjectValueMatcherTest.java + * JSONCompareYamlResultTest.java * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -19,45 +19,164 @@ import org.testtools.jsondiff.JSONCompare; import org.testtools.jsondiff.JSONCompareResult; import org.junit.Test; +import org.junit.Before; +import org.junit.After; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertEquals; - +import static org.junit.Assert.*; +/** + * Unit test class for testing JSON comparison functionality + * Reads test cases from test resources folder, executes comparison and validates results + */ public class JSONCompareYamlResultTest { - private static final String TEST_PATH = "/src/test/resources/"; + private static final String TEST_RESOURCES_PATH = "src/test/resources/"; + private static final String OUTPUT_PATH = "testoutput/"; + private ObjectMapper objectMapper; - private void runTestCase(String caseNumber) throws Exception { - // Read the test file - String expectedJSON = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_a.json"); - String actualJSON = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_e.json"); - String rules = FileUtil.readFile(TEST_PATH + "rule_case" + caseNumber + ".yaml"); + @Before + public void setUp() { + objectMapper = new ObjectMapper(); + // Ensure output directory exists + createOutputDirectory(); + } + @After + public void tearDown() { + // Clean up test output files (optional) + // cleanupTestOutput(); + } + /** + * Run the specified test case + * @param caseNumber Test case number + * @throws Exception if test execution fails + */ + private void runTestCase(String caseNumber) throws Exception { + System.out.println("=== Starting test case execution: case_" + caseNumber + " ==="); + + // Build file paths + String expectedJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_a.json"; + String actualJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_e.json"; + String rulesPath = TEST_RESOURCES_PATH + "rule_case" + caseNumber + ".yaml"; + String expectedResultPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_result.json"; + String outputFilePath = OUTPUT_PATH + "case_" + caseNumber + "_diff.json"; + + // Validate test files exist + validateTestFiles(caseNumber, expectedJsonPath, actualJsonPath, rulesPath, expectedResultPath); + + // Read test data + String expectedJSON = readFileContent(expectedJsonPath); + String actualJSON = readFileContent(actualJsonPath); + String rules = readFileContent(rulesPath); + String expectedResult = readFileContent(expectedResultPath); + + System.out.println("Test data reading completed:"); + System.out.println("- Expected JSON file: " + expectedJsonPath); + System.out.println("- Actual JSON file: " + actualJsonPath); + System.out.println("- Rules file: " + rulesPath); + System.out.println("- Expected result file: " + expectedResultPath); + + // Execute JSON comparison + System.out.println("Starting JSON comparison..."); JSONCompareResult result = JSONCompare.compareJSONYaml(expectedJSON, actualJSON, rules); + + if (result == null) { + fail("JSON comparison returned null result"); + } - ObjectMapper objectMapper = new ObjectMapper(); + // Serialize comparison result String actualResult = objectMapper.writeValueAsString(result.getFailure()); - String outputFilePath = "./testoutput/case_" + caseNumber + "_diff.json"; + + // Write to output file writeToFile(outputFilePath, actualResult); - actualResult=FileUtil.readFile(outputFilePath); - System.out.println("case_" + caseNumber); + System.out.println("Comparison result written to: " + outputFilePath); + + // Output comparison results for debugging + System.out.println("Actual comparison result:"); System.out.println(actualResult); - String expectResult = FileUtil.readFile(TEST_PATH + "case_" + caseNumber + "_result.json"); + System.out.println("Expected comparison result:"); + System.out.println(expectedResult); + + // Validate results + assertEquals("Test case case_" + caseNumber + " comparison result does not match", + expectedResult.trim(), actualResult.trim()); + + System.out.println("=== Test case case_" + caseNumber + " executed successfully ===\n"); + } - assertEquals("case_" + caseNumber, actualResult,expectResult); + /** + * Validate test files exist + */ + private void validateTestFiles(String caseNumber, String... filePaths) { + for (String filePath : filePaths) { + // For test resource files, use classpath check + if (filePath.startsWith(TEST_RESOURCES_PATH)) { + String resourcePath = filePath.substring(TEST_RESOURCES_PATH.length()); + if (getClass().getClassLoader().getResource(resourcePath) == null) { + fail("Test resource file does not exist: " + resourcePath + " (test case: case_" + caseNumber + ")"); + } + } else { + // For other files, use FileUtil + if (!FileUtil.fileExists(filePath)) { + fail("Test file does not exist: " + filePath + " (test case: case_" + caseNumber + ")"); + } + } + } + } + /** + * Read file content + */ + private String readFileContent(String filePath) throws IOException { + // For test resource files, use classpath loading + if (filePath.startsWith(TEST_RESOURCES_PATH)) { + String resourcePath = filePath.substring(TEST_RESOURCES_PATH.length()); + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(resourcePath)) { + if (inputStream == null) { + throw new IOException("Cannot find resource file: " + resourcePath); + } + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } + } else { + // For other files, use FileUtil + String content = FileUtil.readFile(filePath); + if (content == null) { + throw new IOException("Cannot read file: " + filePath); + } + return content; + } } + /** + * Create output directory + */ + private void createOutputDirectory() { + File outputDir = new File(OUTPUT_PATH); + if (!outputDir.exists()) { + boolean created = outputDir.mkdirs(); + if (!created) { + System.err.println("Warning: Cannot create output directory: " + OUTPUT_PATH); + } + } + } + + /** + * Write to file + */ private void writeToFile(String filePath, String content) throws IOException { File file = new File(filePath); File parentDir = file.getParentFile(); if (parentDir != null && !parentDir.exists()) { - parentDir.mkdirs(); // Create all necessary parent directories + parentDir.mkdirs(); } try (FileWriter writer = new FileWriter(filePath)) { @@ -65,8 +184,68 @@ private void writeToFile(String filePath, String content) throws IOException { } } + /** + * Clean up test output files (optional) + */ + private void cleanupTestOutput() { + try { + File outputDir = new File(OUTPUT_PATH); + if (outputDir.exists()) { + Files.walk(Paths.get(OUTPUT_PATH)) + .filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith("_diff.json")) + .forEach(path -> { + try { + Files.delete(path); + } catch (IOException e) { + System.err.println("Cannot delete file: " + path); + } + }); + } + } catch (IOException e) { + System.err.println("Error cleaning up output files: " + e.getMessage()); + } + } + + /** + * Test case 01 + * Test basic JSON comparison functionality + */ @Test - public void TestCase() throws Exception { + public void testCase01() throws Exception { runTestCase("01"); } + + /** + * Test file reading functionality + */ + @Test + public void testFileReading() { + String testFilePath = TEST_RESOURCES_PATH + "case_01_a.json"; + // Use classpath to check test resource file + String resourcePath = testFilePath.substring(TEST_RESOURCES_PATH.length()); + assertTrue("Test file should exist", getClass().getClassLoader().getResource(resourcePath) != null); + + try { + String content = readFileContent(testFilePath); + assertNotNull("File content should not be null", content); + assertFalse("File content should not be empty", content.trim().isEmpty()); + } catch (IOException e) { + fail("Exception occurred while reading file: " + e.getMessage()); + } + } + + /** + * Test basic JSON comparison functionality + */ + @Test + public void testBasicJSONCompare() throws Exception { + String expectedJSON = "{\"name\":\"John\",\"age\":30}"; + String actualJSON = "{\"name\":\"John\",\"age\":30}"; + String rules = "[]"; + + JSONCompareResult result = JSONCompare.compareJSONYaml(expectedJSON, actualJSON, rules); + assertNotNull("Comparison result should not be null", result); + assertTrue("Identical JSON should compare successfully", result.getFailure().isEmpty()); + } } diff --git a/src/test/resources/rule_case01.yaml b/src/test/resources/rule_case01.yaml index e0a68f07..8abf5910 100644 --- a/src/test/resources/rule_case01.yaml +++ b/src/test/resources/rule_case01.yaml @@ -1,41 +1,59 @@ # you can define multiple subRule - subRule: + # JSONPath expression to specify which part of the JSON to apply this rule to jsonPath: $.user + # Whether the target JSON can have additional fields not present in the expected JSON extensible: true + # Whether arrays should be compared in strict order (true) or allow reordering (false) strictOrder: true + # Whether to ignore null values during comparison ignoreNull: true + # Whether to stop comparison immediately when first difference is found fastFail: false preProcess: # TODO + # Remove specific nodes from JSON before comparison removeNode: jsonPath: "" + # Escape special characters in JSON values escape: jsonPath: "" + # Custom comparison rules to apply to this JSONPath customRules: + # Apply number precision comparison to all age fields (3 decimal places, rounding mode 3) - name: NumberPrecise jsonPath: "**.age" param: "newScale=3,roundingMode=3" + # Compare arrays using a specific key field for matching elements - name: ArrayWithKey jsonPath: "$" param: "key=id" + # Ignore specific paths during comparison - name: IngorePath # which path will be ignored param: "user.queryTimestamp" + # Allow array elements to be in any order - name: ArrayDisorder jsonPath: "**.ordersWithoutOrder" + # Recursively compare array elements - name: ArrayRecursively jsonPath: param: + # Compare degree values with specified tolerance - name: DegreePrecise jsonPath: param: "tolerance=10e-1" + # Compare radian values with specified tolerance - name: RadianPrecise jsonPath: param: "tolerance=10e-4" + # Compare values with tolerance for floating point differences - name: TolerantValue jsonPath: "" param: "tolerance=10e-4" + # Compare values with percentage-based tolerance - name: PercentTolerant jsonPath: "" param: "tolerance=10e-4" + # Compare position values with tolerance (e.g., {"position": "-300.0,-250.0"}) - name: ImprecisePosition #eg: {"position": "-300.0,-250.0"} jsonPath: "" param: "tolerance=0.01;separator=," From cb7580f565b7f1cb424ec799765867eb336adc1d Mon Sep 17 00:00:00 2001 From: liuge Date: Sat, 19 Jul 2025 22:37:50 +0800 Subject: [PATCH 14/18] fix bug and translate to English --- README.md | 5 +- .../org/testtools/jsondiff/JSONCompare.java | 126 +++---- .../testtools/jsondiff/PreProcessItem.java | 13 + .../jsondiff/matcher/EscapedJsonMatcher.java | 1 - .../jsondiff/matcher/IngorePathMatcher.java | 2 +- src/site/resources/CNAME | 2 - src/site/resources/cookbook.html | 137 -------- src/site/resources/css/style.css | 317 ------------------ src/site/resources/index.html | 130 ------- src/site/resources/quickstart.html | 83 ----- src/test/java/jsondiff/FileUtil.java | 31 +- .../jsondiff/JSONCompareYamlResultTest.java | 17 +- src/test/resources/case_01_result.json | 2 +- src/test/resources/rule_case01.yaml | 7 +- testoutput/case_01_diff.json | 1 + 15 files changed, 94 insertions(+), 780 deletions(-) delete mode 100644 src/site/resources/CNAME delete mode 100644 src/site/resources/cookbook.html delete mode 100644 src/site/resources/css/style.css delete mode 100644 src/site/resources/index.html delete mode 100644 src/site/resources/quickstart.html create mode 100644 testoutput/case_01_diff.json diff --git a/README.md b/README.md index 31ca4006..8cf8bc0e 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,6 @@ The following example demonstrates how to configure a subRule for comparing JSON # Remove specific nodes from JSON before comparison removeNode: jsonPath: "" - # Escape special characters in JSON values - escape: - jsonPath: "" # Custom comparison rules to apply to this JSONPath customRules: # Apply number precision comparison to all age fields (3 decimal places, rounding mode 3) @@ -80,7 +77,7 @@ The following example demonstrates how to configure a subRule for comparing JSON - **strictOrder**: When `true`, arrays must be in the exact same order; when `false`, array elements can be reordered - **ignoreNull**: When `true`, null values are ignored during comparison - **fastFail**: When `true`, comparison stops immediately when the first difference is found -- **preProcess**: Pre-processing options for removing nodes or escaping characters before comparison +- **preProcess**: Pre-processing options for removing nodes before comparison - **customRules**: Array of custom comparison rules with specific behaviors: - **NumberPrecise**: Compares numbers with specified precision and rounding mode - **ArrayWithKey**: Compares arrays using a specific key field for element matching diff --git a/src/main/java/org/testtools/jsondiff/JSONCompare.java b/src/main/java/org/testtools/jsondiff/JSONCompare.java index b2ffc821..019efa41 100644 --- a/src/main/java/org/testtools/jsondiff/JSONCompare.java +++ b/src/main/java/org/testtools/jsondiff/JSONCompare.java @@ -20,6 +20,7 @@ import org.testtools.jsondiff.comparator.CustomComparator; import org.testtools.jsondiff.comparator.DefaultComparator; import org.testtools.jsondiff.comparator.JSONComparator; +import org.apache.commons.lang.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -28,9 +29,7 @@ import java.util.List; /** - * Provides API to compare two JSON entities. but it can - * be programmed against directly to access the functionality. (eg, to make something that works with a - * non-JUnit test framework) + * Provides API to compare two JSON entities using YAML configuration. */ public final class JSONCompare { private JSONCompare() { @@ -51,16 +50,16 @@ private static JSONComparator getComparatorForMode(CompareContext mode) { * @throws JSONException JSON parsing error * @throws IllegalArgumentException when type of expectedStr doesn't match the type of actualStr */ - public static JSONCompareDetailResult compareJSON(String expectedStr, String actualStr, JSONComparator comparator) + public static JSONCompareDetailResult compareJSONInternal(String expectedStr, String actualStr, JSONComparator comparator) throws JSONException { Object expected = JSONParser.parseJSON(expectedStr); Object actual = JSONParser.parseJSON(actualStr); if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { - return compareJSON((JSONObject) expected, (JSONObject) actual, comparator); + return compareJSONInternal((JSONObject) expected, (JSONObject) actual, comparator); } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { - return compareJSON((JSONArray) expected, (JSONArray) actual, comparator); + return compareJSONInternal((JSONArray) expected, (JSONArray) actual, comparator); } else if (expected instanceof JSONString && actual instanceof JSONString) { - return compareJson((JSONString) expected, (JSONString) actual); + return compareJSONInternal((JSONString) expected, (JSONString) actual); } else if (expected instanceof JSONObject) { return new JSONCompareDetailResult().fail("", expected, actual); } else { @@ -78,7 +77,7 @@ public static JSONCompareDetailResult compareJSON(String expectedStr, String act * @return result of the comparison * @throws JSONException JSON parsing error */ - public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual, JSONComparator comparator) + public static JSONCompareDetailResult compareJSONInternal(JSONObject expected, JSONObject actual, JSONComparator comparator) throws JSONException { return comparator.compareJSON(expected, actual); } @@ -93,7 +92,7 @@ public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObjec * @return result of the comparison * @throws JSONException JSON parsing error */ - public static JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual, JSONComparator comparator) + public static JSONCompareDetailResult compareJSONInternal(JSONArray expected, JSONArray actual, JSONComparator comparator) throws JSONException { return comparator.compareJSON(expected, actual); } @@ -106,7 +105,7 @@ public static JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray * @param actual {@code JSONstring} to compare * @return result of the comparison */ - public static JSONCompareDetailResult compareJson(final JSONString expected, final JSONString actual) { + public static JSONCompareDetailResult compareJSONInternal(final JSONString expected, final JSONString actual) { final JSONCompareDetailResult result = new JSONCompareDetailResult(); final String expectedJson = expected.toJSONString(); final String actualJson = actual.toJSONString(); @@ -125,9 +124,9 @@ public static JSONCompareDetailResult compareJson(final JSONString expected, fin * @return result of the comparison * @throws JSONException JSON parsing error */ - public static JSONCompareDetailResult compareJSON(String expectedStr, String actualStr, CompareContext mode) + public static JSONCompareDetailResult compareJSONInternal(String expectedStr, String actualStr, CompareContext mode) throws JSONException { - return compareJSON(expectedStr, actualStr, getComparatorForMode(mode)); + return compareJSONInternal(expectedStr, actualStr, getComparatorForMode(mode)); } /** @@ -139,12 +138,11 @@ public static JSONCompareDetailResult compareJSON(String expectedStr, String act * @return result of the comparison * @throws JSONException JSON parsing error */ - public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObject actual, CompareContext mode) + public static JSONCompareDetailResult compareJSONInternal(JSONObject expected, JSONObject actual, CompareContext mode) throws JSONException { - return compareJSON(expected, actual, getComparatorForMode(mode)); + return compareJSONInternal(expected, actual, getComparatorForMode(mode)); } - /** * Compares JSONArray provided to the expected JSONArray, and returns the results of the comparison. * @@ -154,41 +152,32 @@ public static JSONCompareDetailResult compareJSON(JSONObject expected, JSONObjec * @return result of the comparison * @throws JSONException JSON parsing error */ - public static JSONCompareDetailResult compareJSON(JSONArray expected, JSONArray actual, CompareContext mode) + public static JSONCompareDetailResult compareJSONInternal(JSONArray expected, JSONArray actual, CompareContext mode) throws JSONException { - return compareJSON(expected, actual, getComparatorForMode(mode)); + return compareJSONInternal(expected, actual, getComparatorForMode(mode)); } - /** - * Compares JSONArray provided to the expected JSONArray, and returns the results of the comparison. + * Compares JSON using YAML configuration rules. * - * @param expectedStr Expected JSON string - * @param actualStr JSON string to compare - * @param compareRules Compare rules in JSON string + * @param expectedStr Expected JSON string + * @param actualStr JSON string to compare + * @param yamlRule YAML configuration string containing comparison rules * @return result of the comparison - * @throws JSONException JSON parsing error + * @throws Exception if YAML parsing or comparison fails */ - public static JSONCompareSimpleResult compareJSONSimple(String expectedStr, String actualStr, - String compareRules) - throws JSONException { - CustomComparator comparator = CompareRulesTransformer.getComparator(compareRules); - return compareJSONSimple(expectedStr, actualStr, comparator); - } - - - public static JSONCompareResult compareJSONYaml(String expectedStr, String actualStr, String yamlRule) + public static JSONCompareResult compareJSON(String expectedStr, String actualStr, String yamlRule) throws Exception { JSONCompareConf yamlRuleObj = new JSONCompareConf(); yamlRuleObj.readNodeFromYaml(yamlRule); List compareRules = yamlRuleObj.getCompareRules(); JSONCompareResult result = new JSONCompareResult(); - // 解析 JSON 字符串 + // Parse JSON strings DocumentContext contextExpect = JsonPath.parse(expectedStr); DocumentContext contextActual = JsonPath.parse(actualStr); - // 使用路径表达式读取值 + // Use path expressions to read values String expectedByJsonPath = expectedStr; String actualByJsonPath = actualStr; @@ -198,67 +187,62 @@ public static JSONCompareResult compareJSONYaml(String expectedStr, String actua ObjectMapper objectMapper = new ObjectMapper(); expectedByJsonPath = objectMapper.writeValueAsString(contextExpect.read(compareRule.getJsonPath())); actualByJsonPath = objectMapper.writeValueAsString(contextActual.read(compareRule.getJsonPath())); + //If compareRule has preprocess and removeNode's jsonPath is not empty, perform preprocessing first + if (compareRule.getPreProcesses() != null){ + for (PreProcessItem preProcess : compareRule.getPreProcesses()) { + if ("removeNode".equals(preProcess.getAction()) && !StringUtils.isEmpty(preProcess.getPath())) { + expectedByJsonPath = removeNode(expectedByJsonPath, preProcess.getPath()); + actualByJsonPath = removeNode(actualByJsonPath, preProcess.getPath()); + } + } + } } try { - JSONCompareSimpleResult compareSimpleResult = compareJSONSimpleYaml(expectedByJsonPath, actualByJsonPath, comparator); + JSONCompareSimpleResult compareSimpleResult = compareJSONComparator(expectedByJsonPath, actualByJsonPath, comparator); result.addFailures(compareSimpleResult.getFailure()); } catch (JSONException e) { FailureField failureField = new FailureField("", "", compareRule.getJsonPath(), e.getMessage()); result.addFailure(failureField); } - - } - return result; - } - - public static JSONCompareDeepDetailResult compareJSONDeep(String expectedStr, String actualStr, - JSONComparator comparator) - throws JSONException { - Object expected = JSONParser.parseJSON(expectedStr); - Object actual = JSONParser.parseJSON(actualStr); - JSONCompareDeepDetailResult result; - if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { - result = new JSONCompareDeepDetailResult(compareJSON((JSONObject) expected, - (JSONObject) actual, comparator)); - } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { - result = new JSONCompareDeepDetailResult(compareJSON((JSONArray) expected, (JSONArray) actual - , comparator)); - } else if (expected instanceof JSONString && actual instanceof JSONString) { - result = new JSONCompareDeepDetailResult(compareJson((JSONString) expected, - (JSONString) actual)); - } else { - result = new JSONCompareDeepDetailResult(); - result.fail("", expected, actual); - return result; } - JSONCompareResultUtil.getAbsolutePath(expected, actual, result); return result; } - public static JSONCompareSimpleResult compareJSONSimpleYaml(String expectedStr, String actualStr, CustomComparator comparator) - throws JSONException { - return compareJSONSimple(expectedStr, actualStr, comparator); - } - - public static JSONCompareSimpleResult compareJSONSimple(String expectedStr, String actualStr, + /** + * Compares JSON string provided to the expected JSON string using provided comparator, and returns the results of + * the comparison. + * + * @param expectedStr Expected JSON string + * @param actualStr JSON string to compare + * @param comparator Comparator to use + * @return result of the comparison + * @throws JSONException JSON parsing error + */ + public static JSONCompareSimpleResult compareJSONComparator(String expectedStr, String actualStr, JSONComparator comparator) throws JSONException { Object expected = JSONParser.parseJSON(expectedStr); Object actual = JSONParser.parseJSON(actualStr); JSONCompareDetailResult result; if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) { - result = compareJSON((JSONObject) expected, (JSONObject) actual, comparator); + result = compareJSONInternal((JSONObject) expected, (JSONObject) actual, comparator); } else if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) { - result = compareJSON((JSONArray) expected, (JSONArray) actual, comparator); + result = compareJSONInternal((JSONArray) expected, (JSONArray) actual, comparator); } else if (expected instanceof JSONString && actual instanceof JSONString) { - result = compareJson((JSONString) expected, (JSONString) actual); + result = compareJSONInternal((JSONString) expected, (JSONString) actual); } else { result = new JSONCompareDetailResult(); result.fail("", expected, actual); } - JSONCompareSimpleResult simpleResult = JSONCompareResultUtil.getSimpleResult(result); - return simpleResult; + return JSONCompareResultUtil.getSimpleResult(result); + } + + //Add preprocess method to preprocess json, remove corresponding nodes, and return new json + public static String removeNode(String json, String jsonPath) { + DocumentContext context = JsonPath.parse(json); + context.delete(jsonPath); + return context.jsonString(); } } diff --git a/src/main/java/org/testtools/jsondiff/PreProcessItem.java b/src/main/java/org/testtools/jsondiff/PreProcessItem.java index 5eae4f0c..425f8302 100644 --- a/src/main/java/org/testtools/jsondiff/PreProcessItem.java +++ b/src/main/java/org/testtools/jsondiff/PreProcessItem.java @@ -17,4 +17,17 @@ public class PreProcessItem { String path; String action; + //增加get set方法 + public String getPath() { + return path; + } + public void setPath(String path) { + this.path = path; + } + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } } diff --git a/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java index 64a84c0e..e316fe71 100644 --- a/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/EscapedJsonMatcher.java @@ -43,7 +43,6 @@ public boolean equal(T o1, T o2) { return false; } - public void EscapedJsonMatcher(){} @Override public boolean equal(String prefix, T actual, T expected, JSONCompareDetailResult result, JSONComparator comparator) { diff --git a/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java b/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java index 7320a22a..6625edce 100644 --- a/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java +++ b/src/main/java/org/testtools/jsondiff/matcher/IngorePathMatcher.java @@ -18,7 +18,7 @@ /** * Function: - * + * Ignore specific paths during comparison * */ public class IngorePathMatcher implements ValueMatcher { diff --git a/src/site/resources/CNAME b/src/site/resources/CNAME deleted file mode 100644 index 01e66b25..00000000 --- a/src/site/resources/CNAME +++ /dev/null @@ -1,2 +0,0 @@ -jsonassert.skyscreamer.org - diff --git a/src/site/resources/cookbook.html b/src/site/resources/cookbook.html deleted file mode 100644 index 2e271348..00000000 --- a/src/site/resources/cookbook.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - JSONAssert - Write JSON Unit Tests with Less Code - Cookbook - - - - - - - -
-

JSONassert

-

a Skyscreamer project

-
-
- -
- -

Cookbook

- -

Assertion parameters can be a java.lang.String with JSON data, an org.json.JSONObject, or an org.json.JSONArray. - For readability, we'll use strings in the following examples.

- - - - - - - - -

Because application interfaces are naturally extended as they mature, it is recommended that you - default to leaving strict mode off, except in particular cases.

- - - -
-

When strict mode is off, arrays can be in any order:

-
- String result = "[1,2,3,4,5]";
- JSONAssert.assertEquals("[5,3,2,1,4]", result, false); // Pass
-
-
- - - -

The example so far are simple, but this will work for JSON objects of any size (per VM memory limits), depth, - or complexity.

- - - - - - -
- - diff --git a/src/site/resources/css/style.css b/src/site/resources/css/style.css deleted file mode 100644 index 260c3bc8..00000000 --- a/src/site/resources/css/style.css +++ /dev/null @@ -1,317 +0,0 @@ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0 none; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -html { - color: #000000; - background: #ffffff; - overflow-y: scroll; -} -body {line-height: 1;} -h1, h2, h3, h4, h5, h6 {font-weight: normal;} -ol, ul {list-style: none;} -blockquote, q {quotes: none;} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -caption, th {text-align: left;} -*:focus {outline: none 0;} -input::-moz-focus-inner, a img,:link img,:visited img {border: 0 none;} -:link, :visited, :hover, :active {text-decoration: none;} -address, caption, cite, code, dfn, em, strong, th, var { - font-style: normal; - font-weight: normal; -} -textarea {overflow: auto;} - - -a{ - color: #339CA5; -} - -/* Default Layout: 992px. - Gutters: 24px. - Outer margins: 48px. - Leftover space for scrollbars @1024px: 32px. -------------------------------------------------------------------------------- -cols 1 2 3 4 5 6 7 8 9 10 -px 68 160 252 344 436 528 620 712 804 896 */ - -body { - font-family: "Lucida Grande", Verdana, Tahoma, sans-serif; - font-size: 14px; - line-height: 15px; - color: #444; - padding: 48px 48px 84px; - margin: 0 auto; - width: 896px; - -webkit-text-size-adjust: 100%; /* Stops Mobile Safari from auto-adjusting font-sizes */ -} - nav { - background: #BEBBBB; - letter-spacing: .5px; - overflow: auto; - top: 0; - -webkit-box-shadow: 0 3px 3px 0 #ccf; - -moz-box-shadow: 0 3px 3px 0 #ccf; - box-shadow: 0 2px 6px 0 #bbb; - } - nav a { - display: block; - color: #fff; - float: left; - padding: 10px 18px; - border-right: 1px solid #eee; - } - nav .intro { - background: #3a3a3a; - } - nav .cookbook { - background: #339CA5; - } - nav .quickstart { - background: #757575; - } - nav .javadoc { - background: #757575; - } - nav .download { - background: #929090; - } - nav .contrib { - background: #a6a6a6; - background-image:url('http://skyscreamer.org/i/blacktocat.png'); - background-repeat:no-repeat; - background-position:center; - background-origin:content-box; - } - nav a.active { - background: #f3444e; - } - header { } - header h1 { - clear: both; - color: #339CA5; - font-size: 43px; - line-height: 60px; - float: left; - width: 70%; - } - header h2 { - padding: 33px 0 0 0; - float: left; - text-align: right; - width: 30%; - } - header h2 a { - color: #950510; - } - header ul li { - float: left; - } -section { - clear: both; - margin: 0 0 20px 0; - padding: 0 20px; -} - section h2 { - border-bottom: 2px solid #339CA5; - font-size: 20px; - line-height: 21px; - margin-bottom: 20px; - padding-top: 30px; - } - section p { - margin: 10px 0; - } - section blockquote, - section pre { - background: #B2F1F7; - border: 3px double #aaa; - padding: 10px; - } - section pre { - overflow: auto; - font: 11px "Courier New", Courier, monospace; - } - section blockquote a { - font: 12px "Courier New", Courier, monospace; - color: #000; - } - section .demo { - background: #d1d1ff; - border: 3px double #aaa; - float: left; - margin: 20px 0 20px 0; - padding: 8px; - width: 380px; - } - section .demo h5 { - font-size: 13px; - font-weight: bold; - } - section .demo .wrapper { - display: none; - font: 12px "Courier New", Courier, monospace; - margin: 0; - padding: 0; - } - section .wrapper article h4 { - font-weight: bold; - margin-top: 20px; - } - section .demo .wrapper h4 { - font-size: 15px; - } - section .demo input, - section .demo textarea { - border: 1px solid #888; - margin-top: 30px; - width: 100%; - } - section .demo textarea { - height: 150px; - } - section .demo2 { - float: right; - } - section div.example { - margin: 30px 20px; - } - section div.example p { - font: 12px Verdana; - margin-bottom: 3px; - } - section ul { - list-style: circle; - margin-left: 20px; - } - section ul li { - margin-bottom: 8px; - } - - .strikethrough { text-decoration: line-through; } - - .emphasize { font-weight: bold; } - - .perf_table { - border: #30873E 2px solid; - width: 800px; - } - - .perf_table th { - border: #30873E 1px solid; - padding: 3px; - spacing: 3px; - background-color: #30873E; - color: #FFFFFF; - } - - .perf_table td { - border: #30873E 1px solid; - padding: 3px; - spacing: 3px; - } - - .perf_table .alt_row td { - border: #30873E 1px solid; - padding: 3px; - spacing: 3px; - background-color: #7EC16A; - } - - - -/* Tablet Layout: 768px. -Gutters: 24px. -Outer margins: 28px. -Inherits styles from: Default Layout. ------------------------------------------------------------------ -cols 1 2 3 4 5 6 7 8 -px 68 160 252 344 436 528 620 712 */ - -@media only screen and (min-width: 768px) and (max-width: 991px) { - - body { - width: 712px; - padding: 48px 28px 60px; - } - section .demo { - width: 285px; - } -} - - - -/* Mobile Layout: 320px. - Gutters: 24px. - Outer margins: 34px. - Inherits styles from: Default Layout. ---------------------------------------------- -cols 1 2 3 -px 68 160 252 */ - -@media only screen and (max-width: 767px) { - - body { - width: 252px; - padding: 48px 34px 60px; - } - nav li a { - float: none; - display: block; - } - section .demo { - float: left; - width: 200px; - } - -} - - - -/* Wide Mobile Layout: 480px. - Gutters: 24px. - Outer margins: 22px. - Inherits styles from: Default Layout, Mobile Layout. ------------------------------------------------------------- -cols 1 2 3 4 5 -px 68 160 252 344 436 */ - -@media only screen and (min-width: 480px) and (max-width: 767px) { - - body { - width: 436px; - padding: 48px 22px 48px; - } - section .demo { - float: left; - } - -} diff --git a/src/site/resources/index.html b/src/site/resources/index.html deleted file mode 100644 index 41f2c5ae..00000000 --- a/src/site/resources/index.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - JSONAssert - Write JSON Unit Tests with Less Code - Introduction - - - - - - - -
-

JSONassert

-

a Skyscreamer project

-
-
- -
- -

Introduction

- -

Write JSON unit tests in less code. Great for testing REST interfaces.

- -


Code JSON tests as if you are comparing a string. Under the covers, JSONassert converts your string into a JSON object and compares the logical structure and data with the actual JSON. When strict is set to false (recommended), it forgives reordering data and extending results (as long as all the expected elements are there), making tests less brittle.

- -


Supported test frameworks:

- - - -


The current version of JSONassert is 2.0-rc1

- -

Examples

- - - - - -

Error Messages

- - - - - - ... which tells you that the pets array under the friend where id=3 was supposed to contain "bird", but had "cat" instead. - (Maybe the cat ate the bird?) -
- -
- -

Contact

-

- This is open source so if you want to help out whether by submitting code, design, suggestions, feedback, - or feature requests, we appreciate whatever you can contribute. Contact us at - jsonassert-dev@skyscreamer.org with questions or ideas. -

-
- - diff --git a/src/site/resources/quickstart.html b/src/site/resources/quickstart.html deleted file mode 100644 index 371e3575..00000000 --- a/src/site/resources/quickstart.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - JSONAssert - Write JSON Unit Tests with Less Code - Quickstart - - - - - - - -
-

JSONassert

-

a Skyscreamer project

-
-
- -
- -

Quick Start

- -

To use, download and build the JAR or - add the following to your project's pom.xml:

- - - -

Syntax is simple, and similar to JUnit Assert:

- - -

Add JSONassert tests within existing JUnit tests, just like you would add a standard Assert:

- - - -

It is recommended that you leave strictMode - off, so your tests will be less brittle. - Turn it on if you need to enforce a particular order for arrays, or if you want to - ensure that the actual JSON does not have any fields beyond what's expected.

-
- - diff --git a/src/test/java/jsondiff/FileUtil.java b/src/test/java/jsondiff/FileUtil.java index 9743dea4..0703dc2c 100644 --- a/src/test/java/jsondiff/FileUtil.java +++ b/src/test/java/jsondiff/FileUtil.java @@ -27,14 +27,14 @@ public FileUtil() { } /** - * 读取文件内容 - * @param fileName 文件路径,可以是相对路径或绝对路径 - * @return 文件内容字符串 + * Read file content + * @param fileName File path, can be relative path or absolute path + * @return File content string */ public static String readFile(String fileName) { try{ String path; - // 如果是绝对路径,直接使用;否则拼接工作目录 + // If it's an absolute path, use it directly; otherwise concatenate with working directory if (new File(fileName).isAbsolute()) { path = fileName; } else { @@ -45,11 +45,10 @@ public static String readFile(String fileName) { FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String line; -// System.out.println("Reading text file using FileReader"); + StringBuffer sb = new StringBuffer(); while((line = br.readLine()) != null){ - //逐行读取 -// System.out.println(line); + sb.append(line).append("\n"); } br.close(); @@ -62,9 +61,9 @@ public static String readFile(String fileName) { } /** - * 获取文件的绝对路径 - * @param filePath 文件路径,可以是相对路径或绝对路径 - * @return 文件的绝对路径 + * Get the absolute path of the file + * @param filePath File path, can be relative path or absolute path + * @return The absolute path of the file */ public static String getAbsolutePath(String filePath) { File file = new File(filePath); @@ -76,9 +75,9 @@ public static String getAbsolutePath(String filePath) { } /** - * 检查文件是否存在 - * @param filePath 文件路径 - * @return 如果文件存在返回true,否则返回false + * Check if the file exists + * @param filePath File path + * @return Returns true if the file exists, otherwise returns false */ public static boolean fileExists(String filePath) { String path; @@ -91,9 +90,9 @@ public static boolean fileExists(String filePath) { } /** - * 获取文件所在目录的绝对路径 - * @param filePath 文件路径 - * @return 文件所在目录的绝对路径 + * Get the absolute path of the directory containing the file + * @param filePath File path + * @return The absolute path of the directory containing the file */ public static String getParentPath(String filePath) { return new File(getAbsolutePath(filePath)).getParent(); diff --git a/src/test/java/jsondiff/JSONCompareYamlResultTest.java b/src/test/java/jsondiff/JSONCompareYamlResultTest.java index ae5541fa..687e1148 100644 --- a/src/test/java/jsondiff/JSONCompareYamlResultTest.java +++ b/src/test/java/jsondiff/JSONCompareYamlResultTest.java @@ -49,11 +49,6 @@ public void setUp() { createOutputDirectory(); } - @After - public void tearDown() { - // Clean up test output files (optional) - // cleanupTestOutput(); - } /** * Run the specified test case @@ -64,8 +59,8 @@ private void runTestCase(String caseNumber) throws Exception { System.out.println("=== Starting test case execution: case_" + caseNumber + " ==="); // Build file paths - String expectedJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_a.json"; - String actualJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_e.json"; + String expectedJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_e.json"; + String actualJsonPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_a.json"; String rulesPath = TEST_RESOURCES_PATH + "rule_case" + caseNumber + ".yaml"; String expectedResultPath = TEST_RESOURCES_PATH + "case_" + caseNumber + "_result.json"; String outputFilePath = OUTPUT_PATH + "case_" + caseNumber + "_diff.json"; @@ -87,11 +82,7 @@ private void runTestCase(String caseNumber) throws Exception { // Execute JSON comparison System.out.println("Starting JSON comparison..."); - JSONCompareResult result = JSONCompare.compareJSONYaml(expectedJSON, actualJSON, rules); - - if (result == null) { - fail("JSON comparison returned null result"); - } + JSONCompareResult result = JSONCompare.compareJSON(expectedJSON, actualJSON, rules); // Serialize comparison result String actualResult = objectMapper.writeValueAsString(result.getFailure()); @@ -244,7 +235,7 @@ public void testBasicJSONCompare() throws Exception { String actualJSON = "{\"name\":\"John\",\"age\":30}"; String rules = "[]"; - JSONCompareResult result = JSONCompare.compareJSONYaml(expectedJSON, actualJSON, rules); + JSONCompareResult result = JSONCompare.compareJSON(expectedJSON, actualJSON, rules); assertNotNull("Comparison result should not be null", result); assertTrue("Identical JSON should compare successfully", result.getFailure().isEmpty()); } diff --git a/src/test/resources/case_01_result.json b/src/test/resources/case_01_result.json index 30136d4d..4a271d3f 100644 --- a/src/test/resources/case_01_result.json +++ b/src/test/resources/case_01_result.json @@ -1 +1 @@ -[{"expected":37.7749,"actual":37.7749001,"diffKey":"location.x","reason":"actual unequals to expected"}] \ No newline at end of file +[{"expected":37.7749001,"actual":37.7749,"diffKey":"location.x","reason":"actual unequals to expected"}] \ No newline at end of file diff --git a/src/test/resources/rule_case01.yaml b/src/test/resources/rule_case01.yaml index 8abf5910..93aba5df 100644 --- a/src/test/resources/rule_case01.yaml +++ b/src/test/resources/rule_case01.yaml @@ -10,13 +10,12 @@ ignoreNull: true # Whether to stop comparison immediately when first difference is found fastFail: false - preProcess: # TODO + preProcess: # Remove specific nodes from JSON before comparison removeNode: jsonPath: "" - # Escape special characters in JSON values - escape: - jsonPath: "" + removeNode: + jsonPath: "" # Custom comparison rules to apply to this JSONPath customRules: # Apply number precision comparison to all age fields (3 decimal places, rounding mode 3) diff --git a/testoutput/case_01_diff.json b/testoutput/case_01_diff.json new file mode 100644 index 00000000..4a271d3f --- /dev/null +++ b/testoutput/case_01_diff.json @@ -0,0 +1 @@ +[{"expected":37.7749001,"actual":37.7749,"diffKey":"location.x","reason":"actual unequals to expected"}] \ No newline at end of file From 4f34eed12948fe051a2894afa8d60105fbeb111e Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sat, 19 Jul 2025 22:40:43 +0800 Subject: [PATCH 15/18] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8cf8bc0e..22edfcea 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The following example demonstrates how to configure a subRule for comparing JSON - name: ImprecisePosition jsonPath: "" param: "tolerance=0.01;separator=," +``` ### Configuration Parameters Explained From a06af3b20bcdb42c191bf8dea17122184da9331c Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sat, 19 Jul 2025 22:46:05 +0800 Subject: [PATCH 16/18] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c502176..915a680b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,8 @@ Version 1.0.0 - 03/02/2025 ------------------- - create repo - first version of UJD + +Version 1.0.1 - 07/19/2025 +------------------- + - fix some bugs + - add readme and translate CN to English From aedb01c469b2c62ac06b008064b87d9e96399abe Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 20 Jul 2025 22:10:55 +0800 Subject: [PATCH 17/18] Update README.md --- README.md | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 22edfcea..b0842619 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,127 @@ 3. Can easily extend new comparison rules based on existing source code, Easier to rewrite and expand new rules 4. For huge json files, such as json files over several megabytes, has better performance, with jsonpath selector to improve performance +# Usage + +UltraJSONDiff provides a simple and powerful API for comparing JSON data using YAML configuration rules. The core method is `JSONCompare.compareJSON()`. + +## Basic Usage + +The main method for JSON comparison is: + +```java +public static JSONCompareResult compareJSON(String expectedStr, String actualStr, String yamlRule) throws Exception +``` + +### Parameters: +- **expectedStr**: The expected JSON string +- **actualStr**: The actual JSON string to compare against +- **yamlRule**: YAML configuration string containing comparison rules + +### Return Value: +- **JSONCompareResult**: Object containing the comparison results and any failures + +## Quick Start Example + +Here's a simple example based on the unit test: + +```java +import org.testtools.jsondiff.JSONCompare; +import org.testtools.jsondiff.JSONCompareResult; + +// Test data +String expectedJSON = "{\"name\":\"John\",\"age\":30}"; +String actualJSON = "{\"name\":\"John\",\"age\":30}"; +String rules = "[]"; // Empty rules for basic comparison + +// Perform comparison +JSONCompareResult result = JSONCompare.compareJSON(expectedJSON, actualJSON, rules); + +// Check if comparison was successful +if (result.getFailure().isEmpty()) { + System.out.println("JSON comparison successful!"); +} else { + System.out.println("JSON comparison failed: " + result.getFailure()); +} +``` + +### YAML Rules Configuration (rule_case01.yaml) + +```yaml +- subRule: + jsonPath: $.user + extensible: true + strictOrder: true + ignoreNull: true + fastFail: false + customRules: + # Apply number precision comparison to age fields + - name: NumberPrecise + jsonPath: "**.age" + param: "newScale=3,roundingMode=3" + + # Ignore timestamp field during comparison + - name: IngorePath + param: "user.queryTimestamp" + + # Compare position values with tolerance + - name: ImprecisePosition + jsonPath: "" + param: "tolerance=0.01;separator=," + +- subRule: + jsonPath: $.ordersStrictOrder + extensible: true + strictOrder: true + customRules: + - name: ArrayWithKey + jsonPath: "$" + param: "key=orderId" + +- subRule: + jsonPath: $.ordersWithoutOrder + extensible: true + strictOrder: false + customRules: + - name: ArrayDisorder + jsonPath: "$" +``` + +### Test Execution + +```java +@Test +public void testCase01() throws Exception { + // Read test files + String expectedJSON = readFileContent("src/test/resources/case_01_e.json"); + String actualJSON = readFileContent("src/test/resources/case_01_a.json"); + String rules = readFileContent("src/test/resources/rule_case01.yaml"); + + // Execute comparison + JSONCompareResult result = JSONCompare.compareJSON(expectedJSON, actualJSON, rules); + + // Process results + ObjectMapper objectMapper = new ObjectMapper(); + String actualResult = objectMapper.writeValueAsString(result.getFailure()); + + // Validate - this test should pass because: + // 1. User data matches (with precision tolerance for location.x) + // 2. Timestamp is ignored + // 3. Position values are compared with tolerance + // 4. ordersStrictOrder maintains strict order + // 5. ordersWithoutOrder allows reordering + assertTrue("Comparison should succeed with configured rules", result.getFailure().isEmpty()); +} +``` + +### What This Test Demonstrates + +1. **Precision Comparison**: Location coordinates are compared with tolerance for floating-point precision +2. **Field Ignoring**: The `queryTimestamp` field is completely ignored during comparison +3. **Position Tolerance**: Position strings are parsed and compared with tolerance +4. **Array Order Control**: `ordersStrictOrder` requires exact order, while `ordersWithoutOrder` allows reordering +5. **Key-based Array Matching**: Arrays can be matched using specific key fields + # Configuration Example ## SubRule Configuration @@ -69,7 +190,6 @@ The following example demonstrates how to configure a subRule for comparing JSON - name: ImprecisePosition jsonPath: "" param: "tolerance=0.01;separator=," -``` ### Configuration Parameters Explained @@ -275,3 +395,27 @@ The framework automatically discovers and instantiates your matcher class using Your custom matcher will be automatically available for use in YAML configuration files without any additional registration steps. +## Summary + +UltraJSONDiff's `JSONCompare.compareJSON()` method provides a powerful and flexible solution for JSON comparison: + +### Key Features: +- **Simple API**: Single method call with three parameters +- **YAML Configuration**: Declarative rule definition for complex comparison scenarios +- **Flexible Matching**: Support for tolerance, precision, array ordering, and field ignoring +- **Extensible**: Easy to add custom comparison rules +- **Performance**: Optimized for large JSON files with JSONPath selectors + +### When to Use: +- **API Testing**: Compare API responses with expected results +- **Data Validation**: Verify JSON data transformations +- **Integration Testing**: Ensure data consistency across systems +- **Regression Testing**: Detect changes in JSON output formats + +### Method Signature: +```java +public static JSONCompareResult compareJSON(String expectedStr, String actualStr, String yamlRule) throws Exception +``` + +This method is the core of UltraJSONDiff and provides all the functionality needed for sophisticated JSON comparison scenarios. + From e6e6b26e44882394513761d81a371f9373357064 Mon Sep 17 00:00:00 2001 From: shend2025 Date: Sun, 20 Jul 2025 22:12:16 +0800 Subject: [PATCH 18/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0842619..b936d74c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# What's this UJD(UltraJSONDiff) +# What's this JavaJSONDiff * A powerful jsondiff tool for developer and test engineer * rewrite some modules of https://github.com/skyscreamer/JSONassert which is a tool for Test Assert but UltraJSONDiff experts in JSONDiff # Core Advantages