Index: tools/binary_size/libsupersize/integration_test.py |
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py |
index e9ad9254a8ce250353f30d5f69efff4dc323d461..ad06650ac41c6a0d11bb86fa3aacc31f1833b14c 100755 |
--- a/tools/binary_size/libsupersize/integration_test.py |
+++ b/tools/binary_size/libsupersize/integration_test.py |
@@ -3,6 +3,7 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
+import contextlib |
import copy |
import difflib |
import glob |
@@ -10,20 +11,25 @@ import itertools |
import logging |
import os |
import unittest |
+import re |
import subprocess |
import sys |
import tempfile |
import archive |
import describe |
+import diff |
import file_format |
import models |
-import paths |
_SCRIPT_DIR = os.path.dirname(__file__) |
_TEST_DATA_DIR = os.path.join(_SCRIPT_DIR, 'testdata') |
+_TEST_OUTPUT_DIR = os.path.join(_TEST_DATA_DIR, 'mock_output_directory') |
+_TEST_TOOL_PREFIX = os.path.join( |
+ os.path.abspath(_TEST_DATA_DIR), 'mock_toolchain', '') |
_TEST_MAP_PATH = os.path.join(_TEST_DATA_DIR, 'test.map') |
+_TEST_ELF_PATH = os.path.join(_TEST_OUTPUT_DIR, 'elf') |
update_goldens = False |
@@ -35,66 +41,117 @@ def _AssertGolden(expected_lines, actual_lines): |
''.join(difflib.unified_diff(expected, actual, 'expected', 'actual'))) |
-def _CompareWithGolden(func): |
- name = func.__name__.replace('test_', '') |
- golden_path = os.path.join(_TEST_DATA_DIR, name + '.golden') |
+def _CompareWithGolden(name=None): |
+ def real_decorator(func): |
+ basename = name |
+ if not basename: |
+ basename = func.__name__.replace('test_', '') |
+ golden_path = os.path.join(_TEST_DATA_DIR, basename+ '.golden') |
estevenson
2017/04/28 17:06:11
nit: space after basename.
agrieve
2017/04/28 19:26:59
Done.
|
- def inner(self): |
- actual_lines = func(self) |
+ def inner(self): |
+ actual_lines = func(self) |
+ actual_lines = (re.sub(r'(elf_mtime=).*', r'\1{redacted}', l) |
+ for l in actual_lines) |
- if update_goldens: |
- with open(golden_path, 'w') as file_obj: |
- describe.WriteLines(actual_lines, file_obj.write) |
- logging.info('Wrote %s', golden_path) |
- else: |
- with open(golden_path) as file_obj: |
- _AssertGolden(file_obj, actual_lines) |
- return inner |
+ if update_goldens: |
+ with open(golden_path, 'w') as file_obj: |
+ describe.WriteLines(actual_lines, file_obj.write) |
+ logging.info('Wrote %s', golden_path) |
+ else: |
+ with open(golden_path) as file_obj: |
+ _AssertGolden(file_obj, actual_lines) |
+ return inner |
+ return real_decorator |
+ |
+ |
+@contextlib.contextmanager |
+def _AddMocksToPath(): |
+ prev_path = os.environ['PATH'] |
+ os.environ['PATH'] = _TEST_TOOL_PREFIX[:-1] + os.path.pathsep + prev_path |
+ yield |
+ os.environ['PATH'] = prev_path |
-def _RunApp(name, *args): |
+def _RunApp(name, args, debug_measures=False): |
argv = [os.path.join(_SCRIPT_DIR, 'main.py'), name, '--no-pypy'] |
argv.extend(args) |
- return subprocess.check_output(argv).splitlines() |
+ with _AddMocksToPath(): |
+ env = None |
+ if debug_measures: |
+ env = os.environ.copy() |
+ env['SUPERSIZE_DISABLE_ASYNC'] = '1' |
+ env['SUPERSIZE_MEASURE_GZIP'] = '1' |
+ |
+ return subprocess.check_output(argv, env=env).splitlines() |
class IntegrationTest(unittest.TestCase): |
- size_info = None |
+ cached_size_info = [None, None, None] |
- def _CloneSizeInfo(self): |
- if not IntegrationTest.size_info: |
- lazy_paths = paths.LazyPaths(output_directory=_TEST_DATA_DIR) |
- IntegrationTest.size_info = ( |
- archive.CreateSizeInfo(_TEST_MAP_PATH, lazy_paths)) |
- return copy.deepcopy(IntegrationTest.size_info) |
+ def _CloneSizeInfo(self, use_output_directory=True, use_elf=True): |
+ assert not use_elf or use_output_directory |
+ i = int(use_output_directory) + int(use_elf) |
+ if not IntegrationTest.cached_size_info[i]: |
+ elf_path = _TEST_ELF_PATH if use_elf else None |
+ output_directory = _TEST_OUTPUT_DIR if use_output_directory else None |
+ IntegrationTest.cached_size_info[i] = archive.CreateSizeInfo( |
+ _TEST_MAP_PATH, elf_path, _TEST_TOOL_PREFIX, output_directory) |
+ if use_elf: |
+ with _AddMocksToPath(): |
+ IntegrationTest.cached_size_info[i].metadata = archive.CreateMetadata( |
+ _TEST_MAP_PATH, elf_path, None, _TEST_TOOL_PREFIX, |
+ output_directory) |
+ return copy.deepcopy(IntegrationTest.cached_size_info[i]) |
- @_CompareWithGolden |
- def test_Archive(self): |
+ def _DoArchiveTest(self, use_output_directory=True, use_elf=True, |
+ debug_measures=False): |
with tempfile.NamedTemporaryFile(suffix='.size') as temp_file: |
- _RunApp('archive', temp_file.name, '--output-directory', _TEST_DATA_DIR, |
- '--map-file', _TEST_MAP_PATH) |
+ args = [temp_file.name, '--map-file', _TEST_MAP_PATH] |
+ if use_output_directory: |
+ # Let autodetection find output_directory when --elf-file is used. |
+ if not use_elf: |
+ args += ['--output-directory', _TEST_OUTPUT_DIR] |
+ else: |
+ args += ['--no-source-paths'] |
+ if use_elf: |
+ args += ['--elf-file', _TEST_ELF_PATH] |
+ _RunApp('archive', args, debug_measures=debug_measures) |
size_info = archive.LoadAndPostProcessSizeInfo(temp_file.name) |
# Check that saving & loading is the same as directly parsing the .map. |
- expected_size_info = self._CloneSizeInfo() |
+ expected_size_info = self._CloneSizeInfo( |
+ use_output_directory=use_output_directory, use_elf=use_elf) |
self.assertEquals(expected_size_info.metadata, size_info.metadata) |
- expected = '\n'.join(describe.GenerateLines( |
- expected_size_info, verbose=True, recursive=True)), |
- actual = '\n'.join(describe.GenerateLines( |
- size_info, verbose=True, recursive=True)), |
+ expected = list(describe.GenerateLines( |
+ expected_size_info, verbose=True, recursive=True)) |
+ actual = list(describe.GenerateLines( |
+ size_info, verbose=True, recursive=True)) |
self.assertEquals(expected, actual) |
sym_strs = (repr(sym) for sym in size_info.symbols) |
stats = describe.DescribeSizeInfoCoverage(size_info) |
- return itertools.chain(stats, sym_strs) |
+ if size_info.metadata: |
+ metadata = describe.DescribeMetadata(size_info.metadata) |
+ else: |
+ metadata = [] |
+ return itertools.chain(metadata, stats, sym_strs) |
- def test_Archive_NoSourcePaths(self): |
- # Just tests that it doesn't crash. |
- with tempfile.NamedTemporaryFile(suffix='.size') as temp_file: |
- _RunApp('archive', temp_file.name, '--no-source-paths', |
- '--map-file', _TEST_MAP_PATH) |
- archive.LoadAndPostProcessSizeInfo(temp_file.name) |
+ @_CompareWithGolden() |
+ def test_Archive(self): |
+ return self._DoArchiveTest(use_output_directory=False, use_elf=False) |
+ |
+ @_CompareWithGolden() |
+ def test_Archive_OutputDirectory(self): |
+ return self._DoArchiveTest(use_elf=False) |
+ |
+ @_CompareWithGolden() |
+ def test_Archive_Elf(self): |
+ return self._DoArchiveTest() |
- @_CompareWithGolden |
+ @_CompareWithGolden(name='Archive_Elf') |
+ def test_Archive_Elf_DebugMeasures(self): |
+ return self._DoArchiveTest(debug_measures=True) |
+ |
+ @_CompareWithGolden() |
def test_Console(self): |
with tempfile.NamedTemporaryFile(suffix='.size') as size_file, \ |
tempfile.NamedTemporaryFile(suffix='.txt') as output_file: |
@@ -104,34 +161,85 @@ class IntegrationTest(unittest.TestCase): |
'ExpandRegex("_foo_")', |
'Print(size_info, to_file=%r)' % output_file.name, |
] |
- ret = _RunApp('console', size_file.name, '--query', '; '.join(query)) |
+ ret = _RunApp('console', [size_file.name, '--query', '; '.join(query)]) |
with open(output_file.name) as f: |
ret.extend(l.rstrip() for l in f) |
return ret |
- @_CompareWithGolden |
+ @_CompareWithGolden() |
def test_Diff_NullDiff(self): |
with tempfile.NamedTemporaryFile(suffix='.size') as temp_file: |
file_format.SaveSizeInfo(self._CloneSizeInfo(), temp_file.name) |
- return _RunApp('diff', temp_file.name, temp_file.name) |
+ return _RunApp('diff', [temp_file.name, temp_file.name]) |
- @_CompareWithGolden |
- def test_ActualDiff(self): |
- size_info1 = self._CloneSizeInfo() |
- size_info2 = self._CloneSizeInfo() |
+ @_CompareWithGolden() |
+ def test_Diff_Basic(self): |
+ size_info1 = self._CloneSizeInfo(use_elf=False) |
+ size_info2 = self._CloneSizeInfo(use_elf=False) |
size_info1.metadata = {"foo": 1, "bar": [1,2,3], "baz": "yes"} |
size_info2.metadata = {"foo": 1, "bar": [1,3], "baz": "yes"} |
size_info1.symbols -= size_info1.symbols[:2] |
size_info2.symbols -= size_info2.symbols[-3:] |
size_info1.symbols[1].size -= 10 |
- diff = models.Diff(size_info1, size_info2) |
- return describe.GenerateLines(diff, verbose=True) |
+ d = diff.Diff(size_info1, size_info2) |
+ return describe.GenerateLines(d, verbose=True) |
+ |
+ def test_Diff_Aliases1(self): |
+ symbols1 = self._CloneSizeInfo().symbols |
+ symbols2 = self._CloneSizeInfo().symbols |
+ |
+ # Removing 1 alias should not change the size. |
+ a1, _, _ = symbols2.Filter(lambda s: s.num_aliases == 3)[0].aliases |
+ symbols2 -= [a1] |
+ a1.aliases.remove(a1) |
+ d = diff.Diff(symbols1, symbols2) |
+ self.assertEquals(d.size, 0) |
+ self.assertEquals(d.removed_count, 1) |
+ |
+ # Adding one alias should not change size. |
+ d = diff.Diff(symbols2, symbols1) |
+ self.assertEquals(d.size, 0) |
+ self.assertEquals(d.added_count, 1) |
+ |
+ def test_Diff_Aliases2(self): |
+ symbols1 = self._CloneSizeInfo().symbols |
+ symbols2 = self._CloneSizeInfo().symbols |
+ |
+ # Removing 2 aliases should not change the size. |
+ a1, a2, _ = symbols2.Filter(lambda s: s.num_aliases == 3)[0].aliases |
+ symbols2 -= [a1, a2] |
+ a1.aliases.remove(a1) |
+ a1.aliases.remove(a2) |
+ d = diff.Diff(symbols1, symbols2) |
+ self.assertEquals(d.size, 0) |
+ self.assertEquals(d.removed_count, 2) |
+ |
+ # Adding 2 aliases should not change size. |
+ d = diff.Diff(symbols2, symbols1) |
+ self.assertEquals(d.size, 0) |
+ self.assertEquals(d.added_count, 2) |
+ |
+ def test_Diff_Aliases3(self): |
+ symbols1 = self._CloneSizeInfo().symbols |
+ symbols2 = self._CloneSizeInfo().symbols |
+ |
+ # Removing all 3 aliases should change the size. |
+ a1, a2, a3 = symbols2.Filter(lambda s: s.num_aliases == 3)[0].aliases |
+ symbols2 -= [a1, a2, a3] |
+ d = diff.Diff(symbols1, symbols2) |
+ self.assertEquals(d.size, -a1.size) |
+ self.assertEquals(d.removed_count, 3) |
+ |
+ # Adding all 3 aliases should change size. |
+ d = diff.Diff(symbols2, symbols1) |
+ self.assertEquals(d.size, a1.size) |
+ self.assertEquals(d.added_count, 3) |
- @_CompareWithGolden |
+ @_CompareWithGolden() |
def test_FullDescription(self): |
return describe.GenerateLines(self._CloneSizeInfo()) |
- @_CompareWithGolden |
+ @_CompareWithGolden() |
def test_SymbolGroupMethods(self): |
all_syms = self._CloneSizeInfo().symbols |
global_syms = all_syms.WhereNameMatches('GLOBAL') |