From f55e645b5f8516d3e22760976c05c474314f5049 Mon Sep 17 00:00:00 2001 From: erussell Date: Thu, 5 Jun 2014 13:52:54 -0500 Subject: [PATCH 1/3] Make jsoncompare.contains ignore missing keys in nested dictionaries Also add some tests --- jsoncompare/jsoncompare.py | 8 ++-- jsoncompare/test/test_jsoncompare.py | 66 +++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/jsoncompare/jsoncompare.py b/jsoncompare/jsoncompare.py index 9a2357f..376bf11 100644 --- a/jsoncompare/jsoncompare.py +++ b/jsoncompare/jsoncompare.py @@ -49,7 +49,7 @@ def _generate_pprint_json(value): return json.dumps(value, sort_keys=True, indent=4) -def _is_dict_same(expected, actual, ignore_value_of_keys): +def _is_dict_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False): # DAN - I had to flip flop this for key in expected: if not key in actual: @@ -63,7 +63,7 @@ def _is_dict_same(expected, actual, ignore_value_of_keys): if not key in ignore_value_of_keys: # have to change order #are_same_flag, stack = _are_same(actual[key], expected[key], ignore_value_of_keys) - are_same_flag, stack = _are_same(expected[key], actual[key],ignore_value_of_keys) + are_same_flag, stack = _are_same(expected[key], actual[key], ignore_value_of_keys, ignore_missing_keys) if not are_same_flag: return False, \ stack.append(StackItem('Different values', expected[key], actual[key])) @@ -134,10 +134,8 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) expected, actual)) - - if isinstance(expected, dict): - return _is_dict_same(expected, actual, ignore_value_of_keys) + return _is_dict_same(expected, actual, ignore_value_of_keys, ignore_missing_keys) if isinstance(expected, list): return _is_list_same(expected, actual, ignore_value_of_keys) diff --git a/jsoncompare/test/test_jsoncompare.py b/jsoncompare/test/test_jsoncompare.py index 541ddfb..2440256 100755 --- a/jsoncompare/test/test_jsoncompare.py +++ b/jsoncompare/test/test_jsoncompare.py @@ -1,13 +1,15 @@ #!/usr/bin/env python import unittest -import sys, os +import os +import sys path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not path in sys.path: sys.path.insert(1, path) import jsoncompare + class TestJSONCompare(unittest.TestCase): def setUp(self): @@ -197,7 +199,7 @@ def test_inner_val_sensitivity_false(self): ] } b = { - "failureReason" : "Invalid request entity", + "failureReason": "Invalid request entity", "fieldValidationErrors" : [ { "field" : "Catalog.catalogOwner", @@ -213,8 +215,8 @@ def test_inner_val_sensitivity_false(self): def test_nested_list_order_inner_val_sensitivity_false(self): a = { - "failureReason" : "Invalid request entity", - "fieldValidationErrors" : [ + "failureReason": "Invalid request entity", + "fieldValidationErrors": [ { "field" : "Catalog.catalogOwner", "reason" : "may not be smelly" @@ -226,7 +228,7 @@ def test_nested_list_order_inner_val_sensitivity_false(self): ] } b = { - "failureReason" : "Invalid request entity", + "failureReason": "Invalid request entity", "fieldValidationErrors" : [ { "field" : "Catalog.name", @@ -245,7 +247,6 @@ def test_giant_json_ignores_reordering(self): b = open("testing-data/jsonblobb.json").read() self.assertTrue(jsoncompare.json_are_same(a, b, True)[0]) - def test_giant_json_finds_reordering(self): a = open("testing-data/jsonbloba.json").read() b = open("testing-data/jsonblobb.json").read() @@ -304,7 +305,7 @@ def test_contains_same_size4(self): self.assertFalse(jsoncompare.contains(expected, actual)[0]) #same, error_message = jsoncompare.contains(expected, actual) #assert same, error_message - + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes def test_contains_actual_bigger(self): actual = [ @@ -318,6 +319,23 @@ def test_contains_actual_bigger(self): ] self.assertTrue(jsoncompare.contains(expected, actual)[0]) + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_contains_actual_bigger_nested(self): + actual = { + "inner": [ + {"wtf": "omg"}, + {"wtf1": "omg1"}, + {"wtf3": "omg3"} + ] + } + expected = { + "inner": [ + {"wtf": "omg"}, + {"wtf1": "omg1"} + ] + } + self.assertTrue(jsoncompare.contains(expected, actual)[0]) + # Test two json where Actual is smaller - it can NOT contain all of expected attributes def test_contains_actual_smaller(self): actual = [ @@ -331,6 +349,40 @@ def test_contains_actual_smaller(self): ] self.assertFalse(jsoncompare.contains(expected, actual)[0]) + # Test two json where Actual is smaller - it can NOT contain all of expected attributes + def test_contains_actual_smaller_nested(self): + actual = { + "inner": [ + {"wtf": "omg"}, + {"wtf1": "omg1"} + ] + } + expected = { + "inner": [ + {"wtf": "omg"}, + {"wtf1": "omg1"}, + {"wtf2": "omg2"} + ] + } + self.assertFalse(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_contains_nested_different_value(self): + actual = { + "inner": [ + {"wtf": "omg!!!!!!!"}, + {"wtf1": "omg1"}, + {"wtf3": "omg3"} + ] + } + expected = { + "inner": [ + {"wtf": "omg"}, + {"wtf1": "omg1"} + ] + } + self.assertFalse(jsoncompare.contains(expected, actual)[0]) + if __name__ == '__main__': unittest.main() From 9ab6df55e69a2ab1e0ffa1e9fc50cbe42c21b47c Mon Sep 17 00:00:00 2001 From: erussell Date: Thu, 5 Jun 2014 14:16:51 -0500 Subject: [PATCH 2/3] Fix contains testing for object contained in array, add more tests --- jsoncompare/jsoncompare.py | 6 +- jsoncompare/test/test_jsoncompare.py | 95 ++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/jsoncompare/jsoncompare.py b/jsoncompare/jsoncompare.py index 376bf11..64c5424 100644 --- a/jsoncompare/jsoncompare.py +++ b/jsoncompare/jsoncompare.py @@ -69,9 +69,9 @@ def _is_dict_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=Fa stack.append(StackItem('Different values', expected[key], actual[key])) return True, Stack() -def _is_list_same(expected, actual, ignore_value_of_keys): +def _is_list_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False): for i in xrange(len(expected)): - are_same_flag, stack = _are_same(expected[i], actual[i], ignore_value_of_keys) + are_same_flag, stack = _are_same(expected[i], actual[i], ignore_value_of_keys, ignore_missing_keys) if not are_same_flag: return False, \ stack.append( @@ -138,7 +138,7 @@ def _are_same(expected, actual, ignore_value_of_keys, ignore_missing_keys=False) return _is_dict_same(expected, actual, ignore_value_of_keys, ignore_missing_keys) if isinstance(expected, list): - return _is_list_same(expected, actual, ignore_value_of_keys) + return _is_list_same(expected, actual, ignore_value_of_keys, ignore_missing_keys) return False, Stack().append(StackItem('Unhandled Type: {0}'.format(type(expected)), expected, actual)) diff --git a/jsoncompare/test/test_jsoncompare.py b/jsoncompare/test/test_jsoncompare.py index 2440256..fba28b9 100755 --- a/jsoncompare/test/test_jsoncompare.py +++ b/jsoncompare/test/test_jsoncompare.py @@ -367,18 +367,101 @@ def test_contains_actual_smaller_nested(self): self.assertFalse(jsoncompare.contains(expected, actual)[0]) # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes - def test_contains_nested_different_value(self): + def test_contains_nested_in_array(self): actual = { "inner": [ - {"wtf": "omg!!!!!!!"}, - {"wtf1": "omg1"}, - {"wtf3": "omg3"} + {"a": 1, "b": 2} ] } expected = { "inner": [ - {"wtf": "omg"}, - {"wtf1": "omg1"} + {"a": 1} + ] + } + self.assertTrue(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_contains_nested_in_array_in_object(self): + actual = { + "outer": [ + {"inner": {"a": 1, "b": 2}} + ] + } + expected = { + "outer": [ + {"inner": {"a": 1}} + ] + } + self.assertTrue(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_contains_nested_in_array_in_object_in_array(self): + actual = { + "outer": [ + { + "inner": [ + {"a": 1, "b": 2} + ] + } + ] + } + expected = { + "outer": [ + { + "inner": [ + {"b": 2} + ] + } + ] + } + self.assertTrue(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_not_contains_nested_in_array(self): + actual = { + "inner": [ + {"a": 1} + ] + } + expected = { + "inner": [ + {"a": 1, "b": 2} + ] + } + self.assertFalse(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_not_contains_nested_in_array_in_object(self): + actual = { + "outer": [ + {"inner": {"a": 1}} + ] + } + expected = { + "outer": [ + {"inner": {"a": 1, "b": 2}} + ] + } + self.assertFalse(jsoncompare.contains(expected, actual)[0]) + + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes + def test_not_contains_nested_in_array_in_object_in_array(self): + actual = { + "outer": [ + { + "inner": [ + {"b": 2} + ] + } + ] + } + expected = { + "outer": [ + { + "inner": [ + {"a": 1, "b": 2} + ] + } ] } self.assertFalse(jsoncompare.contains(expected, actual)[0]) From 0ac5f0cd85d68ef31a89bc8ef525d908f1bf3d95 Mon Sep 17 00:00:00 2001 From: erussell Date: Thu, 5 Jun 2014 15:36:07 -0500 Subject: [PATCH 3/3] Revert some irrelevant code style changes to tests --- jsoncompare/test/test_jsoncompare.py | 41 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/jsoncompare/test/test_jsoncompare.py b/jsoncompare/test/test_jsoncompare.py index fba28b9..ea72c29 100755 --- a/jsoncompare/test/test_jsoncompare.py +++ b/jsoncompare/test/test_jsoncompare.py @@ -1,15 +1,13 @@ #!/usr/bin/env python import unittest -import os -import sys +import sys, os path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not path in sys.path: sys.path.insert(1, path) import jsoncompare - class TestJSONCompare(unittest.TestCase): def setUp(self): @@ -199,7 +197,7 @@ def test_inner_val_sensitivity_false(self): ] } b = { - "failureReason": "Invalid request entity", + "failureReason" : "Invalid request entity", "fieldValidationErrors" : [ { "field" : "Catalog.catalogOwner", @@ -215,8 +213,8 @@ def test_inner_val_sensitivity_false(self): def test_nested_list_order_inner_val_sensitivity_false(self): a = { - "failureReason": "Invalid request entity", - "fieldValidationErrors": [ + "failureReason" : "Invalid request entity", + "fieldValidationErrors" : [ { "field" : "Catalog.catalogOwner", "reason" : "may not be smelly" @@ -228,7 +226,7 @@ def test_nested_list_order_inner_val_sensitivity_false(self): ] } b = { - "failureReason": "Invalid request entity", + "failureReason" : "Invalid request entity", "fieldValidationErrors" : [ { "field" : "Catalog.name", @@ -247,6 +245,7 @@ def test_giant_json_ignores_reordering(self): b = open("testing-data/jsonblobb.json").read() self.assertTrue(jsoncompare.json_are_same(a, b, True)[0]) + def test_giant_json_finds_reordering(self): a = open("testing-data/jsonbloba.json").read() b = open("testing-data/jsonblobb.json").read() @@ -305,7 +304,7 @@ def test_contains_same_size4(self): self.assertFalse(jsoncompare.contains(expected, actual)[0]) #same, error_message = jsoncompare.contains(expected, actual) #assert same, error_message - + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes def test_contains_actual_bigger(self): actual = [ @@ -319,6 +318,19 @@ def test_contains_actual_bigger(self): ] self.assertTrue(jsoncompare.contains(expected, actual)[0]) + # Test two json where Actual is smaller - it can NOT contain all of expected attributes + def test_contains_actual_smaller(self): + actual = [ + {"wtf": "omg"}, + {"wtf1": "omg1"} + ] + expected = [ + {"wtf": "omg"}, + {"wtf1": "omg1"}, + {"wtf2": "omg2"} + ] + self.assertFalse(jsoncompare.contains(expected, actual)[0]) + # Test two json where Actual is larger - it can (potentialy) contain all of the expected attributes def test_contains_actual_bigger_nested(self): actual = { @@ -336,19 +348,6 @@ def test_contains_actual_bigger_nested(self): } self.assertTrue(jsoncompare.contains(expected, actual)[0]) - # Test two json where Actual is smaller - it can NOT contain all of expected attributes - def test_contains_actual_smaller(self): - actual = [ - {"wtf": "omg"}, - {"wtf1": "omg1"} - ] - expected = [ - {"wtf": "omg"}, - {"wtf1": "omg1"}, - {"wtf2": "omg2"} - ] - self.assertFalse(jsoncompare.contains(expected, actual)[0]) - # Test two json where Actual is smaller - it can NOT contain all of expected attributes def test_contains_actual_smaller_nested(self): actual = {