dstr2 = json.dumps(d2, **json_format_opts)
return difflines(dstr2, dstr1, title1='Expected value', title2='Current value', n=0)
+
+def _json_list_cmp(list1, list2, parent, result):
+ "Handles list type entries."
+ # Check second list2 type
+ if not isinstance(list1, type([])) or not isinstance(list2, type([])):
+ result.add_error(
+ '{} has different type than expected '.format(parent) +
+ '(have {}, expected {}):\n{}'.format(
+ type(list1), type(list2), json_diff(list1, list2)))
+ return
+
+ # Check list size
+ if len(list2) > len(list1):
+ result.add_error(
+ '{} too few items '.format(parent) +
+ '(have {}, expected {}:\n {})'.format(
+ len(list1), len(list2),
+ json_diff(list1, list2)))
+ return
+
+ # List all unmatched items errors
+ unmatched = []
+ for expected in list2:
+ matched = False
+ for value in list1:
+ if json_cmp({'json': value}, {'json': expected}) is None:
+ matched = True
+ break
+
+ if matched:
+ break
+ if not matched:
+ unmatched.append(expected)
+
+ # If there are unmatched items, error out.
+ if unmatched:
+ result.add_error(
+ '{} value is different (\n{})'.format(
+ parent, json_diff(list1, list2)))
+
+
def json_cmp(d1, d2):
"""
JSON compare function. Receives two parameters:
"""
squeue = [(d1, d2, 'json')]
result = json_cmp_result()
+
for s in squeue:
nd1, nd2, parent = s
- s1, s2 = set(nd1), set(nd2)
+
+ # Handle JSON beginning with lists.
+ if isinstance(nd1, type([])) or isinstance(nd2, type([])):
+ _json_list_cmp(nd1, nd2, parent, result)
+ if result.has_errors():
+ return result
+ else:
+ return None
# Expect all required fields to exist.
+ s1, s2 = set(nd1), set(nd2)
s2_req = set([key for key in nd2 if nd2[key] is not None])
diff = s2_req - s1
if diff != set({}):
result.add_error('"{}" should not exist in {} (have {}):\n{}'.format(
key, parent, str(s1), json_diff(nd1[key], nd2[key])))
continue
+
# If nd1 key is a dict, we have to recurse in it later.
if isinstance(nd2[key], type({})):
if not isinstance(nd1[key], type({})):
nparent = '{}["{}"]'.format(parent, key)
squeue.append((nd1[key], nd2[key], nparent))
continue
+
# Check list items
if isinstance(nd2[key], type([])):
- if not isinstance(nd1[key], type([])):
- result.add_error(
- '{}["{}"] has different type than expected '.format(parent, key) +
- '(have {}, expected {}):\n{}'.format(
- type(nd1[key]), type(nd2[key]), json_diff(nd1[key], nd2[key])))
- continue
- # Check list size
- if len(nd2[key]) > len(nd1[key]):
- result.add_error(
- '{}["{}"] too few items '.format(parent, key) +
- '(have {}, expected {}:\n {})'.format(
- len(nd1[key]), len(nd2[key]),
- json_diff(nd1[key], nd2[key])))
- continue
-
- # List all unmatched items errors
- unmatched = []
- for expected in nd2[key]:
- matched = False
- for value in nd1[key]:
- if json_cmp({'json': value}, {'json': expected}) is None:
- matched = True
- break
-
- if matched:
- break
- if not matched:
- unmatched.append(expected)
-
- # If there are unmatched items, error out.
- if unmatched:
- result.add_error(
- '{}["{}"] value is different (\n{})'.format(
- parent, key, json_diff(nd1[key], nd2[key])))
+ _json_list_cmp(nd1[key], nd2[key], parent, result)
continue
# Compare JSON values
return None
+
def run_and_expect(func, what, count=20, wait=3):
"""
Run `func` and compare the result with `what`. Do it for `count` times