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