mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-17 18:03:06 +09:00
924 lines
29 KiB
Python
924 lines
29 KiB
Python
# 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/.
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import itertools
|
|
import hashlib
|
|
import os
|
|
import unittest
|
|
import shutil
|
|
import string
|
|
import sys
|
|
import tempfile
|
|
import textwrap
|
|
|
|
from mozfile.mozfile import NamedTemporaryFile
|
|
from mozunit import (
|
|
main,
|
|
MockedOpen,
|
|
)
|
|
|
|
from mozbuild.util import (
|
|
expand_variables,
|
|
FileAvoidWrite,
|
|
group_unified_files,
|
|
hash_file,
|
|
indented_repr,
|
|
memoize,
|
|
memoized_property,
|
|
pair,
|
|
resolve_target_to_make,
|
|
MozbuildDeletionError,
|
|
HierarchicalStringList,
|
|
EnumString,
|
|
EnumStringComparisonError,
|
|
ListWithAction,
|
|
StrictOrderingOnAppendList,
|
|
StrictOrderingOnAppendListWithFlagsFactory,
|
|
TypedList,
|
|
TypedNamedTuple,
|
|
UnsortedError,
|
|
)
|
|
|
|
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 TestFileAvoidWrite(unittest.TestCase):
|
|
def test_file_avoid_write(self):
|
|
with MockedOpen({'file': 'content'}):
|
|
# Overwriting an existing file replaces its content
|
|
faw = FileAvoidWrite('file')
|
|
faw.write('bazqux')
|
|
self.assertEqual(faw.close(), (True, True))
|
|
self.assertEqual(open('file', 'r').read(), 'bazqux')
|
|
|
|
# Creating a new file (obviously) stores its content
|
|
faw = FileAvoidWrite('file2')
|
|
faw.write('content')
|
|
self.assertEqual(faw.close(), (False, True))
|
|
self.assertEqual(open('file2').read(), 'content')
|
|
|
|
with MockedOpen({'file': 'content'}):
|
|
with FileAvoidWrite('file') as file:
|
|
file.write('foobar')
|
|
|
|
self.assertEqual(open('file', 'r').read(), 'foobar')
|
|
|
|
class MyMockedOpen(MockedOpen):
|
|
'''MockedOpen extension to raise an exception if something
|
|
attempts to write in an opened file.
|
|
'''
|
|
def __call__(self, name, mode):
|
|
if 'w' in mode:
|
|
raise Exception, 'Unexpected open with write mode'
|
|
return MockedOpen.__call__(self, name, mode)
|
|
|
|
with MyMockedOpen({'file': 'content'}):
|
|
# Validate that MyMockedOpen works as intended
|
|
file = FileAvoidWrite('file')
|
|
file.write('foobar')
|
|
self.assertRaises(Exception, file.close)
|
|
|
|
# Check that no write actually happens when writing the
|
|
# same content as what already is in the file
|
|
faw = FileAvoidWrite('file')
|
|
faw.write('content')
|
|
self.assertEqual(faw.close(), (True, False))
|
|
|
|
def test_diff_not_default(self):
|
|
"""Diffs are not produced by default."""
|
|
|
|
with MockedOpen({'file': 'old'}):
|
|
faw = FileAvoidWrite('file')
|
|
faw.write('dummy')
|
|
faw.close()
|
|
self.assertIsNone(faw.diff)
|
|
|
|
def test_diff_update(self):
|
|
"""Diffs are produced on file update."""
|
|
|
|
with MockedOpen({'file': 'old'}):
|
|
faw = FileAvoidWrite('file', capture_diff=True)
|
|
faw.write('new')
|
|
faw.close()
|
|
|
|
diff = '\n'.join(faw.diff)
|
|
self.assertIn('-old', diff)
|
|
self.assertIn('+new', diff)
|
|
|
|
def test_diff_create(self):
|
|
"""Diffs are produced when files are created."""
|
|
|
|
tmpdir = tempfile.mkdtemp()
|
|
try:
|
|
path = os.path.join(tmpdir, 'file')
|
|
faw = FileAvoidWrite(path, capture_diff=True)
|
|
faw.write('new')
|
|
faw.close()
|
|
|
|
diff = '\n'.join(faw.diff)
|
|
self.assertIn('+new', diff)
|
|
finally:
|
|
shutil.rmtree(tmpdir)
|
|
|
|
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"]
|
|
self.assertItemsEqual(self.EXPORTS._children, {"foo" : True})
|
|
self.assertEqual(self.EXPORTS.foo._strings, ["foo.h"])
|
|
self.EXPORTS.bar += ["bar.h"]
|
|
self.assertItemsEqual(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"]
|
|
self.assertItemsEqual(self.EXPORTS._children, {"foo" : True})
|
|
self.assertItemsEqual(self.EXPORTS.foo._children, {"bar" : True})
|
|
self.assertItemsEqual(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"
|
|
self.assertEqual(str(ve.exception),
|
|
"Expected a list of strings, not <type '%s'>" % str_type)
|
|
|
|
def test_invalid_exports_set(self):
|
|
with self.assertRaises(ValueError) as ve:
|
|
self.EXPORTS.foo = "foo.h"
|
|
|
|
self.assertEqual(str(ve.exception),
|
|
"Expected a list of strings, not <type '%s'>" % str_type)
|
|
|
|
def test_invalid_exports_append_base(self):
|
|
with self.assertRaises(ValueError) as ve:
|
|
self.EXPORTS += "foo.h"
|
|
|
|
self.assertEqual(str(ve.exception),
|
|
"Expected a list of strings, not <type '%s'>" % str_type)
|
|
|
|
def test_invalid_exports_bool(self):
|
|
with self.assertRaises(ValueError) as ve:
|
|
self.EXPORTS += [True]
|
|
|
|
self.assertEqual(str(ve.exception),
|
|
"Expected a list of strings, not an element of "
|
|
"<type 'bool'>")
|
|
|
|
def test_del_exports(self):
|
|
with self.assertRaises(MozbuildDeletionError) as mde:
|
|
self.EXPORTS.foo += ['bar.h']
|
|
del self.EXPORTS.foo
|
|
|
|
def test_unsorted(self):
|
|
with self.assertRaises(UnsortedError) as ee:
|
|
self.EXPORTS += ['foo.h', 'bar.h']
|
|
|
|
with self.assertRaises(UnsortedError) as ee:
|
|
self.EXPORTS.foo = ['foo.h', 'bar.h']
|
|
|
|
with self.assertRaises(UnsortedError) as ee:
|
|
self.EXPORTS.foo += ['foo.h', 'bar.h']
|
|
|
|
def test_reassign(self):
|
|
self.EXPORTS.foo = ['foo.h']
|
|
|
|
with self.assertRaises(KeyError) as ee:
|
|
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 TestListWithAction(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 = ListWithAction(action=self.action)
|
|
self.assertEqual(len(l), 0)
|
|
original = ['a', 'b', 'c']
|
|
l = ListWithAction(['a', 'b', 'c'], action=self.action)
|
|
expected = map(self.action, original)
|
|
self.assertSameList(expected, l)
|
|
|
|
with self.assertRaises(ValueError):
|
|
ListWithAction('abc', action=self.action)
|
|
|
|
with self.assertRaises(ValueError):
|
|
ListWithAction()
|
|
|
|
def test_extend(self):
|
|
l = ListWithAction(action=self.action)
|
|
original = ['a', 'b']
|
|
l.extend(original)
|
|
expected = map(self.action, original)
|
|
self.assertSameList(expected, l)
|
|
|
|
with self.assertRaises(ValueError):
|
|
l.extend('ab')
|
|
|
|
def test_slicing(self):
|
|
l = ListWithAction(action=self.action)
|
|
original = ['a', 'b']
|
|
l[:] = original
|
|
expected = map(self.action, original)
|
|
self.assertSameList(expected, l)
|
|
|
|
with self.assertRaises(ValueError):
|
|
l[:] = 'ab'
|
|
|
|
def test_add(self):
|
|
l = ListWithAction(action=self.action)
|
|
original = ['a', 'b']
|
|
l2 = l + original
|
|
expected = map(self.action, original)
|
|
self.assertSameList(expected, l2)
|
|
|
|
with self.assertRaises(ValueError):
|
|
l + 'abc'
|
|
|
|
def test_iadd(self):
|
|
l = ListWithAction(action=self.action)
|
|
original = ['a', 'b']
|
|
l += original
|
|
expected = map(self.action, 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):
|
|
c = 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': unicode
|
|
})
|
|
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': unicode, '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 __setslice__.
|
|
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.__setslice__(l, 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(unicode):
|
|
def __init__(self, other):
|
|
if not isinstance(other, unicode):
|
|
raise ValueError()
|
|
super(Unicode, self).__init__(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', unicode), ('bar', int)])
|
|
|
|
t = FooBar(foo='foo', bar=2)
|
|
self.assertEquals(type(t), FooBar)
|
|
self.assertEquals(t.foo, 'foo')
|
|
self.assertEquals(t.bar, 2)
|
|
self.assertEquals(t[0], 'foo')
|
|
self.assertEquals(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.assertEquals(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)
|
|
|
|
def test_unsorted_files(self):
|
|
unsorted_files = ['a%d.cpp' % i for i in range(11)]
|
|
sorted_files = sorted(unsorted_files)
|
|
mapping = list(group_unified_files(unsorted_files, 'Unified', 'cpp', 5))
|
|
|
|
self.assertEqual(mapping[0][1], sorted_files[0:5])
|
|
self.assertEqual(mapping[1][1], sorted_files[5:10])
|
|
self.assertEqual(mapping[2][1], sorted_files[10:])
|
|
|
|
|
|
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):
|
|
CompilerType = EnumString.subclass('msvc', 'gcc', 'clang', 'clang-cl')
|
|
|
|
type = CompilerType('msvc')
|
|
self.assertEquals(type, 'msvc')
|
|
self.assertNotEquals(type, 'gcc')
|
|
self.assertNotEquals(type, 'clang')
|
|
self.assertNotEquals(type, 'clang-cl')
|
|
self.assertIn(type, ('msvc', 'clang-cl'))
|
|
self.assertNotIn(type, ('gcc', 'clang'))
|
|
|
|
with self.assertRaises(EnumStringComparisonError):
|
|
self.assertEquals(type, 'foo')
|
|
|
|
with self.assertRaises(EnumStringComparisonError):
|
|
self.assertNotEquals(type, 'foo')
|
|
|
|
with self.assertRaises(EnumStringComparisonError):
|
|
self.assertIn(type, ('foo', 'gcc'))
|
|
|
|
with self.assertRaises(ValueError):
|
|
type = CompilerType('foo')
|
|
|
|
|
|
class TestIndentedRepr(unittest.TestCase):
|
|
def test_indented_repr(self):
|
|
data = textwrap.dedent(r'''
|
|
{
|
|
'a': 1,
|
|
'b': b'abc',
|
|
b'c': 'xyz',
|
|
'd': False,
|
|
'e': {
|
|
'a': 1,
|
|
'b': b'2',
|
|
'c': '3',
|
|
},
|
|
'f': [
|
|
1,
|
|
b'2',
|
|
'3',
|
|
],
|
|
'pile_of_bytes': b'\xf0\x9f\x92\xa9',
|
|
'pile_of_poo': '💩',
|
|
'special_chars': '\\\'"\x08\n\t',
|
|
'with_accents': 'éàñ',
|
|
}''').lstrip()
|
|
|
|
obj = eval(data)
|
|
|
|
self.assertEqual(indented_repr(obj), data)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|