|
1 """ |
|
2 Tests for stuff in django.utils.datastructures. |
|
3 """ |
|
4 import pickle |
|
5 import unittest |
|
6 |
|
7 from django.utils.datastructures import * |
|
8 |
|
9 |
|
10 class DatastructuresTestCase(unittest.TestCase): |
|
11 def assertRaisesErrorWithMessage(self, error, message, callable, |
|
12 *args, **kwargs): |
|
13 self.assertRaises(error, callable, *args, **kwargs) |
|
14 try: |
|
15 callable(*args, **kwargs) |
|
16 except error, e: |
|
17 self.assertEqual(message, str(e)) |
|
18 |
|
19 |
|
20 class SortedDictTests(DatastructuresTestCase): |
|
21 def setUp(self): |
|
22 self.d1 = SortedDict() |
|
23 self.d1[7] = 'seven' |
|
24 self.d1[1] = 'one' |
|
25 self.d1[9] = 'nine' |
|
26 |
|
27 self.d2 = SortedDict() |
|
28 self.d2[1] = 'one' |
|
29 self.d2[9] = 'nine' |
|
30 self.d2[0] = 'nil' |
|
31 self.d2[7] = 'seven' |
|
32 |
|
33 def test_basic_methods(self): |
|
34 self.assertEquals(self.d1.keys(), [7, 1, 9]) |
|
35 self.assertEquals(self.d1.values(), ['seven', 'one', 'nine']) |
|
36 self.assertEquals(self.d1.items(), [(7, 'seven'), (1, 'one'), (9, 'nine')]) |
|
37 |
|
38 def test_overwrite_ordering(self): |
|
39 """ Overwriting an item keeps it's place. """ |
|
40 self.d1[1] = 'ONE' |
|
41 self.assertEquals(self.d1.values(), ['seven', 'ONE', 'nine']) |
|
42 |
|
43 def test_append_items(self): |
|
44 """ New items go to the end. """ |
|
45 self.d1[0] = 'nil' |
|
46 self.assertEquals(self.d1.keys(), [7, 1, 9, 0]) |
|
47 |
|
48 def test_delete_and_insert(self): |
|
49 """ |
|
50 Deleting an item, then inserting the same key again will place it |
|
51 at the end. |
|
52 """ |
|
53 del self.d2[7] |
|
54 self.assertEquals(self.d2.keys(), [1, 9, 0]) |
|
55 self.d2[7] = 'lucky number 7' |
|
56 self.assertEquals(self.d2.keys(), [1, 9, 0, 7]) |
|
57 |
|
58 def test_change_keys(self): |
|
59 """ |
|
60 Changing the keys won't do anything, it's only a copy of the |
|
61 keys dict. |
|
62 """ |
|
63 k = self.d2.keys() |
|
64 k.remove(9) |
|
65 self.assertEquals(self.d2.keys(), [1, 9, 0, 7]) |
|
66 |
|
67 def test_init_keys(self): |
|
68 """ |
|
69 Initialising a SortedDict with two keys will just take the first one. |
|
70 |
|
71 A real dict will actually take the second value so we will too, but |
|
72 we'll keep the ordering from the first key found. |
|
73 """ |
|
74 tuples = ((2, 'two'), (1, 'one'), (2, 'second-two')) |
|
75 d = SortedDict(tuples) |
|
76 |
|
77 self.assertEquals(d.keys(), [2, 1]) |
|
78 |
|
79 real_dict = dict(tuples) |
|
80 self.assertEquals(sorted(real_dict.values()), ['one', 'second-two']) |
|
81 |
|
82 # Here the order of SortedDict values *is* what we are testing |
|
83 self.assertEquals(d.values(), ['second-two', 'one']) |
|
84 |
|
85 def test_overwrite(self): |
|
86 self.d1[1] = 'not one' |
|
87 self.assertEqual(self.d1[1], 'not one') |
|
88 self.assertEqual(self.d1.keys(), self.d1.copy().keys()) |
|
89 |
|
90 def test_append(self): |
|
91 self.d1[13] = 'thirteen' |
|
92 self.assertEquals( |
|
93 repr(self.d1), |
|
94 "{7: 'seven', 1: 'one', 9: 'nine', 13: 'thirteen'}" |
|
95 ) |
|
96 |
|
97 def test_pop(self): |
|
98 self.assertEquals(self.d1.pop(1, 'missing'), 'one') |
|
99 self.assertEquals(self.d1.pop(1, 'missing'), 'missing') |
|
100 |
|
101 # We don't know which item will be popped in popitem(), so we'll |
|
102 # just check that the number of keys has decreased. |
|
103 l = len(self.d1) |
|
104 self.d1.popitem() |
|
105 self.assertEquals(l - len(self.d1), 1) |
|
106 |
|
107 def test_dict_equality(self): |
|
108 d = SortedDict((i, i) for i in xrange(3)) |
|
109 self.assertEquals(d, {0: 0, 1: 1, 2: 2}) |
|
110 |
|
111 def test_tuple_init(self): |
|
112 d = SortedDict(((1, "one"), (0, "zero"), (2, "two"))) |
|
113 self.assertEquals(repr(d), "{1: 'one', 0: 'zero', 2: 'two'}") |
|
114 |
|
115 def test_pickle(self): |
|
116 self.assertEquals( |
|
117 pickle.loads(pickle.dumps(self.d1, 2)), |
|
118 {7: 'seven', 1: 'one', 9: 'nine'} |
|
119 ) |
|
120 |
|
121 def test_clear(self): |
|
122 self.d1.clear() |
|
123 self.assertEquals(self.d1, {}) |
|
124 self.assertEquals(self.d1.keyOrder, []) |
|
125 |
|
126 class MergeDictTests(DatastructuresTestCase): |
|
127 |
|
128 def test_simple_mergedict(self): |
|
129 d1 = {'chris':'cool', 'camri':'cute', 'cotton':'adorable', |
|
130 'tulip':'snuggable', 'twoofme':'firstone'} |
|
131 |
|
132 d2 = {'chris2':'cool2', 'camri2':'cute2', 'cotton2':'adorable2', |
|
133 'tulip2':'snuggable2'} |
|
134 |
|
135 d3 = {'chris3':'cool3', 'camri3':'cute3', 'cotton3':'adorable3', |
|
136 'tulip3':'snuggable3'} |
|
137 |
|
138 d4 = {'twoofme': 'secondone'} |
|
139 |
|
140 md = MergeDict(d1, d2, d3) |
|
141 |
|
142 self.assertEquals(md['chris'], 'cool') |
|
143 self.assertEquals(md['camri'], 'cute') |
|
144 self.assertEquals(md['twoofme'], 'firstone') |
|
145 |
|
146 md2 = md.copy() |
|
147 self.assertEquals(md2['chris'], 'cool') |
|
148 |
|
149 def test_mergedict_merges_multivaluedict(self): |
|
150 """ MergeDict can merge MultiValueDicts """ |
|
151 |
|
152 multi1 = MultiValueDict({'key1': ['value1'], |
|
153 'key2': ['value2', 'value3']}) |
|
154 |
|
155 multi2 = MultiValueDict({'key2': ['value4'], |
|
156 'key4': ['value5', 'value6']}) |
|
157 |
|
158 mm = MergeDict(multi1, multi2) |
|
159 |
|
160 # Although 'key2' appears in both dictionaries, |
|
161 # only the first value is used. |
|
162 self.assertEquals(mm.getlist('key2'), ['value2', 'value3']) |
|
163 self.assertEquals(mm.getlist('key4'), ['value5', 'value6']) |
|
164 self.assertEquals(mm.getlist('undefined'), []) |
|
165 |
|
166 self.assertEquals(sorted(mm.keys()), ['key1', 'key2', 'key4']) |
|
167 self.assertEquals(len(mm.values()), 3) |
|
168 |
|
169 self.assertTrue('value1' in mm.values()) |
|
170 |
|
171 self.assertEquals(sorted(mm.items(), key=lambda k: k[0]), |
|
172 [('key1', 'value1'), ('key2', 'value3'), |
|
173 ('key4', 'value6')]) |
|
174 |
|
175 self.assertEquals([(k,mm.getlist(k)) for k in sorted(mm)], |
|
176 [('key1', ['value1']), |
|
177 ('key2', ['value2', 'value3']), |
|
178 ('key4', ['value5', 'value6'])]) |
|
179 |
|
180 class MultiValueDictTests(DatastructuresTestCase): |
|
181 |
|
182 def test_multivaluedict(self): |
|
183 d = MultiValueDict({'name': ['Adrian', 'Simon'], |
|
184 'position': ['Developer']}) |
|
185 |
|
186 self.assertEquals(d['name'], 'Simon') |
|
187 self.assertEquals(d.get('name'), 'Simon') |
|
188 self.assertEquals(d.getlist('name'), ['Adrian', 'Simon']) |
|
189 self.assertEquals(list(d.iteritems()), |
|
190 [('position', 'Developer'), ('name', 'Simon')]) |
|
191 |
|
192 self.assertEquals(list(d.iterlists()), |
|
193 [('position', ['Developer']), |
|
194 ('name', ['Adrian', 'Simon'])]) |
|
195 |
|
196 # MultiValueDictKeyError: "Key 'lastname' not found in |
|
197 # <MultiValueDict: {'position': ['Developer'], |
|
198 # 'name': ['Adrian', 'Simon']}>" |
|
199 self.assertRaisesErrorWithMessage(MultiValueDictKeyError, |
|
200 '"Key \'lastname\' not found in <MultiValueDict: {\'position\':'\ |
|
201 ' [\'Developer\'], \'name\': [\'Adrian\', \'Simon\']}>"', |
|
202 d.__getitem__, 'lastname') |
|
203 |
|
204 self.assertEquals(d.get('lastname'), None) |
|
205 self.assertEquals(d.get('lastname', 'nonexistent'), 'nonexistent') |
|
206 self.assertEquals(d.getlist('lastname'), []) |
|
207 |
|
208 d.setlist('lastname', ['Holovaty', 'Willison']) |
|
209 self.assertEquals(d.getlist('lastname'), ['Holovaty', 'Willison']) |
|
210 self.assertEquals(d.values(), ['Developer', 'Simon', 'Willison']) |
|
211 self.assertEquals(list(d.itervalues()), |
|
212 ['Developer', 'Simon', 'Willison']) |
|
213 |
|
214 |
|
215 class DotExpandedDictTests(DatastructuresTestCase): |
|
216 |
|
217 def test_dotexpandeddict(self): |
|
218 |
|
219 d = DotExpandedDict({'person.1.firstname': ['Simon'], |
|
220 'person.1.lastname': ['Willison'], |
|
221 'person.2.firstname': ['Adrian'], |
|
222 'person.2.lastname': ['Holovaty']}) |
|
223 |
|
224 self.assertEquals(d['person']['1']['lastname'], ['Willison']) |
|
225 self.assertEquals(d['person']['2']['lastname'], ['Holovaty']) |
|
226 self.assertEquals(d['person']['2']['firstname'], ['Adrian']) |
|
227 |
|
228 |
|
229 class ImmutableListTests(DatastructuresTestCase): |
|
230 |
|
231 def test_sort(self): |
|
232 d = ImmutableList(range(10)) |
|
233 |
|
234 # AttributeError: ImmutableList object is immutable. |
|
235 self.assertRaisesErrorWithMessage(AttributeError, |
|
236 'ImmutableList object is immutable.', d.sort) |
|
237 |
|
238 self.assertEquals(repr(d), '(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)') |
|
239 |
|
240 def test_custom_warning(self): |
|
241 d = ImmutableList(range(10), warning="Object is immutable!") |
|
242 |
|
243 self.assertEquals(d[1], 1) |
|
244 |
|
245 # AttributeError: Object is immutable! |
|
246 self.assertRaisesErrorWithMessage(AttributeError, |
|
247 'Object is immutable!', d.__setitem__, 1, 'test') |
|
248 |
|
249 |
|
250 class DictWrapperTests(DatastructuresTestCase): |
|
251 |
|
252 def test_dictwrapper(self): |
|
253 f = lambda x: "*%s" % x |
|
254 d = DictWrapper({'a': 'a'}, f, 'xx_') |
|
255 self.assertEquals("Normal: %(a)s. Modified: %(xx_a)s" % d, |
|
256 'Normal: a. Modified: *a') |