• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from collections import deque
2import unittest
3
4
5class base_set:
6    def __init__(self, el):
7        self.el = el
8
9class myset(base_set):
10    def __contains__(self, el):
11        return self.el == el
12
13class seq(base_set):
14    def __getitem__(self, n):
15        return [self.el][n]
16
17class TestContains(unittest.TestCase):
18    def test_common_tests(self):
19        a = base_set(1)
20        b = myset(1)
21        c = seq(1)
22        self.assertIn(1, b)
23        self.assertNotIn(0, b)
24        self.assertIn(1, c)
25        self.assertNotIn(0, c)
26        self.assertRaises(TypeError, lambda: 1 in a)
27        self.assertRaises(TypeError, lambda: 1 not in a)
28
29        # test char in string
30        self.assertIn('c', 'abc')
31        self.assertNotIn('d', 'abc')
32
33        self.assertIn('', '')
34        self.assertIn('', 'abc')
35
36        self.assertRaises(TypeError, lambda: None in 'abc')
37
38    def test_builtin_sequence_types(self):
39        # a collection of tests on builtin sequence types
40        a = range(10)
41        for i in a:
42            self.assertIn(i, a)
43        self.assertNotIn(16, a)
44        self.assertNotIn(a, a)
45
46        a = tuple(a)
47        for i in a:
48            self.assertIn(i, a)
49        self.assertNotIn(16, a)
50        self.assertNotIn(a, a)
51
52        class Deviant1:
53            """Behaves strangely when compared
54
55            This class is designed to make sure that the contains code
56            works when the list is modified during the check.
57            """
58            aList = list(range(15))
59            def __eq__(self, other):
60                if other == 12:
61                    self.aList.remove(12)
62                    self.aList.remove(13)
63                    self.aList.remove(14)
64                return 0
65
66        self.assertNotIn(Deviant1(), Deviant1.aList)
67
68    def test_nonreflexive(self):
69        # containment and equality tests involving elements that are
70        # not necessarily equal to themselves
71
72        class MyNonReflexive(object):
73            def __eq__(self, other):
74                return False
75            def __hash__(self):
76                return 28
77
78        values = float('nan'), 1, None, 'abc', MyNonReflexive()
79        constructors = list, tuple, dict.fromkeys, set, frozenset, deque
80        for constructor in constructors:
81            container = constructor(values)
82            for elem in container:
83                self.assertIn(elem, container)
84            self.assertTrue(container == constructor(values))
85            self.assertTrue(container == container)
86
87    def test_block_fallback(self):
88        # blocking fallback with __contains__ = None
89        class ByContains(object):
90            def __contains__(self, other):
91                return False
92        c = ByContains()
93        class BlockContains(ByContains):
94            """Is not a container
95
96            This class is a perfectly good iterable (as tested by
97            list(bc)), as well as inheriting from a perfectly good
98            container, but __contains__ = None prevents the usual
99            fallback to iteration in the container protocol. That
100            is, normally, 0 in bc would fall back to the equivalent
101            of any(x==0 for x in bc), but here it's blocked from
102            doing so.
103            """
104            def __iter__(self):
105                while False:
106                    yield None
107            __contains__ = None
108        bc = BlockContains()
109        self.assertFalse(0 in c)
110        self.assertFalse(0 in list(bc))
111        self.assertRaises(TypeError, lambda: 0 in bc)
112
113if __name__ == '__main__':
114    unittest.main()
115