diff --git a/apex/apex_test.go b/apex/apex_test.go index dbe918010..6abd8ffa6 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -949,8 +949,10 @@ func TestApexWithStubs(t *testing.T) { // mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] // ensureNotContains(t, mylib2Cflags, "-include ") - // Ensure that genstub is invoked with --apex - ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"]) + // Ensure that genstub for platform-provided lib is invoked with --systemapi + ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + // Ensure that genstub for apex-provided lib is invoked with --apex + ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "lib64/mylib.so", @@ -1134,8 +1136,8 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"] ensureNotContains(t, mylib2Cflags, "-include ") - // Ensure that genstub is invoked with --apex - ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"]) + // Ensure that genstub is invoked with --systemapi + ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi") ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "lib64/mylib.so", diff --git a/cc/library.go b/cc/library.go index c445a42ca..e2d5ef624 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1032,9 +1032,19 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile) return Objects{} } + // b/239274367 --apex and --systemapi filters symbols tagged with # apex and # + // systemapi, respectively. The former is for symbols defined in platform libraries + // and the latter is for symbols defined in APEXes. + var flag string + if ctx.Module().(android.ApexModule).NotInPlatform() { + flag = "--apex" + } else { + // TODO(b/239274367) drop --apex when #apex is replaced with #systemapi + // in the map.txt files of platform libraries + flag = "--systemapi --apex" + } nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, - android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), - "--apex") + android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag) objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) library.versionScriptPath = android.OptionalPathForPath( nativeAbiResult.versionScript) diff --git a/cc/ndk_api_coverage_parser/__init__.py b/cc/ndk_api_coverage_parser/__init__.py index 8b9cd66fa..752f7d488 100755 --- a/cc/ndk_api_coverage_parser/__init__.py +++ b/cc/ndk_api_coverage_parser/__init__.py @@ -23,6 +23,7 @@ import sys from xml.etree.ElementTree import Element, SubElement, tostring from symbolfile import ( ALL_ARCHITECTURES, + Filter, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser, @@ -139,9 +140,8 @@ def main(): with open(args.symbol_file) as symbol_file: try: - versions = SymbolFileParser( - symbol_file, api_map, "", FUTURE_API_LEVEL, True, True - ).parse() + filt = Filter("", FUTURE_API_LEVEL, True, True, True) + versions = SymbolFileParser(symbol_file, api_map, filt).parse() except MultiplyDefinedSymbolError as ex: sys.exit('{}: error: {}'.format(args.symbol_file, ex)) diff --git a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py index 141059c7d..7c6ef682b 100644 --- a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py +++ b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py @@ -20,7 +20,7 @@ import textwrap import unittest from xml.etree.ElementTree import fromstring -from symbolfile import FUTURE_API_LEVEL, SymbolFileParser +from symbolfile import Filter, FUTURE_API_LEVEL, SymbolFileParser import ndk_api_coverage_parser as nparser @@ -78,9 +78,8 @@ class ApiCoverageSymbolFileParserTest(unittest.TestCase): """ ) ) - parser = SymbolFileParser( - input_file, {}, "", FUTURE_API_LEVEL, True, True - ) + filt = Filter("", FUTURE_API_LEVEL, True, True, True) + parser = SymbolFileParser(input_file, {}, filt) generator = nparser.XmlGenerator(io.StringIO()) result = generator.convertToXml(parser.parse()) expected = fromstring( diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py index 5e6b8f509..f893d41e2 100755 --- a/cc/ndkstubgen/__init__.py +++ b/cc/ndkstubgen/__init__.py @@ -29,15 +29,12 @@ from symbolfile import Arch, Version class Generator: """Output generator that writes stub source files and version scripts.""" def __init__(self, src_file: TextIO, version_script: TextIO, - symbol_list: TextIO, arch: Arch, api: int, llndk: bool, - apex: bool) -> None: + symbol_list: TextIO, filt: symbolfile.Filter) -> None: self.src_file = src_file self.version_script = version_script self.symbol_list = symbol_list - self.arch = arch - self.api = api - self.llndk = llndk - self.apex = apex + self.filter = filt + self.api = filt.api def write(self, versions: Iterable[Version]) -> None: """Writes all symbol data to the output files.""" @@ -47,8 +44,7 @@ class Generator: def write_version(self, version: Version) -> None: """Writes a single version block's data to the output files.""" - if symbolfile.should_omit_version(version, self.arch, self.api, - self.llndk, self.apex): + if self.filter.should_omit_version(version): return section_versioned = symbolfile.symbol_versioned_in_api( @@ -56,8 +52,7 @@ class Generator: version_empty = True pruned_symbols = [] for symbol in version.symbols: - if symbolfile.should_omit_symbol(symbol, self.arch, self.api, - self.llndk, self.apex): + if self.filter.should_omit_symbol(symbol): continue if symbolfile.symbol_versioned_in_api(symbol.tags, self.api): @@ -110,12 +105,12 @@ def parse_args() -> argparse.Namespace: parser.add_argument( '--apex', action='store_true', - help='Use the APEX variant. Note: equivalent to --system-api.') + help='Use the APEX variant.') parser.add_argument( - '--system-api', + '--systemapi', action='store_true', - dest='apex', - help='Use the SystemAPI variant. Note: equivalent to --apex.') + dest='systemapi', + help='Use the SystemAPI variant.') parser.add_argument('--api-map', type=resolved_path, @@ -152,11 +147,10 @@ def main() -> None: verbosity = 2 logging.basicConfig(level=verbose_map[verbosity]) + filt = symbolfile.Filter(args.arch, api, args.llndk, args.apex, args.systemapi) with args.symbol_file.open() as symbol_file: try: - versions = symbolfile.SymbolFileParser(symbol_file, api_map, - args.arch, api, args.llndk, - args.apex).parse() + versions = symbolfile.SymbolFileParser(symbol_file, api_map, filt).parse() except symbolfile.MultiplyDefinedSymbolError as ex: sys.exit(f'{args.symbol_file}: error: {ex}') @@ -164,7 +158,7 @@ def main() -> None: with args.version_script.open('w') as version_script: with args.symbol_list.open('w') as symbol_list: generator = Generator(src_file, version_script, symbol_list, - args.arch, api, args.llndk, args.apex) + filt) generator.write(versions) diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py index c8cd056a4..450719bfc 100755 --- a/cc/ndkstubgen/test_ndkstubgen.py +++ b/cc/ndkstubgen/test_ndkstubgen.py @@ -18,6 +18,7 @@ import io import textwrap import unittest +from copy import copy import symbolfile from symbolfile import Arch, Tags @@ -29,6 +30,9 @@ import ndkstubgen class GeneratorTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = symbolfile.Filter(Arch('arm'), 9, False, False) + def test_omit_version(self) -> None: # Thorough testing of the cases involved here is handled by # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest. @@ -37,7 +41,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) version = symbolfile.Version('VERSION_PRIVATE', None, Tags(), [ symbolfile.Symbol('foo', Tags()), @@ -70,7 +74,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) version = symbolfile.Version('VERSION_1', None, Tags(), [ symbolfile.Symbol('foo', Tags.from_strs(['x86'])), @@ -106,7 +110,7 @@ class GeneratorTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) versions = [ symbolfile.Version('VERSION_1', None, Tags(), [ @@ -162,6 +166,9 @@ class GeneratorTest(unittest.TestCase): class IntegrationTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = symbolfile.Filter(Arch('arm'), 9, False, False) + def test_integration(self) -> None: api_map = { 'O': 9000, @@ -199,8 +206,7 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9, False, False) + parser = symbolfile.SymbolFileParser(input_file, api_map, self.filter) versions = parser.parse() src_file = io.StringIO() @@ -208,7 +214,7 @@ class IntegrationTest(unittest.TestCase): symbol_list_file = io.StringIO() generator = ndkstubgen.Generator(src_file, version_file, symbol_list_file, - Arch('arm'), 9, False, False) + self.filter) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -263,16 +269,18 @@ class IntegrationTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9001, False, False) + f = copy(self.filter) + f.api = 9001 + parser = symbolfile.SymbolFileParser(input_file, api_map, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.api = 9001 generator = ndkstubgen.Generator(src_file, - version_file, symbol_list_file, - Arch('arm'), 9001, False, False) + version_file, symbol_list_file, f) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -322,8 +330,9 @@ class IntegrationTest(unittest.TestCase): } VERSION_2; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + f = copy(self.filter) + f.api = 16 + parser = symbolfile.SymbolFileParser(input_file, {}, f) with self.assertRaises( symbolfile.MultiplyDefinedSymbolError) as ex_context: @@ -370,16 +379,18 @@ class IntegrationTest(unittest.TestCase): wobble; } VERSION_4; """)) - parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'), - 9, False, True) + f = copy(self.filter) + f.apex = True + parser = symbolfile.SymbolFileParser(input_file, api_map, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.apex = True generator = ndkstubgen.Generator(src_file, - version_file, symbol_list_file, - Arch('arm'), 9, False, True) + version_file, symbol_list_file, f) generator.write(versions) expected_src = textwrap.dedent("""\ @@ -428,20 +439,19 @@ class IntegrationTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), - 9, llndk=False, apex=True) + f = copy(self.filter) + f.apex = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) versions = parser.parse() src_file = io.StringIO() version_file = io.StringIO() symbol_list_file = io.StringIO() + f = copy(self.filter) + f.apex = True generator = ndkstubgen.Generator(src_file, version_file, - symbol_list_file, - Arch('arm'), - 9, - llndk=False, - apex=True) + symbol_list_file, f) generator.write(versions) self.assertEqual('', src_file.getvalue()) diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index f8d18414c..471a12f50 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -78,12 +78,17 @@ class Tags: @property def has_mode_tags(self) -> bool: """Returns True if any mode tags (apex, llndk, etc) are set.""" - return self.has_apex_tags or self.has_llndk_tags + return self.has_apex_tags or self.has_llndk_tags or self.has_systemapi_tags @property def has_apex_tags(self) -> bool: """Returns True if any APEX tags are set.""" - return 'apex' in self.tags or 'systemapi' in self.tags + return 'apex' in self.tags + + @property + def has_systemapi_tags(self) -> bool: + """Returns True if any APEX tags are set.""" + return 'systemapi' in self.tags @property def has_llndk_tags(self) -> bool: @@ -198,50 +203,57 @@ def get_tag_value(tag: Tag) -> str: """ return split_tag(tag)[1] - -def _should_omit_tags(tags: Tags, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the tagged object should be omitted. - - This defines the rules shared between version tagging and symbol tagging. +class Filter: + """A filter encapsulates a condition that tells whether a version or a + symbol should be omitted or not """ - # The apex and llndk tags will only exclude APIs from other modes. If in - # APEX or LLNDK mode and neither tag is provided, we fall back to the - # default behavior because all NDK symbols are implicitly available to APEX - # and LLNDK. - if tags.has_mode_tags: - if not apex and not llndk: + + def __init__(self, arch: Arch, api: int, llndk: bool = False, apex: bool = False, systemapi: bool = False): + self.arch = arch + self.api = api + self.llndk = llndk + self.apex = apex + self.systemapi = systemapi + + def _should_omit_tags(self, tags: Tags) -> bool: + """Returns True if the tagged object should be omitted. + + This defines the rules shared between version tagging and symbol tagging. + """ + # The apex and llndk tags will only exclude APIs from other modes. If in + # APEX or LLNDK mode and neither tag is provided, we fall back to the + # default behavior because all NDK symbols are implicitly available to + # APEX and LLNDK. + if tags.has_mode_tags: + if self.apex and tags.has_apex_tags: + return False + if self.llndk and tags.has_llndk_tags: + return False + if self.systemapi and tags.has_systemapi_tags: + return False return True - if apex and not tags.has_apex_tags: + if not symbol_in_arch(tags, self.arch): return True - if llndk and not tags.has_llndk_tags: + if not symbol_in_api(tags, self.arch, self.api): return True - if not symbol_in_arch(tags, arch): - return True - if not symbol_in_api(tags, arch, api): - return True - return False + return False + def should_omit_version(self, version: Version) -> bool: + """Returns True if the version section should be omitted. -def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the version section should be omitted. + We want to omit any sections that do not have any symbols we'll have in + the stub library. Sections that contain entirely future symbols or only + symbols for certain architectures. + """ + if version.is_private: + return True + if version.tags.has_platform_only_tags: + return True + return self._should_omit_tags(version.tags) - We want to omit any sections that do not have any symbols we'll have in the - stub library. Sections that contain entirely future symbols or only symbols - for certain architectures. - """ - if version.is_private: - return True - if version.tags.has_platform_only_tags: - return True - return _should_omit_tags(version.tags, arch, api, llndk, apex) - - -def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool, - apex: bool) -> bool: - """Returns True if the symbol should be omitted.""" - return _should_omit_tags(symbol.tags, arch, api, llndk, apex) + def should_omit_symbol(self, symbol: Symbol) -> bool: + """Returns True if the symbol should be omitted.""" + return self._should_omit_tags(symbol.tags) def symbol_in_arch(tags: Tags, arch: Arch) -> bool: @@ -316,14 +328,10 @@ class MultiplyDefinedSymbolError(RuntimeError): class SymbolFileParser: """Parses NDK symbol files.""" - def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch, - api: int, llndk: bool, apex: bool) -> None: + def __init__(self, input_file: TextIO, api_map: ApiMap, filt: Filter) -> None: self.input_file = input_file self.api_map = api_map - self.arch = arch - self.api = api - self.llndk = llndk - self.apex = apex + self.filter = filt self.current_line: Optional[str] = None def parse(self) -> List[Version]: @@ -352,13 +360,11 @@ class SymbolFileParser: symbol_names = set() multiply_defined_symbols = set() for version in versions: - if should_omit_version(version, self.arch, self.api, self.llndk, - self.apex): + if self.filter.should_omit_version(version): continue for symbol in version.symbols: - if should_omit_symbol(symbol, self.arch, self.api, self.llndk, - self.apex): + if self.filter.should_omit_symbol(symbol): continue if symbol.name in symbol_names: diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index c1e821904..e17a8d01d 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -19,7 +19,8 @@ import textwrap import unittest import symbolfile -from symbolfile import Arch, Tag, Tags, Version +from symbolfile import Arch, Tag, Tags, Version, Symbol, Filter +from copy import copy # pylint: disable=missing-docstring @@ -202,178 +203,188 @@ class SymbolPresenceTest(unittest.TestCase): class OmitVersionTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 9) + self.version = Version('foo', None, Tags(), []) + + def assertOmit(self, f: Filter, v: Version) -> None: + self.assertTrue(f.should_omit_version(v)) + + def assertInclude(self, f: Filter, v: Version) -> None: + self.assertFalse(f.should_omit_version(v)) + def test_omit_private(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) + f = self.filter + v = self.version - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo_PRIVATE', None, Tags(), []), - Arch('arm'), 9, False, False)) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo_PLATFORM', None, Tags(), []), - Arch('arm'), 9, False, False)) + self.assertInclude(f, v) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['platform-only']), []), - Arch('arm'), 9, False, False)) + v.name = 'foo_PRIVATE' + self.assertOmit(f, v) + + v.name = 'foo_PLATFORM' + self.assertOmit(f, v) + + v.name = 'foo' + v.tags = Tags.from_strs(['platform-only']) + self.assertOmit(f, v) def test_omit_llndk(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []), - Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_llndk = copy(v) + v_llndk.tags = Tags.from_strs(['llndk']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - True, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []), - Arch('arm'), 9, True, False)) + self.assertOmit(f, v_llndk) + + f.llndk = True + self.assertInclude(f, v) + self.assertInclude(f, v_llndk) def test_omit_apex(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['apex']), []), - Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_apex = copy(v) + v_apex.tags = Tags.from_strs(['apex']) + v_systemapi = copy(v) + v_systemapi.tags = Tags.from_strs(['systemapi']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, True)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['apex']), []), - Arch('arm'), 9, False, True)) + self.assertOmit(f, v_apex) + + f.apex = True + self.assertInclude(f, v) + self.assertInclude(f, v_apex) + self.assertOmit(f, v_systemapi) def test_omit_systemapi(self) -> None: - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['systemapi']), - []), Arch('arm'), 9, False, False)) + f = self.filter + v = self.version + v_apex = copy(v) + v_apex.tags = Tags.from_strs(['apex']) + v_systemapi = copy(v) + v_systemapi.tags = Tags.from_strs(['systemapi']) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, True)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['systemapi']), - []), Arch('arm'), 9, False, True)) + self.assertOmit(f, v_systemapi) + + f.systemapi = True + self.assertInclude(f, v) + self.assertInclude(f, v_systemapi) + self.assertOmit(f, v_apex) def test_omit_arch(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['arm']), []), - Arch('arm'), 9, False, False)) + f_arm = self.filter + v_none = self.version + self.assertInclude(f_arm, v_none) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags.from_strs(['x86']), []), - Arch('arm'), 9, False, False)) + v_arm = copy(v_none) + v_arm.tags = Tags.from_strs(['arm']) + self.assertInclude(f_arm, v_arm) + + v_x86 = copy(v_none) + v_x86.tags = Tags.from_strs(['x86']) + self.assertOmit(f_arm, v_x86) def test_omit_api(self) -> None: - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9, - False, False)) - self.assertFalse( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['introduced=9']), []), - Arch('arm'), 9, False, False)) + f_api9 = self.filter + v_none = self.version + self.assertInclude(f_api9, v_none) - self.assertTrue( - symbolfile.should_omit_version( - symbolfile.Version('foo', None, - Tags.from_strs(['introduced=14']), []), - Arch('arm'), 9, False, False)) + v_api9 = copy(v_none) + v_api9.tags = Tags.from_strs(['introduced=9']) + self.assertInclude(f_api9, v_api9) + + v_api14 = copy(v_none) + v_api14.tags = Tags.from_strs(['introduced=14']) + self.assertOmit(f_api9, v_api14) class OmitSymbolTest(unittest.TestCase): - def test_omit_llndk(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['llndk'])), - Arch('arm'), 9, False, False)) + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 9) - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, True, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['llndk'])), - Arch('arm'), 9, True, False)) + def assertOmit(self, f: Filter, s: Symbol) -> None: + self.assertTrue(f.should_omit_symbol(s)) + + def assertInclude(self, f: Filter, s: Symbol) -> None: + self.assertFalse(f.should_omit_symbol(s)) + + def test_omit_llndk(self) -> None: + f_none = self.filter + f_llndk = copy(f_none) + f_llndk.llndk = True + + s_none = Symbol('foo', Tags()) + s_llndk = Symbol('foo', Tags.from_strs(['llndk'])) + + self.assertOmit(f_none, s_llndk) + self.assertInclude(f_llndk, s_none) + self.assertInclude(f_llndk, s_llndk) def test_omit_apex(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['apex'])), - Arch('arm'), 9, False, False)) + f_none = self.filter + f_apex = copy(f_none) + f_apex.apex = True - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, True)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['apex'])), - Arch('arm'), 9, False, True)) + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) + + self.assertOmit(f_none, s_apex) + self.assertInclude(f_apex, s_none) + self.assertInclude(f_apex, s_apex) + self.assertOmit(f_apex, s_systemapi) def test_omit_systemapi(self) -> None: - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])), - Arch('arm'), 9, False, False)) + f_none = self.filter + f_systemapi = copy(f_none) + f_systemapi.systemapi = True - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, True)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])), - Arch('arm'), 9, False, True)) + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) + + self.assertOmit(f_none, s_systemapi) + self.assertInclude(f_systemapi, s_none) + self.assertInclude(f_systemapi, s_systemapi) + self.assertOmit(f_systemapi, s_apex) + + def test_omit_apex_and_systemapi(self) -> None: + f = self.filter + f.systemapi = True + f.apex = True + + s_none = Symbol('foo', Tags()) + s_apex = Symbol('foo', Tags.from_strs(['apex'])) + s_systemapi = Symbol('foo', Tags.from_strs(['systemapi'])) + self.assertInclude(f, s_none) + self.assertInclude(f, s_apex) + self.assertInclude(f, s_systemapi) def test_omit_arch(self) -> None: - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['arm'])), Arch('arm'), - 9, False, False)) + f_arm = self.filter + s_none = Symbol('foo', Tags()) + s_arm = Symbol('foo', Tags.from_strs(['arm'])) + s_x86 = Symbol('foo', Tags.from_strs(['x86'])) - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['x86'])), Arch('arm'), - 9, False, False)) + self.assertInclude(f_arm, s_none) + self.assertInclude(f_arm, s_arm) + self.assertOmit(f_arm, s_x86) def test_omit_api(self) -> None: - self.assertFalse( - symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()), - Arch('arm'), 9, False, False)) - self.assertFalse( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['introduced=9'])), - Arch('arm'), 9, False, False)) + f_api9 = self.filter + s_none = Symbol('foo', Tags()) + s_api9 = Symbol('foo', Tags.from_strs(['introduced=9'])) + s_api14 = Symbol('foo', Tags.from_strs(['introduced=14'])) - self.assertTrue( - symbolfile.should_omit_symbol( - symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])), - Arch('arm'), 9, False, False)) + self.assertInclude(f_api9, s_none) + self.assertInclude(f_api9, s_api9) + self.assertOmit(f_api9, s_api14) class SymbolFileParseTest(unittest.TestCase): + def setUp(self) -> None: + self.filter = Filter(arch = Arch('arm'), api = 16) + def test_next_line(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo @@ -382,8 +393,7 @@ class SymbolFileParseTest(unittest.TestCase): # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) self.assertIsNone(parser.current_line) self.assertEqual('foo', parser.next_line().strip()) @@ -409,8 +419,7 @@ class SymbolFileParseTest(unittest.TestCase): VERSION_2 { } VERSION_1; # asdf """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() version = parser.parse_version() @@ -419,8 +428,8 @@ class SymbolFileParseTest(unittest.TestCase): self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags) expected_symbols = [ - symbolfile.Symbol('baz', Tags()), - symbolfile.Symbol('qux', Tags.from_strs(['woodly', 'doodly'])), + Symbol('baz', Tags()), + Symbol('qux', Tags.from_strs(['woodly', 'doodly'])), ] self.assertEqual(expected_symbols, version.symbols) @@ -434,8 +443,7 @@ class SymbolFileParseTest(unittest.TestCase): input_file = io.StringIO(textwrap.dedent("""\ VERSION_1 { """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -446,8 +454,7 @@ class SymbolFileParseTest(unittest.TestCase): foo: } """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -457,8 +464,7 @@ class SymbolFileParseTest(unittest.TestCase): foo; bar; # baz qux """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() symbol = parser.parse_symbol() @@ -476,8 +482,7 @@ class SymbolFileParseTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -489,8 +494,7 @@ class SymbolFileParseTest(unittest.TestCase): *; }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() version = parser.parse_version() self.assertEqual([], version.symbols) @@ -501,8 +505,7 @@ class SymbolFileParseTest(unittest.TestCase): foo }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.next_line() with self.assertRaises(symbolfile.ParseError): parser.parse_version() @@ -510,8 +513,7 @@ class SymbolFileParseTest(unittest.TestCase): def test_parse_fails_invalid_input(self) -> None: with self.assertRaises(symbolfile.ParseError): input_file = io.StringIO('foo') - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), - 16, False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) parser.parse() def test_parse(self) -> None: @@ -532,19 +534,18 @@ class SymbolFileParseTest(unittest.TestCase): qwerty; } VERSION_1; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, False) + parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) versions = parser.parse() expected = [ symbolfile.Version('VERSION_1', None, Tags(), [ - symbolfile.Symbol('foo', Tags()), - symbolfile.Symbol('bar', Tags.from_strs(['baz'])), + Symbol('foo', Tags()), + Symbol('bar', Tags.from_strs(['baz'])), ]), symbolfile.Version( 'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [ - symbolfile.Symbol('woodly', Tags()), - symbolfile.Symbol('doodly', Tags.from_strs(['asdf'])), + Symbol('woodly', Tags()), + Symbol('doodly', Tags.from_strs(['asdf'])), ]), ] @@ -559,8 +560,9 @@ class SymbolFileParseTest(unittest.TestCase): qux; # apex }; """)) - parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16, - False, True) + f = copy(self.filter) + f.llndk = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) parser.next_line() version = parser.parse_version() @@ -568,10 +570,10 @@ class SymbolFileParseTest(unittest.TestCase): self.assertIsNone(version.base) expected_symbols = [ - symbolfile.Symbol('foo', Tags()), - symbolfile.Symbol('bar', Tags.from_strs(['llndk'])), - symbolfile.Symbol('baz', Tags.from_strs(['llndk', 'apex'])), - symbolfile.Symbol('qux', Tags.from_strs(['apex'])), + Symbol('foo', Tags()), + Symbol('bar', Tags.from_strs(['llndk'])), + Symbol('baz', Tags.from_strs(['llndk', 'apex'])), + Symbol('qux', Tags.from_strs(['apex'])), ] self.assertEqual(expected_symbols, version.symbols)