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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
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()