def test_duplicates(self): # Three of the exact-same differences. differences = [Extra('xxx'), Extra('xxx'), Extra('xxx')] # Only allow one of them. with self.assertRaises(ValidationError) as cm: allowed = [Extra('xxx')] with allowed_specific(allowed): raise ValidationError(differences) actual = list(cm.exception.differences) expected = [Extra('xxx'), Extra('xxx')] # Expect two remaining. self.assertEqual(actual, expected) # Only allow two of them. with self.assertRaises(ValidationError) as cm: allowed = [Extra('xxx'), Extra('xxx')] with allowed_specific(allowed): raise ValidationError(differences) actual = list(cm.exception.differences) expected = [Extra('xxx')] # Expect one remaining. self.assertEqual(actual, expected) # Allow all three. allowed = [Extra('xxx'), Extra('xxx'), Extra('xxx')] with allowed_specific(allowed): raise ValidationError(differences)
def test_dict_with_predicates(self): """Ellipsis wildcard key matches all, treats as a single group.""" differences = { 'foo': Extra('xxx'), 'bar': [Extra('yyy'), Missing('yyy')], 'baz': [Extra('zzz'), Missing('zzz')], } allowed = { lambda x: x.startswith('ba'): [ Extra('yyy'), Extra('zzz'), ], } with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = cm.exception.differences expected = { 'foo': Extra('xxx'), 'bar': Missing('yyy'), 'baz': Missing('zzz'), } self.assertEqual(actual, expected)
def test_dict_and_dict(self): differences = {'foo': Extra('xxx'), 'bar': [Extra('xxx'), Missing('yyy')]} allowed = {'bar': Extra('xxx')} with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = cm.exception.differences expected = {'foo': Extra('xxx'), 'bar': Missing('yyy')} self.assertEqual(actual, expected)
def test_list_and_diff(self): differences = [Extra('xxx'), Missing('yyy')] allowed = Extra('xxx') # <- Single diff, not in a container. with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = list(cm.exception.differences) expected = [Missing('yyy')] self.assertEqual(actual, expected)
def test_list_and_list(self): differences = [Extra('xxx'), Missing('yyy')] allowed = [Extra('xxx')] expected = [Missing('yyy')] with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = list(cm.exception.differences) self.assertEqual(actual, expected)
def test_dict_and_list(self): """List of allowed differences applied to each group separately.""" differences = {'foo': Extra('xxx'), 'bar': [Extra('xxx'), Missing('yyy')]} allowed = [Extra('xxx')] with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = cm.exception.differences expected = {'bar': Missing('yyy')} self.assertEqual(actual, expected)
def test_combination_of_cases(self): """This is a bit of an integration test.""" differences = { 'foo': [Extra('xxx'), Missing('yyy')], 'bar': [Extra('xxx')], 'baz': [Extra('xxx'), Missing('yyy'), Extra('zzz')], } #allowed = {Ellipsis: [Extra('xxx'), Missing('yyy')]} allowed = [Extra('xxx'), Missing('yyy')] with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = cm.exception.differences self.assertEqual(actual, {'baz': Extra('zzz')})
def test_dict_global_wildcard_predicate(self): """Ellipsis wildcard key matches all, treats as a single group.""" differences = {'foo': Extra('xxx'), 'bar': [Extra('xxx'), Missing('yyy')]} allowed = {Ellipsis: Extra('xxx')} with self.assertRaises(ValidationError) as cm: with allowed_specific(allowed): raise ValidationError(differences) actual = cm.exception.differences # Actual result can vary with unordered dictionaries. if len(actual) == 1: expected = {'bar': [Extra('xxx'), Missing('yyy')]} else: expected = {'foo': Extra('xxx'), 'bar': Missing('yyy')} self.assertEqual(actual, expected)
def test_predicate_collision(self): """Ellipsis wildcard key matches all, treats as a single group.""" differences = { 'foo': Extra('xxx'), 'bar': [Extra('yyy'), Missing('yyy')], } def allow1(x): return x.startswith('ba') def allow2(x): return x == 'bar' allowed = { allow1: Extra('yyy'), allow2: Missing('yyy'), } regex = ("the key 'bar' matches multiple predicates: " "allow[12], allow[12]") with self.assertRaisesRegex(KeyError, regex): with allowed_specific(allowed): raise ValidationError(differences)
def test_integration_examples(self): # Test allowance of +/- 2 OR +/- 6%. with self.assertRaises(ValidationError) as cm: differences = [ Deviation(+2, 1), # 200% Deviation(+4, 8), # 50% Deviation(+8, 32), # 25% ] with allowed_deviation(2) | allowed_percent(0.25): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Deviation(+4, 8)]) # Test missing-type AND matching-value. with self.assertRaises(ValidationError) as cm: differences = [ Missing('A'), Missing('B'), Extra('C'), ] with allowed_missing() & allowed_args(lambda x: x == 'A'): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Missing('B'), Extra('C')]) # Test missing-type OR allowed-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Extra('C'), Missing('D'), ] with allowed_limit(1) | allowed_missing(): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('C')]) # Test missing-type AND allowed-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Missing('C'), ] with allowed_limit(1) & allowed_missing(): # Allows only 1 missing. raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('A'), Missing('C')]) # Test missing-type OR allowed-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Extra('C'), Missing('D'), ] with allowed_limit(1) | allowed_specific(Extra('A')): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('C'), Missing('D')])
def test_all_allowed(self): differences = {'foo': Extra('xxx'), 'bar': Missing('yyy')} allowed = {'foo': Extra('xxx'), 'bar': Missing('yyy')} with allowed_specific(allowed): # <- Allows all differences, no error! raise ValidationError(differences)
def test_excess_allowed(self): diffs = [Extra('xxx')] allowed = [Extra('xxx'), Missing('yyy')] # <- More allowed than with allowed_specific(allowed): # are actually found. raise ValidationError(diffs)