def test_multiargument_callable(self): """Should unpack arguments if callable expects multiple parameters. """ data = set([(5, 2), (1, 4), (10, 8)]) required = lambda x, y: x > y # <- Multiple positional parameters. result = _compare_other(data, required) self.assertEqual(result, [Invalid((1, 4))]) required = lambda *z: z[0] > z[1] # <- Variable parameters. result = _compare_other(data, required) self.assertEqual(result, [Invalid((1, 4))]) required = lambda a: a[0] > a[1] # <- Single parameter. result = _compare_other(data, required) self.assertEqual(result, [Invalid((1, 4))]) data = [[], [], []] required = lambda x, y: x > y # <- Multiple positional params. with self.assertRaisesRegex(TypeError, 'missing 2|0 given'): _compare_other(data, required) data = (5, 2) required = lambda x, y: x > y # <- Multiple positional params. with self.assertRaisesRegex(TypeError, 'missing 1|1 given'): _compare_other(data, required) data = set([(5, 2), (1, 4), (10, 8)]) # Args and params match def required(x, y): # but function raises raise TypeError('other error') # some other TypeError. with self.assertRaisesRegex(TypeError, 'other error'): _compare_other(data, required)
def test_compare_mixed_types(self): a = CompareDict({'aaa': 2, 'bbb': 3, 'ccc': 'z'}, 'foo') b = CompareDict({'aaa': 'y', 'bbb': 4.0, 'ccc': 5}, 'foo') expected = set([ Invalid(2, 'y', foo='aaa'), Deviation(-1, 4, foo='bbb'), Invalid('z', 5, foo='ccc'), ]) self.assertEqual(expected, set(a.compare(b)))
def test_failing_explicit_callable(self): self.subject = self.src2_records with self.assertRaises(DataError) as cm: required = lambda x: x in (65, 70) self.assertSubjectSum('value', ['label1'], required) differences = cm.exception.differences expected = [Invalid(Decimal(66), label1='a'), Invalid(Decimal(69), label1='b')] #expected = [Invalid(66, label1='a'), # Invalid(69, label1='b')] super(DataTestCase, self).assertEqual(set(differences), set(expected))
def test_error_condition(self): """If callable raises an Exception, the result is counted as False. """ isalpha = lambda x: x.isalpha() # Raises TypeError if given # a non-string value. data = set(['a', 'b', 3, '4']) # <- Value 3 raises an error. result = _compare_other(data, isalpha) expected = [Invalid(3), Invalid('4')] self.assertEqual(set(result), set(expected)) data = 10 result = _compare_other(data, isalpha) self.assertEqual(result, [Invalid(data)])
def test_str_or_noniterable(self): isalpha = lambda x: x.isalpha() data = 'ABCD' result = _compare_other(data, isalpha) self.assertEqual(result, []) data = '!@#$' result = _compare_other(data, isalpha) self.assertEqual(result, [Invalid('!@#$')]) data = 5 required = lambda x: 10 < x result = _compare_other(data, required) self.assertEqual(result, [Invalid(5)])
def test_invalid(self): with self.assertRaises(DataError) as cm: required = lambda x: x in ('a', 'b') self.assertSubjectSet('label1', required) differences = cm.exception.differences self.assertEqual(differences, [Invalid('c')])
def test_compareset_v_callable_fail(self): with self.assertRaises(DataError) as cm: first = CompareSet([1, 2, 3, 4, 5, 6, 7]) second = lambda x: x <= 6 self.assertEqual(first, second) differences = cm.exception.differences super(DataTestCase, self).assertEqual(differences, [Invalid(7)])
def test_iterable(self): isalpha = lambda x: x.isalpha() data = iter(['a', 'b', 'c']) result = _compare_other(data, isalpha) self.assertEqual(result, []) data = iter(['a', 'b', 'c', '9']) result = _compare_other(data, isalpha) self.assertEqual(result, [Invalid('9')])
def test_sequence(self): isalpha = lambda x: x.isalpha() data = ['a', 'b', 'c'] result = _compare_other(data, isalpha) self.assertEqual(result, {}) data = ['a', 'b', 'c', '9'] result = _compare_other(data, isalpha) self.assertEqual(result, {3: Invalid('9')})
def test_mapping(self): isalpha = lambda x: x.isalpha() data = {'AAA': 'a', 'BBB': 'b', 'CCC': 'c'} result = _compare_other(data, isalpha) self.assertEqual(result, {}) data = {'AAA': 'a', 'BBB': 'b', 'CCC': 'c', 'DDD': '3'} result = _compare_other(data, isalpha) self.assertEqual(result, {'DDD': Invalid('3')})
def test_set(self): isalpha = lambda x: x.isalpha() data = set(['a', 'b', 'c']) result = _compare_other(data, isalpha) self.assertEqual(result, []) data = set(['a', 'b', 'c', '3']) result = _compare_other(data, isalpha) self.assertEqual(result, [Invalid('3')])
def test_required_other(self): """When *required* is a string or other object, _compare_other() should be called.""" with self.assertRaises(DataError) as cm: required = lambda x: x.isupper() data = ['AAA', 'BBB', 'ccc', 'DDD'] self.assertValid(data, required) differences = cm.exception.differences self.assertEqual = super(DataTestCase, self).assertEqual self.assertEqual(differences, {2: Invalid('ccc')})
def test_required_sequence(self): """When *required* is a sequence, _compare_sequence() should be called.""" with self.assertRaises(DataError) as cm: required = ['a', 2, 'c', 4] data = ['a', 2, 'x', 3] self.assertValid(data, required) differences = cm.exception.differences self.assertEqual = super(DataTestCase, self).assertEqual self.assertEqual(differences, {2: Invalid('x', 'c'), 3: Deviation(-1, 4)})
def test_compare_function(self): a = CompareDict({'aaa': 'x', 'bbb': 'y', 'ccc': 'z'}, 'foo') # All True. result = a.compare(lambda x: len(x) == 1) self.assertEqual([], result) # Some False. result = a.compare(lambda a: a in ('x', 'y')) expected = [Invalid('z', foo='ccc')] self.assertEqual(expected, result) # All True, multiple args. a = CompareDict({'aaa': (1, 2), 'bbb': (1, 3), 'ccc': (4, 8)}, 'foo') result = a.compare(lambda x, y: x < y) self.assertEqual([], result) # Some False, multiple args. a = CompareDict({'aaa': (1, 0), 'bbb': (1, 3), 'ccc': (3, 2)}, 'foo') result = a.compare(lambda x, y: x < y) expected = [Invalid((1, 0), foo='aaa'), Invalid((3, 2), foo='ccc')] self.assertEqual(expected, result)
def test_invalid(self): data = [('LABEL1', 'value'), ('a', '6'), ('b', '7')] self.subject = MinimalSource(data) with self.assertRaises(DataError) as cm: def lowercase(x): # <- Helper function!!! return x == x.lower() self.assertSubjectColumns(required=lowercase) # <- test assert differences = cm.exception.differences self.assertEqual(set(differences), set([Invalid('LABEL1')]))
def test_sequence(self): required = ['a', 'b', 'c'] data = ['a', 'b', 'c'] result = _compare_sequence(data, required) self.assertEqual(result, {}) data = ['a', 'b', 'c', 'd'] result = _compare_sequence(data, required) self.assertEqual(result, {3: Extra('d')}) data = ['a', 'b'] result = _compare_sequence(data, required) self.assertEqual(result, {2: Missing('c')}) data = ['a', 'x', 'c', 'y'] result = _compare_sequence(data, required) self.assertEqual(result, {1: Invalid('x', 'b'), 3: Extra('y')})
def wrapped(element): try: if isinstance(element, BaseElement): returned_value = function(element) else: returned_value = function(*element) except Exception: returned_value = False # Raised errors count as False. if returned_value == True: return None # <- EXIT! if returned_value == False: return Invalid(element) # <- EXIT! if isinstance(returned_value, BaseDifference): return returned_value # <- EXIT! callable_name = function.__name__ message = \ '{0!r} returned {1!r}, should return True, False or a difference instance' raise TypeError(message.format(callable_name, returned_value))
def _require_callable(data, function): if data is NOVALUE: return Invalid(None) # <- EXIT! def wrapped(element): try: if isinstance(element, BaseElement): returned_value = function(element) else: returned_value = function(*element) except Exception: returned_value = False # Raised errors count as False. if returned_value == True: return None # <- EXIT! if returned_value == False: return Invalid(element) # <- EXIT! if isinstance(returned_value, BaseDifference): return returned_value # <- EXIT! callable_name = function.__name__ message = \ '{0!r} returned {1!r}, should return True, False or a difference instance' raise TypeError(message.format(callable_name, returned_value)) if isinstance(data, BaseElement): return wrapped(data) # <- EXIT! results = (wrapped(elem) for elem in data) diffs = (diff for diff in results if diff) first_element, diffs = iterpeek(diffs) if first_element: # If not empty, return diffs. return diffs return None
def test_required_regex(self): data = set(['a1', 'b2', 'c3', 'd', 'e5']) regex = re.compile('[a-z][0-9]+') result = _compare_other(data, regex) self.assertEqual(result, [Invalid('d')])
def test_not_regex_failing(self): with self.assertRaises(DataError) as cm: self.assertSubjectNotRegex('label2', '^\d{1,2}$') differences = cm.exception.differences super(DataTestCase, self).assertEqual(differences, [Invalid('2')])
def test_required_string(self): data = set(['AAA', 'BBB']) string_val = 'AAA' result = _compare_other(data, string_val) self.assertEqual(result, [Invalid('BBB')])
def test_compare(self): a = CompareSet(['aaa', 'bbb', 'ddd']) b = CompareSet(['aaa', 'bbb', 'ccc']) expected = [Extra('ddd'), Missing('ccc')] self.assertEqual(expected, a.compare(b)) a = CompareSet(['aaa', 'bbb', 'ccc']) b = CompareSet(['aaa', 'bbb', 'ccc']) self.assertEqual([], a.compare(b), ('When there is no difference, ' 'compare should return an empty ' 'list.')) # Test callable other (all True). result = a.compare(lambda x: len(x) == 3) self.assertEqual([], result) # Test callable other (some False). result = a.compare(lambda x: x.startswith('b')) expected = set([Invalid('aaa'), Invalid('ccc')]) self.assertEqual(expected, set(result)) # Test callable other, multiple arguments (all True). a = CompareSet([(1, 1), (1, 2), (2, 1), (2, 2)]) result = a.compare(lambda x, y: x + y > 0) self.assertEqual([], result) # Test callable other, using single vararg (all True). a = CompareSet([(1, 1), (1, 2), (2, 1), (2, 2)]) result = a.compare(lambda *x: x[0] + x[1] > 0) self.assertEqual([], result) # Test callable other, multiple arguments (some False). a = CompareSet([(1, 1), (1, 2), (2, 1), (2, 2)]) result = a.compare(lambda x, y: x != y) expected = set([Invalid((1, 1)), Invalid((2, 2))]) self.assertEqual(expected, set(result)) # Test subset (less-than-or-equal). a = CompareSet(['aaa', 'bbb', 'ddd']) b = CompareSet(['aaa', 'bbb', 'ccc']) expected = [Extra('ddd')] self.assertEqual(expected, a.compare(b, op='<=')) # Test strict subset (less-than). a = CompareSet(['aaa', 'bbb']) b = CompareSet(['aaa', 'bbb', 'ccc']) self.assertEqual([], a.compare(b, op='<')) # Test strict subset (less-than) assertion violation. a = CompareSet(['aaa', 'bbb', 'ccc']) b = CompareSet(['aaa', 'bbb', 'ccc']) self.assertEqual([NotProperSubset()], a.compare(b, op='<')) # Test superset (greater-than-or-equal). a = CompareSet(['aaa', 'bbb', 'ccc']) b = CompareSet(['aaa', 'bbb', 'ddd']) expected = [Missing('ddd')] self.assertEqual(expected, a.compare(b, op='>=')) # Test superset subset (greater-than). a = CompareSet(['aaa', 'bbb', 'ccc']) b = CompareSet(['aaa', 'bbb']) self.assertEqual([], a.compare(b, op='>')) # Test superset subset (greater-than) assertion violation. a = CompareSet(['aaa', 'bbb', 'ccc']) b = CompareSet(['aaa', 'bbb', 'ccc']) self.assertEqual([NotProperSuperset()], a.compare(b, op='>'))
def test_compare_strings(self): a = CompareDict({'aaa': 'x', 'bbb': 'y', 'ccc': 'z'}, 'foo') b = CompareDict({'aaa': 'x', 'bbb': 'z', 'ccc': 'z'}, 'foo') expected = [Invalid('y', 'z', foo='bbb')] self.assertEqual(expected, a.compare(b))