Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
# coding: utf-8
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
import copy
import hashlib
import itertools
import os
import string
import sys
import unittest
import pytest
import six
from mozfile.mozfile import NamedTemporaryFile
from mozunit import main
from mozbuild.util import (
EnumString,
EnumStringComparisonError,
HierarchicalStringList,
MozbuildDeletionError,
ReadOnlyDict,
StrictOrderingOnAppendList,
StrictOrderingOnAppendListWithAction,
StrictOrderingOnAppendListWithFlagsFactory,
TypedList,
TypedNamedTuple,
UnsortedError,
expand_variables,
group_unified_files,
hash_file,
hexdump,
memoize,
memoized_property,
pair,
resolve_target_to_make,
)
if sys.version_info[0] == 3:
str_type = "str"
else:
str_type = "unicode"
data_path = os.path.abspath(os.path.dirname(__file__))
data_path = os.path.join(data_path, "data")
class TestHashing(unittest.TestCase):
def test_hash_file_known_hash(self):
"""Ensure a known hash value is recreated."""
data = b"The quick brown fox jumps over the lazy cog"
expected = "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"
temp = NamedTemporaryFile()
temp.write(data)
temp.flush()
actual = hash_file(temp.name)
self.assertEqual(actual, expected)
def test_hash_file_large(self):
"""Ensure that hash_file seems to work with a large file."""
data = b"x" * 1048576
hasher = hashlib.sha1()
hasher.update(data)
expected = hasher.hexdigest()
temp = NamedTemporaryFile()
temp.write(data)
temp.flush()
actual = hash_file(temp.name)
self.assertEqual(actual, expected)
class TestResolveTargetToMake(unittest.TestCase):
def setUp(self):
self.topobjdir = data_path
def assertResolve(self, path, expected):
# Handle Windows path separators.
(reldir, target) = resolve_target_to_make(self.topobjdir, path)
if reldir is not None:
reldir = reldir.replace(os.sep, "/")
if target is not None:
target = target.replace(os.sep, "/")
self.assertEqual((reldir, target), expected)
def test_root_path(self):
self.assertResolve("/test-dir", ("test-dir", None))
self.assertResolve("/test-dir/with", ("test-dir/with", None))
self.assertResolve("/test-dir/without", ("test-dir", None))
self.assertResolve("/test-dir/without/with", ("test-dir/without/with", None))
def test_dir(self):
self.assertResolve("test-dir", ("test-dir", None))
self.assertResolve("test-dir/with", ("test-dir/with", None))
self.assertResolve("test-dir/with", ("test-dir/with", None))
self.assertResolve("test-dir/without", ("test-dir", None))
self.assertResolve("test-dir/without/with", ("test-dir/without/with", None))
def test_top_level(self):
self.assertResolve("package", (None, "package"))
# Makefile handling shouldn't affect top-level targets.
self.assertResolve("Makefile", (None, "Makefile"))
def test_regular_file(self):
self.assertResolve("test-dir/with/file", ("test-dir/with", "file"))
self.assertResolve(
"test-dir/with/without/file", ("test-dir/with", "without/file")
)
self.assertResolve(
"test-dir/with/without/with/file", ("test-dir/with/without/with", "file")
)
self.assertResolve("test-dir/without/file", ("test-dir", "without/file"))
self.assertResolve(
"test-dir/without/with/file", ("test-dir/without/with", "file")
)
self.assertResolve(
"test-dir/without/with/without/file",
("test-dir/without/with", "without/file"),
)
def test_Makefile(self):
self.assertResolve("test-dir/with/Makefile", ("test-dir", "with/Makefile"))
self.assertResolve(
"test-dir/with/without/Makefile", ("test-dir/with", "without/Makefile")
)
self.assertResolve(
"test-dir/with/without/with/Makefile",
("test-dir/with", "without/with/Makefile"),
)
self.assertResolve(
"test-dir/without/Makefile", ("test-dir", "without/Makefile")
)
self.assertResolve(
"test-dir/without/with/Makefile", ("test-dir", "without/with/Makefile")
)
self.assertResolve(
"test-dir/without/with/without/Makefile",
("test-dir/without/with", "without/Makefile"),
)
class TestHierarchicalStringList(unittest.TestCase):
def setUp(self):
self.EXPORTS = HierarchicalStringList()
def test_exports_append(self):
self.assertEqual(self.EXPORTS._strings, [])
self.EXPORTS += ["foo.h"]
self.assertEqual(self.EXPORTS._strings, ["foo.h"])
self.EXPORTS += ["bar.h"]
self.assertEqual(self.EXPORTS._strings, ["foo.h", "bar.h"])
def test_exports_subdir(self):
self.assertEqual(self.EXPORTS._children, {})
self.EXPORTS.foo += ["foo.h"]
six.assertCountEqual(self, self.EXPORTS._children, {"foo": True})
self.assertEqual(self.EXPORTS.foo._strings, ["foo.h"])
self.EXPORTS.bar += ["bar.h"]
six.assertCountEqual(self, self.EXPORTS._children, {"foo": True, "bar": True})
self.assertEqual(self.EXPORTS.foo._strings, ["foo.h"])
self.assertEqual(self.EXPORTS.bar._strings, ["bar.h"])
def test_exports_multiple_subdir(self):
self.EXPORTS.foo.bar = ["foobar.h"]
six.assertCountEqual(self, self.EXPORTS._children, {"foo": True})
six.assertCountEqual(self, self.EXPORTS.foo._children, {"bar": True})
six.assertCountEqual(self, self.EXPORTS.foo.bar._children, {})
self.assertEqual(self.EXPORTS._strings, [])
self.assertEqual(self.EXPORTS.foo._strings, [])
self.assertEqual(self.EXPORTS.foo.bar._strings, ["foobar.h"])
def test_invalid_exports_append(self):
with self.assertRaises(ValueError) as ve:
self.EXPORTS += "foo.h"
six.assertRegex(
self,
str(ve.exception),
"Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
)
def test_invalid_exports_set(self):
with self.assertRaises(ValueError) as ve:
self.EXPORTS.foo = "foo.h"
six.assertRegex(
self,
str(ve.exception),
"Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
)
def test_invalid_exports_append_base(self):
with self.assertRaises(ValueError) as ve:
self.EXPORTS += "foo.h"
six.assertRegex(
self,
str(ve.exception),
"Expected a list of strings, not <(?:type|class) '%s'>" % str_type,
)
def test_invalid_exports_bool(self):
with self.assertRaises(ValueError) as ve:
self.EXPORTS += [True]
six.assertRegex(
self,
str(ve.exception),
"Expected a list of strings, not an element of " "<(?:type|class) 'bool'>",
)
def test_del_exports(self):
with self.assertRaises(MozbuildDeletionError):
self.EXPORTS.foo += ["bar.h"]
del self.EXPORTS.foo
def test_unsorted(self):
with self.assertRaises(UnsortedError):
self.EXPORTS += ["foo.h", "bar.h"]
with self.assertRaises(UnsortedError):
self.EXPORTS.foo = ["foo.h", "bar.h"]
with self.assertRaises(UnsortedError):
self.EXPORTS.foo += ["foo.h", "bar.h"]
def test_reassign(self):
self.EXPORTS.foo = ["foo.h"]
with self.assertRaises(KeyError):
self.EXPORTS.foo = ["bar.h"]
def test_walk(self):
l = HierarchicalStringList()
l += ["root1", "root2", "root3"]
l.child1 += ["child11", "child12", "child13"]
l.child1.grandchild1 += ["grandchild111", "grandchild112"]
l.child1.grandchild2 += ["grandchild121", "grandchild122"]
l.child2.grandchild1 += ["grandchild211", "grandchild212"]
l.child2.grandchild1 += ["grandchild213", "grandchild214"]
els = list((path, list(seq)) for path, seq in l.walk())
self.assertEqual(
els,
[
("", ["root1", "root2", "root3"]),
("child1", ["child11", "child12", "child13"]),
("child1/grandchild1", ["grandchild111", "grandchild112"]),
("child1/grandchild2", ["grandchild121", "grandchild122"]),
(
"child2/grandchild1",
[
"grandchild211",
"grandchild212",
"grandchild213",
"grandchild214",
],
),
],
)
def test_merge(self):
l1 = HierarchicalStringList()
l1 += ["root1", "root2", "root3"]
l1.child1 += ["child11", "child12", "child13"]
l1.child1.grandchild1 += ["grandchild111", "grandchild112"]
l1.child1.grandchild2 += ["grandchild121", "grandchild122"]
l1.child2.grandchild1 += ["grandchild211", "grandchild212"]
l1.child2.grandchild1 += ["grandchild213", "grandchild214"]
l2 = HierarchicalStringList()
l2.child1 += ["child14", "child15"]
l2.child1.grandchild2 += ["grandchild123"]
l2.child3 += ["child31", "child32"]
l1 += l2
els = list((path, list(seq)) for path, seq in l1.walk())
self.assertEqual(
els,
[
("", ["root1", "root2", "root3"]),
("child1", ["child11", "child12", "child13", "child14", "child15"]),
("child1/grandchild1", ["grandchild111", "grandchild112"]),
(
"child1/grandchild2",
["grandchild121", "grandchild122", "grandchild123"],
),
(
"child2/grandchild1",
[
"grandchild211",
"grandchild212",
"grandchild213",
"grandchild214",
],
),
("child3", ["child31", "child32"]),
],
)
class TestStrictOrderingOnAppendList(unittest.TestCase):
def test_init(self):
l = StrictOrderingOnAppendList()
self.assertEqual(len(l), 0)
l = StrictOrderingOnAppendList(["a", "b", "c"])
self.assertEqual(len(l), 3)
with self.assertRaises(UnsortedError):
StrictOrderingOnAppendList(["c", "b", "a"])
self.assertEqual(len(l), 3)
def test_extend(self):
l = StrictOrderingOnAppendList()
l.extend(["a", "b"])
self.assertEqual(len(l), 2)
self.assertIsInstance(l, StrictOrderingOnAppendList)
with self.assertRaises(UnsortedError):
l.extend(["d", "c"])
self.assertEqual(len(l), 2)
def test_slicing(self):
l = StrictOrderingOnAppendList()
l[:] = ["a", "b"]
self.assertEqual(len(l), 2)
self.assertIsInstance(l, StrictOrderingOnAppendList)
with self.assertRaises(UnsortedError):
l[:] = ["b", "a"]
self.assertEqual(len(l), 2)
def test_add(self):
l = StrictOrderingOnAppendList()
l2 = l + ["a", "b"]
self.assertEqual(len(l), 0)
self.assertEqual(len(l2), 2)
self.assertIsInstance(l2, StrictOrderingOnAppendList)
with self.assertRaises(UnsortedError):
l2 = l + ["b", "a"]
self.assertEqual(len(l), 0)
def test_iadd(self):
l = StrictOrderingOnAppendList()
l += ["a", "b"]
self.assertEqual(len(l), 2)
self.assertIsInstance(l, StrictOrderingOnAppendList)
with self.assertRaises(UnsortedError):
l += ["b", "a"]
self.assertEqual(len(l), 2)
def test_add_after_iadd(self):
l = StrictOrderingOnAppendList(["b"])
l += ["a"]
l2 = l + ["c", "d"]
self.assertEqual(len(l), 2)
self.assertEqual(len(l2), 4)
self.assertIsInstance(l2, StrictOrderingOnAppendList)
with self.assertRaises(UnsortedError):
l2 = l + ["d", "c"]
self.assertEqual(len(l), 2)
def test_add_StrictOrderingOnAppendList(self):
l = StrictOrderingOnAppendList()
l += ["c", "d"]
l += ["a", "b"]
l2 = StrictOrderingOnAppendList()
with self.assertRaises(UnsortedError):
l2 += list(l)
# Adding a StrictOrderingOnAppendList to another shouldn't throw
l2 += l
class TestStrictOrderingOnAppendListWithAction(unittest.TestCase):
def setUp(self):
self.action = lambda a: (a, id(a))
def assertSameList(self, expected, actual):
self.assertEqual(len(expected), len(actual))
for idx, item in enumerate(actual):
self.assertEqual(item, expected[idx])
def test_init(self):
l = StrictOrderingOnAppendListWithAction(action=self.action)
self.assertEqual(len(l), 0)
original = ["a", "b", "c"]
l = StrictOrderingOnAppendListWithAction(["a", "b", "c"], action=self.action)
expected = [self.action(i) for i in original]
self.assertSameList(expected, l)
with self.assertRaises(ValueError):
StrictOrderingOnAppendListWithAction("abc", action=self.action)
with self.assertRaises(ValueError):
StrictOrderingOnAppendListWithAction()
def test_extend(self):
l = StrictOrderingOnAppendListWithAction(action=self.action)
original = ["a", "b"]
l.extend(original)
expected = [self.action(i) for i in original]
self.assertSameList(expected, l)
with self.assertRaises(ValueError):
l.extend("ab")
def test_slicing(self):
l = StrictOrderingOnAppendListWithAction(action=self.action)
original = ["a", "b"]
l[:] = original
expected = [self.action(i) for i in original]
self.assertSameList(expected, l)
with self.assertRaises(ValueError):
l[:] = "ab"
def test_add(self):
l = StrictOrderingOnAppendListWithAction(action=self.action)
original = ["a", "b"]
l2 = l + original
expected = [self.action(i) for i in original]
self.assertSameList(expected, l2)
with self.assertRaises(ValueError):
l + "abc"
def test_iadd(self):
l = StrictOrderingOnAppendListWithAction(action=self.action)
original = ["a", "b"]
l += original
expected = [self.action(i) for i in original]
self.assertSameList(expected, l)
with self.assertRaises(ValueError):
l += "abc"
class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
def test_strict_ordering_on_append_list_with_flags_factory(self):
cls = StrictOrderingOnAppendListWithFlagsFactory(
{
"foo": bool,
"bar": int,
}
)
l = cls()
l += ["a", "b"]
with self.assertRaises(Exception):
l["a"] = "foo"
with self.assertRaises(Exception):
l["c"]
self.assertEqual(l["a"].foo, False)
l["a"].foo = True
self.assertEqual(l["a"].foo, True)
with self.assertRaises(TypeError):
l["a"].bar = "bar"
self.assertEqual(l["a"].bar, 0)
l["a"].bar = 42
self.assertEqual(l["a"].bar, 42)
l["b"].foo = True
self.assertEqual(l["b"].foo, True)
with self.assertRaises(AttributeError):
l["b"].baz = False
l["b"].update(foo=False, bar=12)
self.assertEqual(l["b"].foo, False)
self.assertEqual(l["b"].bar, 12)
with self.assertRaises(AttributeError):
l["b"].update(xyz=1)
def test_strict_ordering_on_append_list_with_flags_factory_extend(self):
FooList = StrictOrderingOnAppendListWithFlagsFactory(
{"foo": bool, "bar": six.text_type}
)
foo = FooList(["a", "b", "c"])
foo["a"].foo = True
foo["b"].bar = "bar"
# Don't allow extending lists with different flag definitions.
BarList = StrictOrderingOnAppendListWithFlagsFactory(
{"foo": six.text_type, "baz": bool}
)
bar = BarList(["d", "e", "f"])
bar["d"].foo = "foo"
bar["e"].baz = True
with self.assertRaises(ValueError):
foo + bar
with self.assertRaises(ValueError):
bar + foo
# It's not obvious what to do with duplicate list items with possibly
# different flag values, so don't allow that case.
with self.assertRaises(ValueError):
foo + foo
def assertExtended(l):
self.assertEqual(len(l), 6)
self.assertEqual(l["a"].foo, True)
self.assertEqual(l["b"].bar, "bar")
self.assertTrue("c" in l)
self.assertEqual(l["d"].foo, True)
self.assertEqual(l["e"].bar, "bar")
self.assertTrue("f" in l)
# Test extend.
zot = FooList(["d", "e", "f"])
zot["d"].foo = True
zot["e"].bar = "bar"
zot.extend(foo)
assertExtended(zot)
# Test __add__.
zot = FooList(["d", "e", "f"])
zot["d"].foo = True
zot["e"].bar = "bar"
assertExtended(foo + zot)
assertExtended(zot + foo)
# Test __iadd__.
foo += zot
assertExtended(foo)
# Test __setitem__.
foo[3:] = []
self.assertEqual(len(foo), 3)
foo[3:] = zot
assertExtended(foo)
class TestMemoize(unittest.TestCase):
def test_memoize(self):
self._count = 0
@memoize
def wrapped(a, b):
self._count += 1
return a + b
self.assertEqual(self._count, 0)
self.assertEqual(wrapped(1, 1), 2)
self.assertEqual(self._count, 1)
self.assertEqual(wrapped(1, 1), 2)
self.assertEqual(self._count, 1)
self.assertEqual(wrapped(2, 1), 3)
self.assertEqual(self._count, 2)
self.assertEqual(wrapped(1, 2), 3)
self.assertEqual(self._count, 3)
self.assertEqual(wrapped(1, 2), 3)
self.assertEqual(self._count, 3)
self.assertEqual(wrapped(1, 1), 2)
self.assertEqual(self._count, 3)
def test_memoize_method(self):
class foo(object):
def __init__(self):
self._count = 0
@memoize
def wrapped(self, a, b):
self._count += 1
return a + b
instance = foo()
refcount = sys.getrefcount(instance)
self.assertEqual(instance._count, 0)
self.assertEqual(instance.wrapped(1, 1), 2)
self.assertEqual(instance._count, 1)
self.assertEqual(instance.wrapped(1, 1), 2)
self.assertEqual(instance._count, 1)
self.assertEqual(instance.wrapped(2, 1), 3)
self.assertEqual(instance._count, 2)
self.assertEqual(instance.wrapped(1, 2), 3)
self.assertEqual(instance._count, 3)
self.assertEqual(instance.wrapped(1, 2), 3)
self.assertEqual(instance._count, 3)
self.assertEqual(instance.wrapped(1, 1), 2)
self.assertEqual(instance._count, 3)
# Memoization of methods is expected to not keep references to
# instances, so the refcount shouldn't have changed after executing the
# memoized method.
self.assertEqual(refcount, sys.getrefcount(instance))
def test_memoized_property(self):
class foo(object):
def __init__(self):
self._count = 0
@memoized_property
def wrapped(self):
self._count += 1
return 42
instance = foo()
self.assertEqual(instance._count, 0)
self.assertEqual(instance.wrapped, 42)
self.assertEqual(instance._count, 1)
self.assertEqual(instance.wrapped, 42)
self.assertEqual(instance._count, 1)
class TestTypedList(unittest.TestCase):
def test_init(self):
cls = TypedList(int)
l = cls()
self.assertEqual(len(l), 0)
l = cls([1, 2, 3])
self.assertEqual(len(l), 3)
with self.assertRaises(ValueError):
cls([1, 2, "c"])
def test_extend(self):
cls = TypedList(int)
l = cls()
l.extend([1, 2])
self.assertEqual(len(l), 2)
self.assertIsInstance(l, cls)
with self.assertRaises(ValueError):
l.extend([3, "c"])
self.assertEqual(len(l), 2)
def test_slicing(self):
cls = TypedList(int)
l = cls()
l[:] = [1, 2]
self.assertEqual(len(l), 2)
self.assertIsInstance(l, cls)
with self.assertRaises(ValueError):
l[:] = [3, "c"]
self.assertEqual(len(l), 2)
def test_add(self):
cls = TypedList(int)
l = cls()
l2 = l + [1, 2]
self.assertEqual(len(l), 0)
self.assertEqual(len(l2), 2)
self.assertIsInstance(l2, cls)
with self.assertRaises(ValueError):
l2 = l + [3, "c"]
self.assertEqual(len(l), 0)
def test_iadd(self):
cls = TypedList(int)
l = cls()
l += [1, 2]
self.assertEqual(len(l), 2)
self.assertIsInstance(l, cls)
with self.assertRaises(ValueError):
l += [3, "c"]
self.assertEqual(len(l), 2)
def test_add_coercion(self):
objs = []
class Foo(object):
def __init__(self, obj):
objs.append(obj)
cls = TypedList(Foo)
l = cls()
l += [1, 2]
self.assertEqual(len(objs), 2)
self.assertEqual(type(l[0]), Foo)
self.assertEqual(type(l[1]), Foo)
# Adding a TypedList to a TypedList shouldn't trigger coercion again
l2 = cls()
l2 += l
self.assertEqual(len(objs), 2)
self.assertEqual(type(l2[0]), Foo)
self.assertEqual(type(l2[1]), Foo)
# Adding a TypedList to a TypedList shouldn't even trigger the code
# that does coercion at all.
l2 = cls()
list.__setitem__(l, slice(0, -1), [1, 2])
l2 += l
self.assertEqual(len(objs), 2)
self.assertEqual(type(l2[0]), int)
self.assertEqual(type(l2[1]), int)
def test_memoized(self):
cls = TypedList(int)
cls2 = TypedList(str)
self.assertEqual(TypedList(int), cls)
self.assertNotEqual(cls, cls2)
class TypedTestStrictOrderingOnAppendList(unittest.TestCase):
def test_init(self):
class Unicode(six.text_type):
def __new__(cls, other):
if not isinstance(other, six.text_type):
raise ValueError()
return six.text_type.__new__(cls, other)
cls = TypedList(Unicode, StrictOrderingOnAppendList)
l = cls()
self.assertEqual(len(l), 0)
l = cls(["a", "b", "c"])
self.assertEqual(len(l), 3)
with self.assertRaises(UnsortedError):
cls(["c", "b", "a"])
with self.assertRaises(ValueError):
cls(["a", "b", 3])
self.assertEqual(len(l), 3)
class TestTypedNamedTuple(unittest.TestCase):
def test_simple(self):
FooBar = TypedNamedTuple("FooBar", [("foo", six.text_type), ("bar", int)])
t = FooBar(foo="foo", bar=2)
self.assertEqual(type(t), FooBar)
self.assertEqual(t.foo, "foo")
self.assertEqual(t.bar, 2)
self.assertEqual(t[0], "foo")
self.assertEqual(t[1], 2)
FooBar("foo", 2)
with self.assertRaises(TypeError):
FooBar("foo", "not integer")
with self.assertRaises(TypeError):
FooBar(2, 4)
# Passing a tuple as the first argument is the same as passing multiple
# arguments.
t1 = ("foo", 3)
t2 = FooBar(t1)
self.assertEqual(type(t2), FooBar)
self.assertEqual(FooBar(t1), FooBar("foo", 3))
class TestGroupUnifiedFiles(unittest.TestCase):
FILES = ["%s.cpp" % letter for letter in string.ascii_lowercase]
def test_multiple_files(self):
mapping = list(group_unified_files(self.FILES, "Unified", "cpp", 5))
def check_mapping(index, expected_num_source_files):
(unified_file, source_files) = mapping[index]
self.assertEqual(unified_file, "Unified%d.cpp" % index)
self.assertEqual(len(source_files), expected_num_source_files)
all_files = list(itertools.chain(*[files for (_, files) in mapping]))
self.assertEqual(len(all_files), len(self.FILES))
self.assertEqual(set(all_files), set(self.FILES))
expected_amounts = [5, 5, 5, 5, 5, 1]
for i, amount in enumerate(expected_amounts):
check_mapping(i, amount)
class TestMisc(unittest.TestCase):
def test_pair(self):
self.assertEqual(list(pair([1, 2, 3, 4, 5, 6])), [(1, 2), (3, 4), (5, 6)])
self.assertEqual(
list(pair([1, 2, 3, 4, 5, 6, 7])), [(1, 2), (3, 4), (5, 6), (7, None)]
)
def test_expand_variables(self):
self.assertEqual(expand_variables("$(var)", {"var": "value"}), "value")
self.assertEqual(
expand_variables("$(a) and $(b)", {"a": "1", "b": "2"}), "1 and 2"
)
self.assertEqual(
expand_variables("$(a) and $(undefined)", {"a": "1", "b": "2"}), "1 and "
)
self.assertEqual(
expand_variables(
"before $(string) between $(list) after",
{"string": "abc", "list": ["a", "b", "c"]},
),
"before abc between a b c after",
)
class TestEnumString(unittest.TestCase):
def test_string(self):
class CompilerType(EnumString):
POSSIBLE_VALUES = ("gcc", "clang", "clang-cl")
type = CompilerType("gcc")
self.assertEqual(type, "gcc")
self.assertNotEqual(type, "clang")
self.assertNotEqual(type, "clang-cl")
self.assertIn(type, ("gcc", "clang-cl"))
self.assertNotIn(type, ("clang", "clang-cl"))
with self.assertRaises(EnumStringComparisonError):
self.assertEqual(type, "foo")
with self.assertRaises(EnumStringComparisonError):
self.assertNotEqual(type, "foo")
with self.assertRaises(EnumStringComparisonError):
self.assertIn(type, ("foo", "gcc"))
with self.assertRaises(ValueError):
type = CompilerType("foo")
class TestHexDump(unittest.TestCase):
@unittest.skipUnless(six.PY3, "requires Python 3")
def test_hexdump(self):
self.assertEqual(
hexdump("abcdef123💩ZYXWVU".encode("utf-8")),
[
"00 61 62 63 64 65 66 31 32 33 f0 9f 92 a9 5a 59 58 |abcdef123....ZYX|\n",
"10 57 56 55 |WVU |\n",
],
)
def test_read_only_dict():
d = ReadOnlyDict(foo="bar")
with pytest.raises(Exception):
d["foo"] = "baz"
with pytest.raises(Exception):
d.update({"foo": "baz"})
with pytest.raises(Exception):
del d["foo"]
# ensure copy still works
d_copy = d.copy()
assert d == d_copy
# TODO Returning a dict here feels like a bug, but there are places in-tree
# relying on this behaviour.
assert isinstance(d_copy, dict)
d_copy = copy.copy(d)
assert d == d_copy
assert isinstance(d_copy, ReadOnlyDict)
d_copy = copy.deepcopy(d)
assert d == d_copy
assert isinstance(d_copy, ReadOnlyDict)
if __name__ == "__main__":
main()