def test_none_vs_numeric(self): diff = _xgetdiff(None, 6) # For None vs non-zero, self.assertEqual(diff, xDeviation(-6, 6)) # difference is calculated # as 0 - other. diff = _xgetdiff(None, 0) # For None vs zero, self.assertEqual(diff, xDeviation(None, 0)) # difference remains None.
def test_keywords(self): """Keywords should be passed to diff objet.""" diff = _xgetdiff(5, 6, col1='AAA') self.assertEqual(diff, xDeviation(-1, 6, col1='AAA')) diff = _xgetdiff('a', 6, col1='AAA') self.assertEqual(diff, xInvalid('a', 6, col1='AAA')) diff = _xgetdiff(_xNOTFOUND, 6, col1='AAA') self.assertEqual(diff, xDeviation(-6, 6, col1='AAA'))
def test_required_integer(self): data = set([11, 8]) integer_val = 11 result = _compare_other(data, integer_val) self.assertEqual(result, [xDeviation(-3, integer_val)]) data = {'foo': 11, 'bar': 8} integer_val = 11 result = _compare_other(data, integer_val) self.assertEqual(result, {'bar': xDeviation(-3, integer_val)})
def test_repr(self): diff = xDeviation(1, 100) # Simple. self.assertEqual("xDeviation(+1, 100)", repr(diff)) diff = xDeviation(-1, 100) # Simple negative. self.assertEqual("xDeviation(-1, 100)", repr(diff)) diff = xDeviation(3, 50, col1='a', col2='b') # Using kwds. self.assertRegex(repr(diff), "xDeviation\(\+3, 50, col1=u?'a', col2=u?'b'\)") diff = xDeviation(1, None, col1='a') # None reference. self.assertRegex(repr(diff), "xDeviation\(\+1, None, col1=u?'a'\)")
def test_group_and_filter(self): """Only groupby fields should appear in diff errors (kwds-filters should be omitted). """ with self.assertRaises(DataError) as cm: self.assertSubjectSum('value', ['label1'], label2='y') differences = cm.exception.differences expected = [ xDeviation(+1, 20, label1='a'), xDeviation(-1, 40, label1='b') ] super(DataTestCase, self).assertEqual(set(differences), set(expected))
def test_failing_implicit_reference(self): self.subject = self.src2_records # <- src1 != src2 self.reference = self.src1_totals with self.assertRaises(DataError) as cm: self.assertSubjectSum('value', ['label1']) differences = cm.exception.differences expected = [ xDeviation(+1, 65, label1='a'), xDeviation(-1, 70, label1='b') ] super(DataTestCase, self).assertEqual(set(differences), set(expected))
def test_failing_explicit_dict(self): self.subject = self.src2_records # <- src1 != src2 with self.assertRaises(DataError) as cm: required = {'a': 65, 'b': 70} self.assertSubjectSum('value', ['label1'], required) differences = cm.exception.differences expected = [ xDeviation(+1, 65, label1='a'), xDeviation(-1, 70, label1='b') ] super(DataTestCase, self).assertEqual(set(differences), set(expected))
def test_nested_acceptances(self): """A quick integration test to make sure acceptances nest as required. """ with allow_only(xDeviation(-4, 70, label1='b')): # <- specified diff only with allow_deviation(3): # <- tolerance of +/- 3 with allow_percent_deviation(0.02): # <- tolerance of +/- 2% differences = [ xDeviation(+3, 65, label1='a'), xDeviation(-4, 70, label1='b'), xDeviation(+5, 250, label1='c'), ] raise DataError('example error', differences)
def test_tolerance_syntax(self): differences = [ xDeviation(-1, 10, label='aaa'), xDeviation(+3, 10, label='bbb'), # <- Not in allowed range. ] with self.assertRaises(DataError) as cm: with allow_deviation(2, 'example message'): # <- Allows +/- 2. raise DataError('example error', differences) result_string = str(cm.exception) self.assertTrue( result_string.startswith('example message: example error')) result_diffs = list(cm.exception.differences) self.assertEqual([xDeviation(+3, 10, label='bbb')], result_diffs)
def test_lowerupper_syntax(self): differences = [ xDeviation(-1, 10, label='aaa'), # <- Not in allowed range. xDeviation(+3, 10, label='bbb'), ] with self.assertRaises(DataError) as cm: with allow_percent_deviation( 0.0, 0.3, 'example message'): # <- Allows from 0 to 30%. raise DataError('example error', differences) result_string = str(cm.exception) self.assertTrue( result_string.startswith('example message: example error')) result_diffs = list(cm.exception.differences) self.assertEqual([xDeviation(-1, 10, label='aaa')], result_diffs)
def test_compare_numbers(self): a = CompareDict({'aaa': 1, 'bbb': 2, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 2, 'ccc': 3, 'ddd': 4}, 'foo') self.assertEqual([], a.compare(b), ('When there is no difference, ' 'compare should return an empty ' 'list.')) a = CompareDict({'aaa': 1, 'bbb': 2, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 2.5, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(-0.5, 2.5, foo='bbb')] self.assertEqual(expected, a.compare(b)) # 'b' is zero in self/subject. a = CompareDict({'aaa': 1, 'bbb': 0, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 2.5, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(-2.5, 2.5, foo='bbb')] self.assertEqual(expected, a.compare(b)) # 'bbb' is zero in other/reference. a = CompareDict({'aaa': 1, 'bbb': 2, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 0, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(+2, 0, foo='bbb')] self.assertEqual(expected, a.compare(b)) # 'bbb' is missing from self/subject. a = CompareDict({'aaa': 1, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 2.5, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(-2.5, 2.5, foo='bbb')] # <- QUESTION: This self.assertEqual(expected, a.compare(b)) # deviation looks the # same as 0 vs 2.5. # Is this OK? # 'bbb' is missing from a/subject. a = CompareDict({'aaa': 1, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 0, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(None, 0, foo='bbb')] self.assertEqual(expected, a.compare(b)) # 'bbb' is empty string in a/subject. a = CompareDict({'aaa': 1, 'bbb': '', 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'bbb': 0, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation('', 0, foo='bbb')] self.assertEqual(expected, a.compare(b)) # 'bbb' is missing from b/reference. a = CompareDict({'aaa': 1, 'bbb': 0, 'ccc': 3, 'ddd': 4}, 'foo') b = CompareDict({'aaa': 1, 'ccc': 3, 'ddd': 4}, 'foo') expected = [xDeviation(0, None, foo='bbb')] self.assertEqual(expected, a.compare(b)) # Test coersion of *other*. a = CompareDict({'aaa': 1, 'bbb': 2, 'ccc': 3, 'ddd': 4}, 'foo') b = {'aaa': 1, 'bbb': 2.5, 'ccc': 3, 'ddd': 4} expected = [xDeviation(-0.5, 2.5, foo='bbb')] self.assertEqual(expected, a.compare(b))
def test_dict_v_dict_numeric_fail(self): with self.assertRaises(DataError) as cm: first = {'foo': 1, 'bar': 2, 'baz': 2} second = {'foo': 1, 'bar': 2, 'baz': 3} self.assertEqual(first, second) differences = cm.exception.differences super(DataTestCase, self).assertEqual(differences, [xDeviation(-1, 3, _0='baz')])
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([ xInvalid(2, 'y', foo='aaa'), xDeviation(-1, 4, foo='bbb'), xInvalid('z', 5, foo='ccc'), ]) self.assertEqual(expected, set(a.compare(b)))
def test_is_common(self): """If requirement is common it should be omitted from xInvalid difference (but not from xDeviation differences). """ diff = _xgetdiff('a', 6, is_common=True) self.assertEqual(diff, xInvalid('a')) diff = _xgetdiff(_xNOTFOUND, 6, is_common=True) self.assertEqual(diff, xDeviation(-6, 6))
def test_notfound_comparisons(self): diff = _xgetdiff('a', _xNOTFOUND) self.assertEqual(diff, xExtra('a')) diff = _xgetdiff(_xNOTFOUND, 'b') self.assertEqual(diff, xMissing('b')) # For numeric comparisons, _xNOTFOUND behaves like None. diff = _xgetdiff(5, _xNOTFOUND) self.assertEqual(diff, xDeviation(+5, None)) diff = _xgetdiff(0, _xNOTFOUND) self.assertEqual(diff, xDeviation(0, None)) diff = _xgetdiff(_xNOTFOUND, 6) self.assertEqual(diff, xDeviation(-6, 6)) # <- Assymetric behavior # (see None vs numeric)! diff = _xgetdiff(_xNOTFOUND, 0) self.assertEqual(diff, xDeviation(None, 0))
def test_empty_value_handling(self): # Test NoneType. with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(None, 0)]) with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(0, None)]) # Test empty string. with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation('', 0)]) with allow_percent_deviation(0): # <- Pass without failure. raise DataError('example error', [xDeviation(0, '')]) # Test NaN (not a number) values. with self.assertRaises( DataError): # <- NaN values should not be caught! with allow_percent_deviation(0): raise DataError('example error', [xDeviation(float('nan'), 0)]) with self.assertRaises( DataError): # <- NaN values should not be caught! with allow_percent_deviation(0): raise DataError('example error', [xDeviation(0, float('nan'))])
def test_single_value_acceptance(self): differences = [ xDeviation(+2.9, 10, label='aaa'), # <- Not accepted. xDeviation(+3.0, 10, label='bbb'), xDeviation(+3.0, 5, label='ccc'), xDeviation(+3.1, 10, label='ddd'), # <- Not accepted. ] with self.assertRaises(DataError) as cm: with allow_deviation(3, 3): # <- Allows +3 only. raise DataError('example error', differences) result_diffs = set(cm.exception.differences) expected_diffs = set([ xDeviation(+2.9, 10, label='aaa'), xDeviation(+3.1, 10, label='ddd'), ]) self.assertEqual(expected_diffs, result_diffs)
def test_kwds_handling(self): differences = [ xDeviation(-1, 10, label='aaa'), xDeviation(+2, 10, label='aaa'), xDeviation(+2, 10, label='bbb'), xDeviation(+3, 10, label='aaa'), ] with self.assertRaises(DataError) as cm: with allow_percent_deviation(0.2, 'example message', label='aaa'): # <- Allows +/- 20%. raise DataError('example error', differences) result_set = set(cm.exception.differences) expected_set = set([ xDeviation(+2, 10, label='bbb'), # <- Keyword value not 'aaa'. xDeviation(+3, 10, label='aaa'), # <- Not in allowed range. ]) self.assertEqual(expected_set, result_set)
def test_str(self): diff = xDeviation(5, 75, col1='a') self.assertEqual(str(diff), repr(diff))
def test_instantiation(self): xDeviation(1, 100) # Pass without error.
def test_empty_value_handling(self): with self.assertRaises(ValueError): xDeviation(0, 100) # Zero diff. xDeviation(0, None) xDeviation(+5, None) xDeviation(None, 0) with self.assertRaises(ValueError): xDeviation(None, 5) # Should be xDeviation(-5, 5) xDeviation(0, '') xDeviation(+5, '') xDeviation('', 0) with self.assertRaises(ValueError): xDeviation('', 5) # Should be xDeviation(-5, 5) xDeviation(0, float('nan')) xDeviation(+5, float('nan')) xDeviation(float('nan'), 0) with self.assertRaises(ValueError): xDeviation(float('nan'), 5) # Should be xDeviation(-5, 5) with self.assertRaises(ValueError): xDeviation(0, 1) # Just no. # False is treated the same as zero. xDeviation(+5, 0) xDeviation(+5, False) with self.assertRaises(ValueError): xDeviation(0, 0) with self.assertRaises(ValueError): xDeviation(0, False) with self.assertRaises(ValueError): xDeviation(False, 0) with self.assertRaises(ValueError): xDeviation(False, 5) # Should be xDeviation(-5, 5)
def test_numeric_vs_none(self): diff = _xgetdiff(5, None) self.assertEqual(diff, xDeviation(+5, None)) diff = _xgetdiff(0, None) self.assertEqual(diff, xDeviation(+0, None))
def test_numeric_vs_numeric(self): diff = _xgetdiff(5, 6) self.assertEqual(diff, xDeviation(-1, 6))
def test_repr_eval(self): diff = xDeviation(+1, 100) self.assertEqual(diff, eval(repr(diff))) # Test __repr__ eval diff = xDeviation(-1, 100, col4='foo', col5='bar') self.assertEqual(diff, eval(repr(diff))) # Test __repr__ eval
def test_eq(self): diff1 = xDeviation(1, 100) diff2 = xDeviation(1, 100) self.assertEqual(diff1, diff2) diff1 = xDeviation(1.0, 100.0) diff2 = xDeviation(1.0, 100.0) self.assertEqual(diff1, diff2) diff1 = xDeviation(1.0, 100) diff2 = xDeviation(1, 100) self.assertEqual(diff1, diff2) diff1 = xDeviation(1, 100.0) diff2 = xDeviation(1, 100) self.assertEqual(diff1, diff2) diff1 = xDeviation(1, 100, foo='aaa', bar='bbb') diff2 = xDeviation(1, 100, bar='bbb', foo='aaa') self.assertEqual(diff1, diff2) diff1 = xDeviation(1, 100) diff2 = xDeviation(1, 250) self.assertNotEqual(diff1, diff2) diff1 = xDeviation(+1, 100) diff2 = "xDeviation(+1, 100)" self.assertNotEqual(diff1, diff2)
def test_hash(self): diff = xDeviation(1, 100, col1='a', col2='b') self.assertIsInstance(hash(diff), int)