def test_specified_scopes(self): # list vs difference, scope differences = { 'a': [Missing('X'), Missing('X')], 'b': [Missing('Y'), Missing('X')], } acceptance = AcceptedDifferences( { 'a': [Missing('X')], 'b': [Missing('Y')] }, scope='element', # <- Element-wise scope. ) expected = {'b': Missing('X')} self.assertAcceptance(differences, acceptance, expected) acceptance = AcceptedDifferences( { 'a': Missing('X'), 'b': Missing('Y') }, scope='group', # <- Group-wise scope. ) expected = {'a': Missing('X'), 'b': Missing('X')} self.assertAcceptance(differences, acceptance, expected)
def test_nonremovable_containers(self): """Allowance containers with no remove() method should be converted to lists. """ # Mapping vs iter. differences = { 'a': iter([Missing('X'), Missing('X')]), 'b': iter([Missing('Y'), Missing('X')]), } acceptance = AcceptedDifferences(iter([Missing('X'), Missing('Y')])) expected = {'a': Missing('X')} self.assertAcceptance(differences, acceptance, expected) # Defaults to element-wise scope. differences = { 'a': iter([Missing('X'), Missing('X')]), 'b': iter([Missing('Y'), Missing('X')]), } acceptance = AcceptedDifferences({'a': Missing('X'), 'b': Missing('Y')}) expected = {'b': Missing('X')} self.assertAcceptance(differences, acceptance, expected) # Defaults to group-wise scope. differences = { 'a': iter([Missing('X'), Missing('X')]), 'b': iter([Missing('Y'), Missing('X')]), } acceptance = AcceptedDifferences({'a': iter([Missing('X')]), 'b': tuple([Missing('Y')])}) expected = {'a': Missing('X'), 'b': Missing('X')} self.assertAcceptance(differences, acceptance, expected)
def test_precedence_relations(self): """Should implement specified precedence order for element (e), group (g), and whole (w) scoped acceptances: e < ge < g < we < wge < wg < w """ element = AcceptedDifferences([Missing(1)], scope='element') group = AcceptedDifferences([Missing(1)], scope='group') whole = AcceptedDifferences([Missing(1)], scope='whole') self.assertPrecedenceLess( element, (group | element), ) self.assertPrecedenceLess( (group | element), group, ) self.assertPrecedenceLess( group, (whole | element), ) self.assertPrecedenceLess( (whole | element), (whole | group | element), ) self.assertPrecedenceLess( (whole | group | element), (whole | group), ) self.assertPrecedenceLess( (whole | group), whole, )
def test_difference_vs_list(self): differences = Missing('X') acceptance = AcceptedDifferences([Missing('Y'), Missing('Z')]) expected = [Missing('X')] self.assertAcceptance(differences, acceptance, expected) differences = Missing('X') acceptance = AcceptedDifferences([Missing('X'), Missing('Y')]) with acceptance: # <- No error, all diffs accepted raise ValidationError(differences)
def test_difference_vs_type(self): differences = Missing('X') acceptance = AcceptedDifferences(Extra) expected = [Missing('X')] self.assertAcceptance(differences, acceptance, expected) differences = Missing('X') acceptance = AcceptedDifferences(Missing) with acceptance: # <- No error, all diffs accepted raise ValidationError(differences)
def test_nonmapping_vs_mapping(self): """A mapping accpetance will not accept any non-mapping differences.""" differences = [Missing('Y'), Extra('X')] acceptance = AcceptedDifferences({'a': Extra('X')}) self.assertAcceptance(differences, acceptance, differences) differences = Extra('X') acceptance = AcceptedDifferences({'a': Extra('X')}) self.assertAcceptance(differences, acceptance, [differences])
def test_mapping_vs_list(self): differences = { 'a': [Missing('X')], 'b': [Missing('Y'), Missing('X')], 'c': [Missing('Y'), Missing('X'), Missing('X')], } acceptance = AcceptedDifferences([Missing('X')]) expected = {'b': Missing('Y'), 'c': [Missing('Y'), Missing('X')]} self.assertAcceptance(differences, acceptance, expected) acceptance = AcceptedDifferences([Missing('X')], scope='element') expected = {'b': Missing('Y'), 'c': Missing('Y')} self.assertAcceptance(differences, acceptance, expected)
def test_mapping_vs_mapping(self): differences = { 'a': [Missing('X'), Missing('X')], 'b': [Missing('X'), Missing('Y'), Missing('Y')], } # Defaults to element-wise scope. acceptance = AcceptedDifferences({'a': Missing('X'), 'b': Missing('Y')}) expected = {'b': Missing('X')} self.assertAcceptance(differences, acceptance, expected) # Defaults to group-wise scope. acceptance = AcceptedDifferences({'a': [Missing('X')], 'b': [Missing('Y')]}) expected = {'a': Missing('X'), 'b': [Missing('X'), Missing('Y')]} self.assertAcceptance(differences, acceptance, expected)
def test_list_vs_list(self): differences = [Missing('X'), Missing('Y'), Missing('X')] acceptance = AcceptedDifferences([Missing('Y'), Missing('X') ]) # <- Accept list of differences. expected = [Missing('X')] self.assertAcceptance(differences, acceptance, expected)
def test_accepted_invalid(self): differences = [Invalid('X'), Invalid('Y'), Extra('Z')] with self.assertRaises(ValidationError) as cm: with AcceptedDifferences(Invalid): # <- Apply acceptance! raise ValidationError(differences) remaining_diffs = cm.exception.differences self.assertEqual(list(remaining_diffs), [Extra('Z')])
def test_mapping_vs_difference(self): differences = { 'a': [Missing('X')], 'b': [Missing('Y'), Missing('X')], } acceptance = AcceptedDifferences(Missing('X')) expected = {'b': Missing('Y')} self.assertAcceptance(differences, acceptance, 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')], } #accepted = {Ellipsis: [Extra('xxx'), Missing('yyy')]} accepted = [Extra('xxx'), Missing('yyy')] with self.assertRaises(ValidationError) as cm: with AcceptedDifferences(accepted): raise ValidationError(differences) actual = cm.exception.differences self.assertEqual(actual, {'baz': Extra('zzz')})
def test_repr(self): acceptance = AcceptedDifferences(Extra) self.assertEqual(repr(acceptance), 'AcceptedDifferences(Extra)') acceptance = AcceptedDifferences(Extra('foo')) self.assertEqual(repr(acceptance), "AcceptedDifferences(Extra('foo'))") acceptance = AcceptedDifferences([Extra('foo')], scope='element') self.assertEqual(repr(acceptance), "AcceptedDifferences([Extra('foo')], scope='element')") acceptance = AcceptedDifferences([Extra('foo')]) # Defaults to 'group' scope. self.assertEqual(repr(acceptance), "AcceptedDifferences([Extra('foo')])") acceptance = AcceptedDifferences([Extra('foo')], scope='whole') self.assertEqual(repr(acceptance), "AcceptedDifferences([Extra('foo')], scope='whole')") acceptance = AcceptedDifferences({'a': Extra('foo')}) self.assertEqual(repr(acceptance), "AcceptedDifferences({'a': Extra('foo')})")
def test_scope(self): acceptance = AcceptedDifferences(Extra) self.assertEqual(acceptance.scope, set(['element'])) acceptance = AcceptedDifferences(Extra('foo')) self.assertEqual(acceptance.scope, set(['element'])) acceptance = AcceptedDifferences([Extra('foo')], scope='element') self.assertEqual(acceptance.scope, set(['element'])) acceptance = AcceptedDifferences([Extra('foo')]) # Defaults to 'group' scope. self.assertEqual(acceptance.scope, set(['group'])) acceptance = AcceptedDifferences([Extra('foo')], scope='whole') self.assertEqual(acceptance.scope, set(['whole'])) # Mapping of differences defaults to 'group' scope, too. acceptance = AcceptedDifferences({'a': Extra('foo')}) self.assertEqual(acceptance.scope, set(['group']))
def test_priority(self): """Priority is determined by scope.""" acceptance = AcceptedDifferences(Extra) self.assertEqual(acceptance.priority, 4) acceptance = AcceptedDifferences(Extra('foo')) self.assertEqual(acceptance.priority, 4) acceptance = AcceptedDifferences([Extra('foo')], scope='element') self.assertEqual(acceptance.priority, 4) acceptance = AcceptedDifferences([Extra('foo') ]) # Defaults to 'group' scope. self.assertEqual(acceptance.priority, 32) acceptance = AcceptedDifferences([Extra('foo')], scope='whole') self.assertEqual(acceptance.priority, 256) # Mapping of differences defaults to 'group' scope, too. acceptance = AcceptedDifferences({'a': Extra('foo')}) self.assertEqual(acceptance.priority, 32)
def test_list_vs_type(self): differences = [Missing('X'), Missing('Y'), Extra('X')] acceptance = AcceptedDifferences(Missing) expected = [Extra('X')] self.assertAcceptance(differences, acceptance, expected)
def test_integration_examples(self): # Test acceptance of +/- 2 OR +/- 6%. with self.assertRaises(ValidationError) as cm: differences = [ Deviation(+2, 1), # 200% Deviation(+4, 8), # 50% Deviation(+8, 32), # 25% ] with AcceptedTolerance(2) | AcceptedPercent(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 AcceptedDifferences(Missing) & AcceptedArgs( lambda x: x == 'A'): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Missing('B'), Extra('C')]) # Test missing-type OR accepted-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Extra('C'), Missing('D'), ] with AcceptedCount(1) | AcceptedDifferences(Missing): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('C')]) # Test missing-type AND accepted-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Missing('C'), ] with AcceptedCount(1) & AcceptedDifferences( Missing): # Accepts only 1 missing. raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('A'), Missing('C')]) # Test missing-type OR accepted-limit. with self.assertRaises(ValidationError) as cm: differences = [ Extra('A'), Missing('B'), Extra('C'), Missing('D'), ] with AcceptedCount(1) | AcceptedDifferences(Extra('A')): raise ValidationError(differences) remaining = cm.exception.differences self.assertEqual(remaining, [Extra('C'), Missing('D')])