Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / python / mozbuild / mozbuild / test / test_util.py
blob4a37172ca43804f066fd9de787f4dee0e07b2b0a
1 # coding: utf-8
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 import copy
7 import hashlib
8 import itertools
9 import os
10 import string
11 import sys
12 import unittest
14 import pytest
15 import six
16 from mozfile.mozfile import NamedTemporaryFile
17 from mozunit import main
19 from mozbuild.util import (
20 EnumString,
21 EnumStringComparisonError,
22 HierarchicalStringList,
23 MozbuildDeletionError,
24 ReadOnlyDict,
25 StrictOrderingOnAppendList,
26 StrictOrderingOnAppendListWithAction,
27 StrictOrderingOnAppendListWithFlagsFactory,
28 TypedList,
29 TypedNamedTuple,
30 UnsortedError,
31 expand_variables,
32 group_unified_files,
33 hash_file,
34 hexdump,
35 memoize,
36 memoized_property,
37 pair,
38 resolve_target_to_make,
41 if sys.version_info[0] == 3:
42 str_type = "str"
43 else:
44 str_type = "unicode"
46 data_path = os.path.abspath(os.path.dirname(__file__))
47 data_path = os.path.join(data_path, "data")
50 class TestHashing(unittest.TestCase):
51 def test_hash_file_known_hash(self):
52 """Ensure a known hash value is recreated."""
53 data = b"The quick brown fox jumps over the lazy cog"
54 expected = "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"
56 temp = NamedTemporaryFile()
57 temp.write(data)
58 temp.flush()
60 actual = hash_file(temp.name)
62 self.assertEqual(actual, expected)
64 def test_hash_file_large(self):
65 """Ensure that hash_file seems to work with a large file."""
66 data = b"x" * 1048576
68 hasher = hashlib.sha1()
69 hasher.update(data)
70 expected = hasher.hexdigest()
72 temp = NamedTemporaryFile()
73 temp.write(data)
74 temp.flush()
76 actual = hash_file(temp.name)
78 self.assertEqual(actual, expected)
81 class TestResolveTargetToMake(unittest.TestCase):
82 def setUp(self):
83 self.topobjdir = data_path
85 def assertResolve(self, path, expected):
86 # Handle Windows path separators.
87 (reldir, target) = resolve_target_to_make(self.topobjdir, path)
88 if reldir is not None:
89 reldir = reldir.replace(os.sep, "/")
90 if target is not None:
91 target = target.replace(os.sep, "/")
92 self.assertEqual((reldir, target), expected)
94 def test_root_path(self):
95 self.assertResolve("/test-dir", ("test-dir", None))
96 self.assertResolve("/test-dir/with", ("test-dir/with", None))
97 self.assertResolve("/test-dir/without", ("test-dir", None))
98 self.assertResolve("/test-dir/without/with", ("test-dir/without/with", None))
100 def test_dir(self):
101 self.assertResolve("test-dir", ("test-dir", None))
102 self.assertResolve("test-dir/with", ("test-dir/with", None))
103 self.assertResolve("test-dir/with", ("test-dir/with", None))
104 self.assertResolve("test-dir/without", ("test-dir", None))
105 self.assertResolve("test-dir/without/with", ("test-dir/without/with", None))
107 def test_top_level(self):
108 self.assertResolve("package", (None, "package"))
109 # Makefile handling shouldn't affect top-level targets.
110 self.assertResolve("Makefile", (None, "Makefile"))
112 def test_regular_file(self):
113 self.assertResolve("test-dir/with/file", ("test-dir/with", "file"))
114 self.assertResolve(
115 "test-dir/with/without/file", ("test-dir/with", "without/file")
117 self.assertResolve(
118 "test-dir/with/without/with/file", ("test-dir/with/without/with", "file")
121 self.assertResolve("test-dir/without/file", ("test-dir", "without/file"))
122 self.assertResolve(
123 "test-dir/without/with/file", ("test-dir/without/with", "file")
125 self.assertResolve(
126 "test-dir/without/with/without/file",
127 ("test-dir/without/with", "without/file"),
130 def test_Makefile(self):
131 self.assertResolve("test-dir/with/Makefile", ("test-dir", "with/Makefile"))
132 self.assertResolve(
133 "test-dir/with/without/Makefile", ("test-dir/with", "without/Makefile")
135 self.assertResolve(
136 "test-dir/with/without/with/Makefile",
137 ("test-dir/with", "without/with/Makefile"),
140 self.assertResolve(
141 "test-dir/without/Makefile", ("test-dir", "without/Makefile")
143 self.assertResolve(
144 "test-dir/without/with/Makefile", ("test-dir", "without/with/Makefile")
146 self.assertResolve(
147 "test-dir/without/with/without/Makefile",
148 ("test-dir/without/with", "without/Makefile"),
152 class TestHierarchicalStringList(unittest.TestCase):
153 def setUp(self):
154 self.EXPORTS = HierarchicalStringList()
156 def test_exports_append(self):
157 self.assertEqual(self.EXPORTS._strings, [])
158 self.EXPORTS += ["foo.h"]
159 self.assertEqual(self.EXPORTS._strings, ["foo.h"])
160 self.EXPORTS += ["bar.h"]
161 self.assertEqual(self.EXPORTS._strings, ["foo.h", "bar.h"])
163 def test_exports_subdir(self):
164 self.assertEqual(self.EXPORTS._children, {})
165 self.EXPORTS.foo += ["foo.h"]
166 six.assertCountEqual(self, self.EXPORTS._children, {"foo": True})
167 self.assertEqual(self.EXPORTS.foo._strings, ["foo.h"])
168 self.EXPORTS.bar += ["bar.h"]
169 six.assertCountEqual(self, self.EXPORTS._children, {"foo": True, "bar": True})
170 self.assertEqual(self.EXPORTS.foo._strings, ["foo.h"])
171 self.assertEqual(self.EXPORTS.bar._strings, ["bar.h"])
173 def test_exports_multiple_subdir(self):
174 self.EXPORTS.foo.bar = ["foobar.h"]
175 six.assertCountEqual(self, self.EXPORTS._children, {"foo": True})
176 six.assertCountEqual(self, self.EXPORTS.foo._children, {"bar": True})
177 six.assertCountEqual(self, self.EXPORTS.foo.bar._children, {})
178 self.assertEqual(self.EXPORTS._strings, [])
179 self.assertEqual(self.EXPORTS.foo._strings, [])
180 self.assertEqual(self.EXPORTS.foo.bar._strings, ["foobar.h"])
182 def test_invalid_exports_append(self):
183 with self.assertRaises(ValueError) as ve:
184 self.EXPORTS += "foo.h"
185 six.assertRegex(
186 self,
187 str(ve.exception),
188 "Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
191 def test_invalid_exports_set(self):
192 with self.assertRaises(ValueError) as ve:
193 self.EXPORTS.foo = "foo.h"
195 six.assertRegex(
196 self,
197 str(ve.exception),
198 "Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
201 def test_invalid_exports_append_base(self):
202 with self.assertRaises(ValueError) as ve:
203 self.EXPORTS += "foo.h"
205 six.assertRegex(
206 self,
207 str(ve.exception),
208 "Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
211 def test_invalid_exports_bool(self):
212 with self.assertRaises(ValueError) as ve:
213 self.EXPORTS += [True]
215 six.assertRegex(
216 self,
217 str(ve.exception),
218 "Expected a list of strings, not an element of " "<(?:type|class) 'bool'>",
221 def test_del_exports(self):
222 with self.assertRaises(MozbuildDeletionError):
223 self.EXPORTS.foo += ["bar.h"]
224 del self.EXPORTS.foo
226 def test_unsorted(self):
227 with self.assertRaises(UnsortedError):
228 self.EXPORTS += ["foo.h", "bar.h"]
230 with self.assertRaises(UnsortedError):
231 self.EXPORTS.foo = ["foo.h", "bar.h"]
233 with self.assertRaises(UnsortedError):
234 self.EXPORTS.foo += ["foo.h", "bar.h"]
236 def test_reassign(self):
237 self.EXPORTS.foo = ["foo.h"]
239 with self.assertRaises(KeyError):
240 self.EXPORTS.foo = ["bar.h"]
242 def test_walk(self):
243 l = HierarchicalStringList()
244 l += ["root1", "root2", "root3"]
245 l.child1 += ["child11", "child12", "child13"]
246 l.child1.grandchild1 += ["grandchild111", "grandchild112"]
247 l.child1.grandchild2 += ["grandchild121", "grandchild122"]
248 l.child2.grandchild1 += ["grandchild211", "grandchild212"]
249 l.child2.grandchild1 += ["grandchild213", "grandchild214"]
251 els = list((path, list(seq)) for path, seq in l.walk())
252 self.assertEqual(
253 els,
255 ("", ["root1", "root2", "root3"]),
256 ("child1", ["child11", "child12", "child13"]),
257 ("child1/grandchild1", ["grandchild111", "grandchild112"]),
258 ("child1/grandchild2", ["grandchild121", "grandchild122"]),
260 "child2/grandchild1",
262 "grandchild211",
263 "grandchild212",
264 "grandchild213",
265 "grandchild214",
271 def test_merge(self):
272 l1 = HierarchicalStringList()
273 l1 += ["root1", "root2", "root3"]
274 l1.child1 += ["child11", "child12", "child13"]
275 l1.child1.grandchild1 += ["grandchild111", "grandchild112"]
276 l1.child1.grandchild2 += ["grandchild121", "grandchild122"]
277 l1.child2.grandchild1 += ["grandchild211", "grandchild212"]
278 l1.child2.grandchild1 += ["grandchild213", "grandchild214"]
279 l2 = HierarchicalStringList()
280 l2.child1 += ["child14", "child15"]
281 l2.child1.grandchild2 += ["grandchild123"]
282 l2.child3 += ["child31", "child32"]
284 l1 += l2
285 els = list((path, list(seq)) for path, seq in l1.walk())
286 self.assertEqual(
287 els,
289 ("", ["root1", "root2", "root3"]),
290 ("child1", ["child11", "child12", "child13", "child14", "child15"]),
291 ("child1/grandchild1", ["grandchild111", "grandchild112"]),
293 "child1/grandchild2",
294 ["grandchild121", "grandchild122", "grandchild123"],
297 "child2/grandchild1",
299 "grandchild211",
300 "grandchild212",
301 "grandchild213",
302 "grandchild214",
305 ("child3", ["child31", "child32"]),
310 class TestStrictOrderingOnAppendList(unittest.TestCase):
311 def test_init(self):
312 l = StrictOrderingOnAppendList()
313 self.assertEqual(len(l), 0)
315 l = StrictOrderingOnAppendList(["a", "b", "c"])
316 self.assertEqual(len(l), 3)
318 with self.assertRaises(UnsortedError):
319 StrictOrderingOnAppendList(["c", "b", "a"])
321 self.assertEqual(len(l), 3)
323 def test_extend(self):
324 l = StrictOrderingOnAppendList()
325 l.extend(["a", "b"])
326 self.assertEqual(len(l), 2)
327 self.assertIsInstance(l, StrictOrderingOnAppendList)
329 with self.assertRaises(UnsortedError):
330 l.extend(["d", "c"])
332 self.assertEqual(len(l), 2)
334 def test_slicing(self):
335 l = StrictOrderingOnAppendList()
336 l[:] = ["a", "b"]
337 self.assertEqual(len(l), 2)
338 self.assertIsInstance(l, StrictOrderingOnAppendList)
340 with self.assertRaises(UnsortedError):
341 l[:] = ["b", "a"]
343 self.assertEqual(len(l), 2)
345 def test_add(self):
346 l = StrictOrderingOnAppendList()
347 l2 = l + ["a", "b"]
348 self.assertEqual(len(l), 0)
349 self.assertEqual(len(l2), 2)
350 self.assertIsInstance(l2, StrictOrderingOnAppendList)
352 with self.assertRaises(UnsortedError):
353 l2 = l + ["b", "a"]
355 self.assertEqual(len(l), 0)
357 def test_iadd(self):
358 l = StrictOrderingOnAppendList()
359 l += ["a", "b"]
360 self.assertEqual(len(l), 2)
361 self.assertIsInstance(l, StrictOrderingOnAppendList)
363 with self.assertRaises(UnsortedError):
364 l += ["b", "a"]
366 self.assertEqual(len(l), 2)
368 def test_add_after_iadd(self):
369 l = StrictOrderingOnAppendList(["b"])
370 l += ["a"]
371 l2 = l + ["c", "d"]
372 self.assertEqual(len(l), 2)
373 self.assertEqual(len(l2), 4)
374 self.assertIsInstance(l2, StrictOrderingOnAppendList)
375 with self.assertRaises(UnsortedError):
376 l2 = l + ["d", "c"]
378 self.assertEqual(len(l), 2)
380 def test_add_StrictOrderingOnAppendList(self):
381 l = StrictOrderingOnAppendList()
382 l += ["c", "d"]
383 l += ["a", "b"]
384 l2 = StrictOrderingOnAppendList()
385 with self.assertRaises(UnsortedError):
386 l2 += list(l)
387 # Adding a StrictOrderingOnAppendList to another shouldn't throw
388 l2 += l
391 class TestStrictOrderingOnAppendListWithAction(unittest.TestCase):
392 def setUp(self):
393 self.action = lambda a: (a, id(a))
395 def assertSameList(self, expected, actual):
396 self.assertEqual(len(expected), len(actual))
397 for idx, item in enumerate(actual):
398 self.assertEqual(item, expected[idx])
400 def test_init(self):
401 l = StrictOrderingOnAppendListWithAction(action=self.action)
402 self.assertEqual(len(l), 0)
403 original = ["a", "b", "c"]
404 l = StrictOrderingOnAppendListWithAction(["a", "b", "c"], action=self.action)
405 expected = [self.action(i) for i in original]
406 self.assertSameList(expected, l)
408 with self.assertRaises(ValueError):
409 StrictOrderingOnAppendListWithAction("abc", action=self.action)
411 with self.assertRaises(ValueError):
412 StrictOrderingOnAppendListWithAction()
414 def test_extend(self):
415 l = StrictOrderingOnAppendListWithAction(action=self.action)
416 original = ["a", "b"]
417 l.extend(original)
418 expected = [self.action(i) for i in original]
419 self.assertSameList(expected, l)
421 with self.assertRaises(ValueError):
422 l.extend("ab")
424 def test_slicing(self):
425 l = StrictOrderingOnAppendListWithAction(action=self.action)
426 original = ["a", "b"]
427 l[:] = original
428 expected = [self.action(i) for i in original]
429 self.assertSameList(expected, l)
431 with self.assertRaises(ValueError):
432 l[:] = "ab"
434 def test_add(self):
435 l = StrictOrderingOnAppendListWithAction(action=self.action)
436 original = ["a", "b"]
437 l2 = l + original
438 expected = [self.action(i) for i in original]
439 self.assertSameList(expected, l2)
441 with self.assertRaises(ValueError):
442 l + "abc"
444 def test_iadd(self):
445 l = StrictOrderingOnAppendListWithAction(action=self.action)
446 original = ["a", "b"]
447 l += original
448 expected = [self.action(i) for i in original]
449 self.assertSameList(expected, l)
451 with self.assertRaises(ValueError):
452 l += "abc"
455 class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
456 def test_strict_ordering_on_append_list_with_flags_factory(self):
457 cls = StrictOrderingOnAppendListWithFlagsFactory(
459 "foo": bool,
460 "bar": int,
464 l = cls()
465 l += ["a", "b"]
467 with self.assertRaises(Exception):
468 l["a"] = "foo"
470 with self.assertRaises(Exception):
471 l["c"]
473 self.assertEqual(l["a"].foo, False)
474 l["a"].foo = True
475 self.assertEqual(l["a"].foo, True)
477 with self.assertRaises(TypeError):
478 l["a"].bar = "bar"
480 self.assertEqual(l["a"].bar, 0)
481 l["a"].bar = 42
482 self.assertEqual(l["a"].bar, 42)
484 l["b"].foo = True
485 self.assertEqual(l["b"].foo, True)
487 with self.assertRaises(AttributeError):
488 l["b"].baz = False
490 l["b"].update(foo=False, bar=12)
491 self.assertEqual(l["b"].foo, False)
492 self.assertEqual(l["b"].bar, 12)
494 with self.assertRaises(AttributeError):
495 l["b"].update(xyz=1)
497 def test_strict_ordering_on_append_list_with_flags_factory_extend(self):
498 FooList = StrictOrderingOnAppendListWithFlagsFactory(
499 {"foo": bool, "bar": six.text_type}
501 foo = FooList(["a", "b", "c"])
502 foo["a"].foo = True
503 foo["b"].bar = "bar"
505 # Don't allow extending lists with different flag definitions.
506 BarList = StrictOrderingOnAppendListWithFlagsFactory(
507 {"foo": six.text_type, "baz": bool}
509 bar = BarList(["d", "e", "f"])
510 bar["d"].foo = "foo"
511 bar["e"].baz = True
512 with self.assertRaises(ValueError):
513 foo + bar
514 with self.assertRaises(ValueError):
515 bar + foo
517 # It's not obvious what to do with duplicate list items with possibly
518 # different flag values, so don't allow that case.
519 with self.assertRaises(ValueError):
520 foo + foo
522 def assertExtended(l):
523 self.assertEqual(len(l), 6)
524 self.assertEqual(l["a"].foo, True)
525 self.assertEqual(l["b"].bar, "bar")
526 self.assertTrue("c" in l)
527 self.assertEqual(l["d"].foo, True)
528 self.assertEqual(l["e"].bar, "bar")
529 self.assertTrue("f" in l)
531 # Test extend.
532 zot = FooList(["d", "e", "f"])
533 zot["d"].foo = True
534 zot["e"].bar = "bar"
535 zot.extend(foo)
536 assertExtended(zot)
538 # Test __add__.
539 zot = FooList(["d", "e", "f"])
540 zot["d"].foo = True
541 zot["e"].bar = "bar"
542 assertExtended(foo + zot)
543 assertExtended(zot + foo)
545 # Test __iadd__.
546 foo += zot
547 assertExtended(foo)
549 # Test __setitem__.
550 foo[3:] = []
551 self.assertEqual(len(foo), 3)
552 foo[3:] = zot
553 assertExtended(foo)
556 class TestMemoize(unittest.TestCase):
557 def test_memoize(self):
558 self._count = 0
560 @memoize
561 def wrapped(a, b):
562 self._count += 1
563 return a + b
565 self.assertEqual(self._count, 0)
566 self.assertEqual(wrapped(1, 1), 2)
567 self.assertEqual(self._count, 1)
568 self.assertEqual(wrapped(1, 1), 2)
569 self.assertEqual(self._count, 1)
570 self.assertEqual(wrapped(2, 1), 3)
571 self.assertEqual(self._count, 2)
572 self.assertEqual(wrapped(1, 2), 3)
573 self.assertEqual(self._count, 3)
574 self.assertEqual(wrapped(1, 2), 3)
575 self.assertEqual(self._count, 3)
576 self.assertEqual(wrapped(1, 1), 2)
577 self.assertEqual(self._count, 3)
579 def test_memoize_method(self):
580 class foo(object):
581 def __init__(self):
582 self._count = 0
584 @memoize
585 def wrapped(self, a, b):
586 self._count += 1
587 return a + b
589 instance = foo()
590 refcount = sys.getrefcount(instance)
591 self.assertEqual(instance._count, 0)
592 self.assertEqual(instance.wrapped(1, 1), 2)
593 self.assertEqual(instance._count, 1)
594 self.assertEqual(instance.wrapped(1, 1), 2)
595 self.assertEqual(instance._count, 1)
596 self.assertEqual(instance.wrapped(2, 1), 3)
597 self.assertEqual(instance._count, 2)
598 self.assertEqual(instance.wrapped(1, 2), 3)
599 self.assertEqual(instance._count, 3)
600 self.assertEqual(instance.wrapped(1, 2), 3)
601 self.assertEqual(instance._count, 3)
602 self.assertEqual(instance.wrapped(1, 1), 2)
603 self.assertEqual(instance._count, 3)
605 # Memoization of methods is expected to not keep references to
606 # instances, so the refcount shouldn't have changed after executing the
607 # memoized method.
608 self.assertEqual(refcount, sys.getrefcount(instance))
610 def test_memoized_property(self):
611 class foo(object):
612 def __init__(self):
613 self._count = 0
615 @memoized_property
616 def wrapped(self):
617 self._count += 1
618 return 42
620 instance = foo()
621 self.assertEqual(instance._count, 0)
622 self.assertEqual(instance.wrapped, 42)
623 self.assertEqual(instance._count, 1)
624 self.assertEqual(instance.wrapped, 42)
625 self.assertEqual(instance._count, 1)
628 class TestTypedList(unittest.TestCase):
629 def test_init(self):
630 cls = TypedList(int)
631 l = cls()
632 self.assertEqual(len(l), 0)
634 l = cls([1, 2, 3])
635 self.assertEqual(len(l), 3)
637 with self.assertRaises(ValueError):
638 cls([1, 2, "c"])
640 def test_extend(self):
641 cls = TypedList(int)
642 l = cls()
643 l.extend([1, 2])
644 self.assertEqual(len(l), 2)
645 self.assertIsInstance(l, cls)
647 with self.assertRaises(ValueError):
648 l.extend([3, "c"])
650 self.assertEqual(len(l), 2)
652 def test_slicing(self):
653 cls = TypedList(int)
654 l = cls()
655 l[:] = [1, 2]
656 self.assertEqual(len(l), 2)
657 self.assertIsInstance(l, cls)
659 with self.assertRaises(ValueError):
660 l[:] = [3, "c"]
662 self.assertEqual(len(l), 2)
664 def test_add(self):
665 cls = TypedList(int)
666 l = cls()
667 l2 = l + [1, 2]
668 self.assertEqual(len(l), 0)
669 self.assertEqual(len(l2), 2)
670 self.assertIsInstance(l2, cls)
672 with self.assertRaises(ValueError):
673 l2 = l + [3, "c"]
675 self.assertEqual(len(l), 0)
677 def test_iadd(self):
678 cls = TypedList(int)
679 l = cls()
680 l += [1, 2]
681 self.assertEqual(len(l), 2)
682 self.assertIsInstance(l, cls)
684 with self.assertRaises(ValueError):
685 l += [3, "c"]
687 self.assertEqual(len(l), 2)
689 def test_add_coercion(self):
690 objs = []
692 class Foo(object):
693 def __init__(self, obj):
694 objs.append(obj)
696 cls = TypedList(Foo)
697 l = cls()
698 l += [1, 2]
699 self.assertEqual(len(objs), 2)
700 self.assertEqual(type(l[0]), Foo)
701 self.assertEqual(type(l[1]), Foo)
703 # Adding a TypedList to a TypedList shouldn't trigger coercion again
704 l2 = cls()
705 l2 += l
706 self.assertEqual(len(objs), 2)
707 self.assertEqual(type(l2[0]), Foo)
708 self.assertEqual(type(l2[1]), Foo)
710 # Adding a TypedList to a TypedList shouldn't even trigger the code
711 # that does coercion at all.
712 l2 = cls()
713 list.__setitem__(l, slice(0, -1), [1, 2])
714 l2 += l
715 self.assertEqual(len(objs), 2)
716 self.assertEqual(type(l2[0]), int)
717 self.assertEqual(type(l2[1]), int)
719 def test_memoized(self):
720 cls = TypedList(int)
721 cls2 = TypedList(str)
722 self.assertEqual(TypedList(int), cls)
723 self.assertNotEqual(cls, cls2)
726 class TypedTestStrictOrderingOnAppendList(unittest.TestCase):
727 def test_init(self):
728 class Unicode(six.text_type):
729 def __new__(cls, other):
730 if not isinstance(other, six.text_type):
731 raise ValueError()
732 return six.text_type.__new__(cls, other)
734 cls = TypedList(Unicode, StrictOrderingOnAppendList)
735 l = cls()
736 self.assertEqual(len(l), 0)
738 l = cls(["a", "b", "c"])
739 self.assertEqual(len(l), 3)
741 with self.assertRaises(UnsortedError):
742 cls(["c", "b", "a"])
744 with self.assertRaises(ValueError):
745 cls(["a", "b", 3])
747 self.assertEqual(len(l), 3)
750 class TestTypedNamedTuple(unittest.TestCase):
751 def test_simple(self):
752 FooBar = TypedNamedTuple("FooBar", [("foo", six.text_type), ("bar", int)])
754 t = FooBar(foo="foo", bar=2)
755 self.assertEqual(type(t), FooBar)
756 self.assertEqual(t.foo, "foo")
757 self.assertEqual(t.bar, 2)
758 self.assertEqual(t[0], "foo")
759 self.assertEqual(t[1], 2)
761 FooBar("foo", 2)
763 with self.assertRaises(TypeError):
764 FooBar("foo", "not integer")
765 with self.assertRaises(TypeError):
766 FooBar(2, 4)
768 # Passing a tuple as the first argument is the same as passing multiple
769 # arguments.
770 t1 = ("foo", 3)
771 t2 = FooBar(t1)
772 self.assertEqual(type(t2), FooBar)
773 self.assertEqual(FooBar(t1), FooBar("foo", 3))
776 class TestGroupUnifiedFiles(unittest.TestCase):
777 FILES = ["%s.cpp" % letter for letter in string.ascii_lowercase]
779 def test_multiple_files(self):
780 mapping = list(group_unified_files(self.FILES, "Unified", "cpp", 5))
782 def check_mapping(index, expected_num_source_files):
783 (unified_file, source_files) = mapping[index]
785 self.assertEqual(unified_file, "Unified%d.cpp" % index)
786 self.assertEqual(len(source_files), expected_num_source_files)
788 all_files = list(itertools.chain(*[files for (_, files) in mapping]))
789 self.assertEqual(len(all_files), len(self.FILES))
790 self.assertEqual(set(all_files), set(self.FILES))
792 expected_amounts = [5, 5, 5, 5, 5, 1]
793 for i, amount in enumerate(expected_amounts):
794 check_mapping(i, amount)
797 class TestMisc(unittest.TestCase):
798 def test_pair(self):
799 self.assertEqual(list(pair([1, 2, 3, 4, 5, 6])), [(1, 2), (3, 4), (5, 6)])
801 self.assertEqual(
802 list(pair([1, 2, 3, 4, 5, 6, 7])), [(1, 2), (3, 4), (5, 6), (7, None)]
805 def test_expand_variables(self):
806 self.assertEqual(expand_variables("$(var)", {"var": "value"}), "value")
808 self.assertEqual(
809 expand_variables("$(a) and $(b)", {"a": "1", "b": "2"}), "1 and 2"
812 self.assertEqual(
813 expand_variables("$(a) and $(undefined)", {"a": "1", "b": "2"}), "1 and "
816 self.assertEqual(
817 expand_variables(
818 "before $(string) between $(list) after",
819 {"string": "abc", "list": ["a", "b", "c"]},
821 "before abc between a b c after",
825 class TestEnumString(unittest.TestCase):
826 def test_string(self):
827 class CompilerType(EnumString):
828 POSSIBLE_VALUES = ("gcc", "clang", "clang-cl")
830 type = CompilerType("gcc")
831 self.assertEqual(type, "gcc")
832 self.assertNotEqual(type, "clang")
833 self.assertNotEqual(type, "clang-cl")
834 self.assertIn(type, ("gcc", "clang-cl"))
835 self.assertNotIn(type, ("clang", "clang-cl"))
837 with self.assertRaises(EnumStringComparisonError):
838 self.assertEqual(type, "foo")
840 with self.assertRaises(EnumStringComparisonError):
841 self.assertNotEqual(type, "foo")
843 with self.assertRaises(EnumStringComparisonError):
844 self.assertIn(type, ("foo", "gcc"))
846 with self.assertRaises(ValueError):
847 type = CompilerType("foo")
850 class TestHexDump(unittest.TestCase):
851 @unittest.skipUnless(six.PY3, "requires Python 3")
852 def test_hexdump(self):
853 self.assertEqual(
854 hexdump("abcdef123💩ZYXWVU".encode("utf-8")),
856 "00 61 62 63 64 65 66 31 32 33 f0 9f 92 a9 5a 59 58 |abcdef123....ZYX|\n",
857 "10 57 56 55 |WVU |\n",
862 def test_read_only_dict():
863 d = ReadOnlyDict(foo="bar")
864 with pytest.raises(Exception):
865 d["foo"] = "baz"
867 with pytest.raises(Exception):
868 d.update({"foo": "baz"})
870 with pytest.raises(Exception):
871 del d["foo"]
873 # ensure copy still works
874 d_copy = d.copy()
875 assert d == d_copy
876 # TODO Returning a dict here feels like a bug, but there are places in-tree
877 # relying on this behaviour.
878 assert isinstance(d_copy, dict)
880 d_copy = copy.copy(d)
881 assert d == d_copy
882 assert isinstance(d_copy, ReadOnlyDict)
884 d_copy = copy.deepcopy(d)
885 assert d == d_copy
886 assert isinstance(d_copy, ReadOnlyDict)
889 if __name__ == "__main__":
890 main()