def compare(cls, expected, actual, type_compare=None): if type_compare is None: type_compare = {} elif isinstance(type_compare, str): type_compare = {"hash": type_compare, "ordered": True} default_type_compare = {"hash": "full", "ordered": True} type_compare = combine(default_type_compare, type_compare) if type(expected) == DontCare: if expected.compare_with(actual): return "match" else: return ("dontcare: %s" % expected.rule, actual) elif type(expected) == re._pattern_type and isinstance(actual, six.string_types): match = expected.match(actual) if match: return "match" else: return ("regex: %s" % expected.pattern, actual) elif type(expected).__name__ == "ParsingHint": return cls.compare(expected.payload, expected.parse(actual), type_compare) elif acts_like_a_hash(expected) and acts_like_a_hash(actual): return cls.hash_compare(expected, actual, type_compare) elif isinstance(expected, tuple) and isinstance(actual, tuple): return cls.list_compare(expected, actual, type_compare, iter_type=tuple) elif acts_like_a_list(expected) and acts_like_a_list(actual): return cls.list_compare(expected, actual, type_compare, iter_type=list) else: if expected == actual: return "match" else: return (expected, actual)
def hash_compare(cls, expected, actual, type_compare={}): default_type_compare =\ {'hash' : 'full', 'dontcare_keys' : [], 'ordered' : True} type_compare =\ combine(default_type_compare, type_compare) if '__compare' in expected: compare_override = expected['__compare'] if acts_like_a_hash(compare_override): type_compare = combine(default_type_compare, compare_override) else: type_compare['hash'] = compare_override expected = dict((k, v) for (k, v) in expected.items() if k != '__compare') expected_return = {} actual_return = {} if type_compare['hash'] == 'full': keys = set([]) keys.update(expected.keys()) keys.update(actual.keys()) else: keys = set(expected.keys()) for key in keys: if key in type_compare['dontcare_keys']: result = cls.compare(DontCare(), actual.get(key, NotPresent), type_compare) else: result = cls.compare(expected.get(key, NotPresent), actual.get(key, NotPresent), type_compare) if result != 'match': expected_sub, actual_sub = result expected_return[key] = expected_sub actual_return[key] = actual_sub if len(expected_return) == 0: return 'match' else: return (expected_return, actual_return)
def hash_compare(cls, expected, actual, type_compare={}): default_type_compare = {"hash": "full", "dontcare_keys": [], "ordered": True} type_compare = combine(default_type_compare, type_compare) if "__compare" in expected: compare_override = expected["__compare"] if acts_like_a_hash(compare_override): type_compare = combine(default_type_compare, compare_override) else: type_compare["hash"] = compare_override expected = dict((k, v) for (k, v) in expected.items() if k != "__compare") expected_return = {} actual_return = {} if type_compare["hash"] == "full": keys = set([]) keys.update(expected.keys()) keys.update(actual.keys()) else: keys = set(expected.keys()) for key in keys: if key in type_compare["dontcare_keys"]: result = cls.compare(DontCare(), actual.get(key, NotPresent), type_compare) else: result = cls.compare(expected.get(key, NotPresent), actual.get(key, NotPresent), type_compare) if result != "match": expected_sub, actual_sub = result expected_return[key] = expected_sub actual_return[key] = actual_sub if len(expected_return) == 0: return "match" else: return (expected_return, actual_return)
def list_compare(cls, expected, actual, type_compare, iter_type=list): default_type_compare = {"hash": "full", "ordered": True} type_compare = combine(default_type_compare, type_compare) if type(expected) == set and type(actual) == set: isset = True expected = list(expected) actual = list(actual) else: isset = False if type_compare["ordered"] and not isset: ret = cls.ordered_list_compare(expected, actual, type_compare, iter_type=iter_type) else: ret = cls.unordered_list_compare(expected, actual, type_compare, iter_type=iter_type) if ret == "match" or not isset: return ret else: ret_exp, ret_act = ret ret_exp = [x for x in ret_exp if x != "_"] ret_act = [x for x in ret_act if x != "_"] return (set(ret_exp), set(ret_act))
def list_compare(cls, expected, actual, type_compare, iter_type=list): default_type_compare =\ {'hash' : 'full', 'ordered' : True} type_compare =\ combine(default_type_compare, type_compare) if type(expected) == set and type(actual) == set: isset = True expected = list(expected) actual = list(actual) else: isset = False if type_compare['ordered'] and not isset: ret = cls.ordered_list_compare(expected, actual, type_compare, iter_type=iter_type) else: ret = cls.unordered_list_compare(expected, actual, type_compare, iter_type=iter_type) if ret == 'match' or not isset: return ret else: ret_exp, ret_act = ret ret_exp = [x for x in ret_exp if x != '_'] ret_act = [x for x in ret_act if x != '_'] return (set(ret_exp), set(ret_act))
def compare(cls, expected, actual, type_compare=None): ''' Compare two arguments against each other. If they are dicts or lists, recursively compare their components. Return the difference. If there is no difference, return the string 'match'. The third, optional argument is type_compare, which gives compare some information about how it should do matching. The value may be either a string or a dictionary. If it is a dictionary, the two keys are "hash" and "ordered". If type_compare is a string, the value is treated as the value for "hash". The hash key may either be "full" or "existing". Full means that two dictionaries must match entirely. Existing means that only the keys in the first dictionary must match in the second dictionary (ie. the keys that are only in the second dictionary are ignored). The ordered key may be either True or False. If it is True, lists that are compared against each other are expected to be ordered the same way. If it is False, lists that are compared against each other are expected to have the same elements, but in any order. hash defaults to "full", and ordered defaults to True. The hash comparison mode may be overridden in a sub-hash, by specifying a special key "__compare". The mode names are the same - "full" and "existing" ''' if type_compare is None: type_compare = {} elif isinstance(type_compare, str): type_compare = {'hash' : type_compare, 'ordered' : True} default_type_compare = {'hash' : 'full', 'ordered' : True} type_compare =\ combine(default_type_compare, type_compare) if type(expected) == DontCare: if expected.compare_with(actual): return 'match' else: return ("dontcare: %s" % expected.rule, actual) elif (type(expected) == pattern_type and isinstance(actual, six.string_types)): match = expected.match(actual) if match: return 'match' else: return ('regex: %s' % expected.pattern, actual) elif (type(expected).__name__ == 'ParsingHint'): return cls.compare( expected.payload, expected.parse(actual), type_compare) elif (acts_like_a_hash(expected) and acts_like_a_hash(actual)): return cls.hash_compare(expected, actual, type_compare) elif (isinstance(expected, tuple) and isinstance(actual, tuple)): return cls.list_compare(expected, actual, type_compare, iter_type=tuple) elif (acts_like_a_list(expected) and acts_like_a_list(actual)): return cls.list_compare(expected, actual, type_compare, iter_type=list) else: if expected == actual: return 'match' else: return (expected, actual)