this repo has no description
1#!/usr/bin/env python3
2# Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
3import array
4import sys
5import unittest
6from unittest.mock import Mock
7
8
9class ArrayTest(unittest.TestCase):
10 def test_new_with_bad_typecode_raises_value_error(self):
11 with self.assertRaises(ValueError) as context:
12 array.array.__new__(array.array, "c")
13 self.assertEqual(
14 str(context.exception),
15 "bad typecode (must be b, B, u, h, H, i, I, l, L, q, Q, f or d)",
16 )
17
18 def test_new_with_non_str_typecode_raises_type_error(self):
19 with self.assertRaises(TypeError) as context:
20 array.array.__new__(array.array, b"not-string")
21 self.assertIn("must be a unicode character, not bytes", str(context.exception))
22
23 def test_new_with_long_str_typecode_raises_type_error(self):
24 with self.assertRaises(TypeError) as context:
25 array.array.__new__(array.array, "too")
26 self.assertIn("must be a unicode character, not str", str(context.exception))
27
28 def test_new_with_str_array_init_and_non_str_typecode_raises_type_error(self):
29 unicode_array = array.array("u")
30
31 with self.assertRaises(TypeError) as context:
32 array.array.__new__(array.array, "c", unicode_array)
33 self.assertEqual(
34 str(context.exception),
35 "cannot use a unicode array to initialize an array with typecode 'c'",
36 )
37
38 def test_new_with_valid_typecode_returns_array(self):
39 byte_array = array.array("b")
40 self.assertEqual(byte_array.typecode, "b")
41
42 def test_new_with_array_subtype_returns_subtype(self):
43 class ArraySub(array.array):
44 pass
45
46 array_sub = array.array.__new__(ArraySub, "B")
47 self.assertIsInstance(array_sub, ArraySub)
48 self.assertEqual(array_sub.typecode, "B")
49
50 def test_new_with_integer_typecode_and_non_number_raises_type_error(self):
51 with self.assertRaises(TypeError) as ctx:
52 array.array("i", ["not-a-number"])
53 self.assertEqual(str(ctx.exception), "an integer is required (got type str)")
54
55 def test_new_with_integer_typecode_and_float_raises_type_error(self):
56 with self.assertRaises(TypeError) as ctx:
57 array.array("Q", [2.0])
58 self.assertEqual(str(ctx.exception), "array item must be integer")
59
60 def test_new_with_integer_typecode_and_too_large_value_raises_overflow_error(self):
61 with self.assertRaises(OverflowError) as ctx:
62 array.array("b", [128])
63 self.assertIn("greater than maximum", str(ctx.exception))
64
65 def test_new_with_float_typecode_and_non_number_raises_type_error(self):
66 with self.assertRaises(TypeError) as ctx:
67 array.array("f", ["1"])
68 self.assertEqual(str(ctx.exception), "must be real number, not str")
69
70 def test_new_with_list_stores_each_number_in_the_array(self):
71 int_array = array.array("i", [1, 2, 3])
72 self.assertEqual(int_array[0], 1)
73 self.assertEqual(int_array[1], 2)
74 self.assertEqual(int_array[2], 3)
75
76 def test_new_with_tuple_stores_each_number_in_the_array(self):
77 int_array = array.array("d", (1.0, 2.0, 4.0))
78 self.assertEqual(int_array[0], 1.0)
79 self.assertEqual(int_array[1], 2.0)
80 self.assertEqual(int_array[2], 4.0)
81
82 def test_new_with_iterable_stores_each_number_in_the_array(self):
83 class Iterator:
84 def __iter__(self):
85 return [1, 2, 3].__iter__()
86
87 int_array = array.array("b", Iterator())
88 self.assertEqual(int_array[0], 1)
89 self.assertEqual(int_array[1], 2)
90 self.assertEqual(int_array[2], 3)
91 with self.assertRaises(IndexError) as ctx:
92 int_array[3]
93 self.assertEqual(str(ctx.exception), "array index out of range")
94
95 def test_new_with_float_typecode_and_list_calls_dunder_float_on_elements(self):
96 class FloatSub(float):
97 pass
98
99 class DunderFloat:
100 def __float__(self):
101 return 4.0
102
103 float_array = array.array("f", [1.0, FloatSub(2.0), DunderFloat()])
104 self.assertEqual(float_array[0], 1.0)
105 self.assertEqual(type(float_array[0]), float)
106 self.assertEqual(float_array[1], 2.0)
107 self.assertEqual(type(float_array[1]), float)
108 self.assertEqual(float_array[2], 4.0)
109 self.assertEqual(type(float_array[2]), float)
110
111 def test_new_with_integer_typecode_and_list_calls_dunder_index_on_elements(self):
112 class IntSub(int):
113 pass
114
115 class DunderIndex:
116 def __index__(self):
117 return 8
118
119 int_array = array.array("i", [1, IntSub(4), DunderIndex()])
120 self.assertEqual(int_array[0], 1)
121 self.assertEqual(type(int_array[0]), int)
122 self.assertEqual(int_array[1], 4)
123 self.assertEqual(type(int_array[1]), int)
124 self.assertEqual(int_array[2], 8)
125 self.assertEqual(type(int_array[2]), int)
126
127 def test_append_does_not_iterate_over_argument(self):
128 int_array = array.array("i")
129 with self.assertRaises(TypeError) as ctx:
130 int_array.append([0, 1])
131 self.assertEqual(str(ctx.exception), "an integer is required (got type list)")
132
133 def test_append_grows_array(self):
134 int_array = array.array("i")
135 self.assertEqual(int_array.__len__(), 0)
136 int_array.append(1)
137 self.assertEqual(int_array.__len__(), 1)
138 int_array.append(2)
139 self.assertEqual(int_array.__len__(), 2)
140 self.assertEqual(int_array[0], 1)
141 self.assertEqual(int_array[1], 2)
142
143 def test_dunder_mul_with_str_raises_type_error(self):
144 int_array = array.array("i")
145 with self.assertRaises(TypeError) as ctx:
146 int_array.__mul__("hello")
147 self.assertEqual(
148 str(ctx.exception), "'str' object cannot be interpreted as an integer"
149 )
150
151 def test_dunder_mul_with_subclass_returns_array(self):
152 class ArraySub(array.array):
153 pass
154
155 int_array = ArraySub("i", [1, 2, 3])
156 new_array = int_array.__mul__(3)
157 self.assertEqual(int_array.__len__(), 3)
158 self.assertEqual(type(new_array), array.array)
159 self.assertEqual(new_array.__len__(), 9)
160 self.assertEqual(list(new_array), [1, 2, 3, 1, 2, 3, 1, 2, 3])
161
162 def test_dunder_mul_with_maxsize_raises_memory_error(self):
163 int_array = array.array("i", [1, 2, 3])
164 with self.assertRaises(MemoryError):
165 int_array.__mul__(sys.maxsize)
166
167 def test_dunder_mul_with_int_returns_array(self):
168 int_array = array.array("i", [1, 2, 3])
169 new_array = int_array.__mul__(3)
170 self.assertEqual(int_array.__len__(), 3)
171 self.assertEqual(new_array.__len__(), 9)
172 self.assertEqual(list(new_array), [1, 2, 3, 1, 2, 3, 1, 2, 3])
173
174 def test_dunder_mul_with_index_returns_array(self):
175 class Num:
176 def __index__(self):
177 return 3
178
179 num = Num()
180 int_array = array.array("i", [1, 2, 3])
181 new_array = int_array.__mul__(num)
182 self.assertEqual(int_array.__len__(), 3)
183 self.assertEqual(new_array.__len__(), 9)
184 self.assertEqual(list(new_array), [1, 2, 3, 1, 2, 3, 1, 2, 3])
185
186 def test_extend_with_iterable_can_resize_past_length_hint(self):
187 class Iterator:
188 def __length_hint__(self):
189 return 1
190
191 def __iter__(self):
192 return [1, 2, 3].__iter__()
193
194 int_array = array.array("b")
195 int_array.extend(Iterator())
196 self.assertEqual(int_array[0], 1)
197 self.assertEqual(int_array[1], 2)
198 self.assertEqual(int_array[2], 3)
199 with self.assertRaises(IndexError) as ctx:
200 int_array[3]
201 self.assertEqual(str(ctx.exception), "array index out of range")
202
203 def test_extend_with_iterable_shorter_than_length_hint_resizes_to_iterable(self):
204 class Iterator:
205 def __length_hint__(self):
206 return 6
207
208 def __iter__(self):
209 return [1, 2, 3].__iter__()
210
211 int_array = array.array("b")
212 int_array.extend(Iterator())
213 self.assertEqual(int_array[0], 1)
214 self.assertEqual(int_array[1], 2)
215 self.assertEqual(int_array[2], 3)
216 with self.assertRaises(IndexError) as ctx:
217 int_array[3] = 4
218 self.assertEqual(str(ctx.exception), "array assignment index out of range")
219
220 def test_subclass_will_call_array_setitem_on_initialization(self):
221 class ArraySub(array.array):
222 __setitem__ = Mock(name="__setitem__", return_value=None)
223
224 int_array = ArraySub("i", [3, 2, 1])
225 self.assertEqual(int_array.__len__(), 3)
226 self.assertEqual(int_array[0], 3)
227 self.assertEqual(int_array[1], 2)
228 self.assertEqual(int_array[2], 1)
229
230 int_array[0] = 0
231 int_array.__setitem__.assert_called_once()
232
233 def test_getting_a_value_out_range_raises_index_error(self):
234 int_array = array.array("i", [1, 2, 3])
235 with self.assertRaises(IndexError) as ctx:
236 int_array[5]
237 self.assertEqual(str(ctx.exception), "array index out of range")
238
239 def test_getting_a_negative_value_out_of_range_raises_index_error(self):
240 int_array = array.array("i", [1, 2, 3])
241 with self.assertRaises(IndexError) as ctx:
242 int_array[-4]
243 self.assertEqual(str(ctx.exception), "array index out of range")
244
245 def test_getting_an_index_longer_than_word_raises_index_error(self):
246 int_array = array.array("i", [1, 2, 3])
247 with self.assertRaises(IndexError) as ctx:
248 int_array[1 << 65]
249 self.assertEqual(
250 str(ctx.exception), "cannot fit 'int' into an index-sized integer"
251 )
252
253 def test_getting_a_non_integer_index_raises_type_error(self):
254 int_array = array.array("i", [1, 2, 3])
255 with self.assertRaises(TypeError) as ctx:
256 int_array["not-int"]
257 self.assertIn("integer", str(ctx.exception))
258
259 def test_getitem_wth_dunder_index_calls_dunder_index(self):
260 class DunderIndex:
261 def __index__(self):
262 return 0
263
264 int_array = array.array("i", [1, 2, 3])
265 self.assertEqual(int_array[DunderIndex()], 1)
266
267 def test_setting_a_value_out_range_raises_index_error(self):
268 int_array = array.array("i", [1, 2, 3])
269 with self.assertRaises(IndexError) as ctx:
270 int_array[5] = 1
271 self.assertEqual(str(ctx.exception), "array assignment index out of range")
272
273 def test_setting_a_negative_value_out_range_raises_index_error(self):
274 int_array = array.array("i", [1, 2, 3])
275 with self.assertRaises(IndexError) as ctx:
276 int_array[-5] = 1
277 self.assertEqual(str(ctx.exception), "array assignment index out of range")
278
279 def test_setting_an_index_longer_than_word_raises_index_error(self):
280 int_array = array.array("i", [1, 2, 3])
281 with self.assertRaises(IndexError) as ctx:
282 int_array[1 << 65] = 1
283 self.assertEqual(
284 str(ctx.exception), "cannot fit 'int' into an index-sized integer"
285 )
286
287 def test_setting_a_non_integer_index_raises_type_error(self):
288 int_array = array.array("i", [1, 2, 3])
289 with self.assertRaises(TypeError) as ctx:
290 int_array["not-int"] = 2
291 self.assertIn("integer", str(ctx.exception))
292
293 def test_setitem_wth_dunder_index_calls_dunder_index(self):
294 class DunderIndex:
295 def __index__(self):
296 return 0
297
298 int_array = array.array("i", [1, 2, 3])
299 int_array[DunderIndex()] = 10
300 self.assertEqual(int_array[0], 10)
301
302
303if __name__ == "__main__":
304 unittest.main()