Add type information to symbolfile and ndkstubgen.
Test: mypy symbolfile Test: pytest Bug: None Change-Id: I6b1045d315e5a10e699d31de9fafc084d82768b2
This commit is contained in:
@@ -20,13 +20,16 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Iterable, TextIO
|
||||||
|
|
||||||
import symbolfile
|
import symbolfile
|
||||||
|
from symbolfile import Arch, Version
|
||||||
|
|
||||||
|
|
||||||
class Generator:
|
class Generator:
|
||||||
"""Output generator that writes stub source files and version scripts."""
|
"""Output generator that writes stub source files and version scripts."""
|
||||||
def __init__(self, src_file, version_script, arch, api, llndk, apex):
|
def __init__(self, src_file: TextIO, version_script: TextIO, arch: Arch,
|
||||||
|
api: int, llndk: bool, apex: bool) -> None:
|
||||||
self.src_file = src_file
|
self.src_file = src_file
|
||||||
self.version_script = version_script
|
self.version_script = version_script
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
@@ -34,12 +37,12 @@ class Generator:
|
|||||||
self.llndk = llndk
|
self.llndk = llndk
|
||||||
self.apex = apex
|
self.apex = apex
|
||||||
|
|
||||||
def write(self, versions):
|
def write(self, versions: Iterable[Version]) -> None:
|
||||||
"""Writes all symbol data to the output files."""
|
"""Writes all symbol data to the output files."""
|
||||||
for version in versions:
|
for version in versions:
|
||||||
self.write_version(version)
|
self.write_version(version)
|
||||||
|
|
||||||
def write_version(self, version):
|
def write_version(self, version: Version) -> None:
|
||||||
"""Writes a single version block's data to the output files."""
|
"""Writes a single version block's data to the output files."""
|
||||||
if symbolfile.should_omit_version(version, self.arch, self.api,
|
if symbolfile.should_omit_version(version, self.arch, self.api,
|
||||||
self.llndk, self.apex):
|
self.llndk, self.apex):
|
||||||
@@ -84,7 +87,7 @@ class Generator:
|
|||||||
self.version_script.write('}' + base + ';\n')
|
self.version_script.write('}' + base + ';\n')
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args() -> argparse.Namespace:
|
||||||
"""Parses and returns command line arguments."""
|
"""Parses and returns command line arguments."""
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
@@ -100,23 +103,31 @@ def parse_args():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--apex', action='store_true', help='Use the APEX variant.')
|
'--apex', action='store_true', help='Use the APEX variant.')
|
||||||
|
|
||||||
|
# https://github.com/python/mypy/issues/1317
|
||||||
|
# mypy has issues with using os.path.realpath as an argument here.
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--api-map', type=os.path.realpath, required=True,
|
'--api-map',
|
||||||
|
type=os.path.realpath, # type: ignore
|
||||||
|
required=True,
|
||||||
help='Path to the API level map JSON file.')
|
help='Path to the API level map JSON file.')
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'symbol_file', type=os.path.realpath, help='Path to symbol file.')
|
'symbol_file',
|
||||||
|
type=os.path.realpath, # type: ignore
|
||||||
|
help='Path to symbol file.')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'stub_src', type=os.path.realpath,
|
'stub_src',
|
||||||
|
type=os.path.realpath, # type: ignore
|
||||||
help='Path to output stub source file.')
|
help='Path to output stub source file.')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'version_script', type=os.path.realpath,
|
'version_script',
|
||||||
|
type=os.path.realpath, # type: ignore
|
||||||
help='Path to output version script.')
|
help='Path to output version script.')
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
"""Program entry point."""
|
"""Program entry point."""
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
|
2
cc/ndkstubgen/mypy.ini
Normal file
2
cc/ndkstubgen/mypy.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[mypy]
|
||||||
|
disallow_untyped_defs = True
|
@@ -21,19 +21,20 @@ import unittest
|
|||||||
|
|
||||||
import ndkstubgen
|
import ndkstubgen
|
||||||
import symbolfile
|
import symbolfile
|
||||||
|
from symbolfile import Arch, Tag
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=missing-docstring
|
# pylint: disable=missing-docstring
|
||||||
|
|
||||||
|
|
||||||
class GeneratorTest(unittest.TestCase):
|
class GeneratorTest(unittest.TestCase):
|
||||||
def test_omit_version(self):
|
def test_omit_version(self) -> None:
|
||||||
# Thorough testing of the cases involved here is handled by
|
# Thorough testing of the cases involved here is handled by
|
||||||
# OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
|
# OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, False)
|
9, False, False)
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION_PRIVATE', None, [], [
|
version = symbolfile.Version('VERSION_PRIVATE', None, [], [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
@@ -42,74 +43,75 @@ class GeneratorTest(unittest.TestCase):
|
|||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION', None, ['x86'], [
|
version = symbolfile.Version('VERSION', None, [Tag('x86')], [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION', None, ['introduced=14'], [
|
version = symbolfile.Version('VERSION', None, [Tag('introduced=14')], [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
def test_omit_symbol(self):
|
def test_omit_symbol(self) -> None:
|
||||||
# Thorough testing of the cases involved here is handled by
|
# Thorough testing of the cases involved here is handled by
|
||||||
# SymbolPresenceTest.
|
# SymbolPresenceTest.
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, False)
|
9, False, False)
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION_1', None, [], [
|
version = symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', ['x86']),
|
symbolfile.Symbol('foo', [Tag('x86')]),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION_1', None, [], [
|
version = symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', ['introduced=14']),
|
symbolfile.Symbol('foo', [Tag('introduced=14')]),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION_1', None, [], [
|
version = symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', ['llndk']),
|
symbolfile.Symbol('foo', [Tag('llndk')]),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
version = symbolfile.Version('VERSION_1', None, [], [
|
version = symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', ['apex']),
|
symbolfile.Symbol('foo', [Tag('apex')]),
|
||||||
])
|
])
|
||||||
generator.write_version(version)
|
generator.write_version(version)
|
||||||
self.assertEqual('', src_file.getvalue())
|
self.assertEqual('', src_file.getvalue())
|
||||||
self.assertEqual('', version_file.getvalue())
|
self.assertEqual('', version_file.getvalue())
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self) -> None:
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, False)
|
9, False, False)
|
||||||
|
|
||||||
versions = [
|
versions = [
|
||||||
symbolfile.Version('VERSION_1', None, [], [
|
symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
symbolfile.Symbol('bar', ['var']),
|
symbolfile.Symbol('bar', [Tag('var')]),
|
||||||
symbolfile.Symbol('woodly', ['weak']),
|
symbolfile.Symbol('woodly', [Tag('weak')]),
|
||||||
symbolfile.Symbol('doodly', ['weak', 'var']),
|
symbolfile.Symbol('doodly',
|
||||||
|
[Tag('weak'), Tag('var')]),
|
||||||
]),
|
]),
|
||||||
symbolfile.Version('VERSION_2', 'VERSION_1', [], [
|
symbolfile.Version('VERSION_2', 'VERSION_1', [], [
|
||||||
symbolfile.Symbol('baz', []),
|
symbolfile.Symbol('baz', []),
|
||||||
]),
|
]),
|
||||||
symbolfile.Version('VERSION_3', 'VERSION_1', [], [
|
symbolfile.Version('VERSION_3', 'VERSION_1', [], [
|
||||||
symbolfile.Symbol('qux', ['versioned=14']),
|
symbolfile.Symbol('qux', [Tag('versioned=14')]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -141,7 +143,7 @@ class GeneratorTest(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class IntegrationTest(unittest.TestCase):
|
class IntegrationTest(unittest.TestCase):
|
||||||
def test_integration(self):
|
def test_integration(self) -> None:
|
||||||
api_map = {
|
api_map = {
|
||||||
'O': 9000,
|
'O': 9000,
|
||||||
'P': 9001,
|
'P': 9001,
|
||||||
@@ -178,14 +180,14 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
wobble;
|
wobble;
|
||||||
} VERSION_4;
|
} VERSION_4;
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9,
|
parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
|
||||||
False, False)
|
9, False, False)
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, False)
|
9, False, False)
|
||||||
generator.write(versions)
|
generator.write(versions)
|
||||||
|
|
||||||
expected_src = textwrap.dedent("""\
|
expected_src = textwrap.dedent("""\
|
||||||
@@ -213,7 +215,7 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
""")
|
""")
|
||||||
self.assertEqual(expected_version, version_file.getvalue())
|
self.assertEqual(expected_version, version_file.getvalue())
|
||||||
|
|
||||||
def test_integration_future_api(self):
|
def test_integration_future_api(self) -> None:
|
||||||
api_map = {
|
api_map = {
|
||||||
'O': 9000,
|
'O': 9000,
|
||||||
'P': 9001,
|
'P': 9001,
|
||||||
@@ -230,14 +232,14 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9001,
|
parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
|
||||||
False, False)
|
9001, False, False)
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9001,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, False)
|
9001, False, False)
|
||||||
generator.write(versions)
|
generator.write(versions)
|
||||||
|
|
||||||
expected_src = textwrap.dedent("""\
|
expected_src = textwrap.dedent("""\
|
||||||
@@ -255,7 +257,7 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
""")
|
""")
|
||||||
self.assertEqual(expected_version, version_file.getvalue())
|
self.assertEqual(expected_version, version_file.getvalue())
|
||||||
|
|
||||||
def test_multiple_definition(self):
|
def test_multiple_definition(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
global:
|
global:
|
||||||
@@ -280,8 +282,8 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
} VERSION_2;
|
} VERSION_2;
|
||||||
|
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False,
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
False)
|
False, False)
|
||||||
|
|
||||||
with self.assertRaises(
|
with self.assertRaises(
|
||||||
symbolfile.MultiplyDefinedSymbolError) as ex_context:
|
symbolfile.MultiplyDefinedSymbolError) as ex_context:
|
||||||
@@ -289,7 +291,7 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
self.assertEqual(['bar', 'foo'],
|
self.assertEqual(['bar', 'foo'],
|
||||||
ex_context.exception.multiply_defined_symbols)
|
ex_context.exception.multiply_defined_symbols)
|
||||||
|
|
||||||
def test_integration_with_apex(self):
|
def test_integration_with_apex(self) -> None:
|
||||||
api_map = {
|
api_map = {
|
||||||
'O': 9000,
|
'O': 9000,
|
||||||
'P': 9001,
|
'P': 9001,
|
||||||
@@ -328,14 +330,14 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
wobble;
|
wobble;
|
||||||
} VERSION_4;
|
} VERSION_4;
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9,
|
parser = symbolfile.SymbolFileParser(input_file, api_map, Arch('arm'),
|
||||||
False, True)
|
9, False, True)
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
src_file = io.StringIO()
|
src_file = io.StringIO()
|
||||||
version_file = io.StringIO()
|
version_file = io.StringIO()
|
||||||
generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
|
generator = ndkstubgen.Generator(src_file, version_file, Arch('arm'),
|
||||||
False, True)
|
9, False, True)
|
||||||
generator.write(versions)
|
generator.write(versions)
|
||||||
|
|
||||||
expected_src = textwrap.dedent("""\
|
expected_src = textwrap.dedent("""\
|
||||||
@@ -369,7 +371,8 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
""")
|
""")
|
||||||
self.assertEqual(expected_version, version_file.getvalue())
|
self.assertEqual(expected_version, version_file.getvalue())
|
||||||
|
|
||||||
def main():
|
|
||||||
|
def main() -> None:
|
||||||
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
unittest.TextTestRunner(verbosity=3).run(suite)
|
unittest.TextTestRunner(verbosity=3).run(suite)
|
||||||
|
|
||||||
|
@@ -14,15 +14,31 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
"""Parser for Android's version script information."""
|
"""Parser for Android's version script information."""
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from typing import (
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Mapping,
|
||||||
|
NewType,
|
||||||
|
Optional,
|
||||||
|
TextIO,
|
||||||
|
Tuple,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ApiMap = Mapping[str, int]
|
||||||
|
Arch = NewType('Arch', str)
|
||||||
|
Tag = NewType('Tag', str)
|
||||||
|
|
||||||
|
|
||||||
ALL_ARCHITECTURES = (
|
ALL_ARCHITECTURES = (
|
||||||
'arm',
|
Arch('arm'),
|
||||||
'arm64',
|
Arch('arm64'),
|
||||||
'x86',
|
Arch('x86'),
|
||||||
'x86_64',
|
Arch('x86_64'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -30,18 +46,36 @@ ALL_ARCHITECTURES = (
|
|||||||
FUTURE_API_LEVEL = 10000
|
FUTURE_API_LEVEL = 10000
|
||||||
|
|
||||||
|
|
||||||
def logger():
|
def logger() -> logging.Logger:
|
||||||
"""Return the main logger for this module."""
|
"""Return the main logger for this module."""
|
||||||
return logging.getLogger(__name__)
|
return logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_tags(line):
|
@dataclass
|
||||||
|
class Symbol:
|
||||||
|
"""A symbol definition from a symbol file."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
tags: List[Tag]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Version:
|
||||||
|
"""A version block of a symbol file."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
base: Optional[str]
|
||||||
|
tags: List[Tag]
|
||||||
|
symbols: List[Symbol]
|
||||||
|
|
||||||
|
|
||||||
|
def get_tags(line: str) -> List[Tag]:
|
||||||
"""Returns a list of all tags on this line."""
|
"""Returns a list of all tags on this line."""
|
||||||
_, _, all_tags = line.strip().partition('#')
|
_, _, all_tags = line.strip().partition('#')
|
||||||
return [e for e in re.split(r'\s+', all_tags) if e.strip()]
|
return [Tag(e) for e in re.split(r'\s+', all_tags) if e.strip()]
|
||||||
|
|
||||||
|
|
||||||
def is_api_level_tag(tag):
|
def is_api_level_tag(tag: Tag) -> bool:
|
||||||
"""Returns true if this tag has an API level that may need decoding."""
|
"""Returns true if this tag has an API level that may need decoding."""
|
||||||
if tag.startswith('introduced='):
|
if tag.startswith('introduced='):
|
||||||
return True
|
return True
|
||||||
@@ -52,7 +86,7 @@ def is_api_level_tag(tag):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def decode_api_level(api, api_map):
|
def decode_api_level(api: str, api_map: ApiMap) -> int:
|
||||||
"""Decodes the API level argument into the API level number.
|
"""Decodes the API level argument into the API level number.
|
||||||
|
|
||||||
For the average case, this just decodes the integer value from the string,
|
For the average case, this just decodes the integer value from the string,
|
||||||
@@ -70,12 +104,13 @@ def decode_api_level(api, api_map):
|
|||||||
return api_map[api]
|
return api_map[api]
|
||||||
|
|
||||||
|
|
||||||
def decode_api_level_tags(tags, api_map):
|
def decode_api_level_tags(tags: Iterable[Tag], api_map: ApiMap) -> List[Tag]:
|
||||||
"""Decodes API level code names in a list of tags.
|
"""Decodes API level code names in a list of tags.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ParseError: An unknown version name was found in a tag.
|
ParseError: An unknown version name was found in a tag.
|
||||||
"""
|
"""
|
||||||
|
decoded_tags = list(tags)
|
||||||
for idx, tag in enumerate(tags):
|
for idx, tag in enumerate(tags):
|
||||||
if not is_api_level_tag(tag):
|
if not is_api_level_tag(tag):
|
||||||
continue
|
continue
|
||||||
@@ -83,13 +118,13 @@ def decode_api_level_tags(tags, api_map):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
decoded = str(decode_api_level(value, api_map))
|
decoded = str(decode_api_level(value, api_map))
|
||||||
tags[idx] = '='.join([name, decoded])
|
decoded_tags[idx] = Tag('='.join([name, decoded]))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ParseError('Unknown version name in tag: {}'.format(tag))
|
raise ParseError(f'Unknown version name in tag: {tag}')
|
||||||
return tags
|
return decoded_tags
|
||||||
|
|
||||||
|
|
||||||
def split_tag(tag):
|
def split_tag(tag: Tag) -> Tuple[str, str]:
|
||||||
"""Returns a key/value tuple of the tag.
|
"""Returns a key/value tuple of the tag.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -103,7 +138,7 @@ def split_tag(tag):
|
|||||||
return key, value
|
return key, value
|
||||||
|
|
||||||
|
|
||||||
def get_tag_value(tag):
|
def get_tag_value(tag: Tag) -> str:
|
||||||
"""Returns the value of a key/value tag.
|
"""Returns the value of a key/value tag.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -114,12 +149,13 @@ def get_tag_value(tag):
|
|||||||
return split_tag(tag)[1]
|
return split_tag(tag)[1]
|
||||||
|
|
||||||
|
|
||||||
def version_is_private(version):
|
def version_is_private(version: str) -> bool:
|
||||||
"""Returns True if the version name should be treated as private."""
|
"""Returns True if the version name should be treated as private."""
|
||||||
return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
|
return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
|
||||||
|
|
||||||
|
|
||||||
def should_omit_version(version, arch, api, llndk, apex):
|
def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool,
|
||||||
|
apex: bool) -> bool:
|
||||||
"""Returns True if the version section should be ommitted.
|
"""Returns True if the version section should be ommitted.
|
||||||
|
|
||||||
We want to omit any sections that do not have any symbols we'll have in the
|
We want to omit any sections that do not have any symbols we'll have in the
|
||||||
@@ -145,7 +181,8 @@ def should_omit_version(version, arch, api, llndk, apex):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def should_omit_symbol(symbol, 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."""
|
"""Returns True if the symbol should be omitted."""
|
||||||
no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags
|
no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags
|
||||||
keep = no_llndk_no_apex or \
|
keep = no_llndk_no_apex or \
|
||||||
@@ -160,7 +197,7 @@ def should_omit_symbol(symbol, arch, api, llndk, apex):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def symbol_in_arch(tags, arch):
|
def symbol_in_arch(tags: Iterable[Tag], arch: Arch) -> bool:
|
||||||
"""Returns true if the symbol is present for the given architecture."""
|
"""Returns true if the symbol is present for the given architecture."""
|
||||||
has_arch_tags = False
|
has_arch_tags = False
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
@@ -175,7 +212,7 @@ def symbol_in_arch(tags, arch):
|
|||||||
return not has_arch_tags
|
return not has_arch_tags
|
||||||
|
|
||||||
|
|
||||||
def symbol_in_api(tags, arch, api):
|
def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
|
||||||
"""Returns true if the symbol is present for the given API level."""
|
"""Returns true if the symbol is present for the given API level."""
|
||||||
introduced_tag = None
|
introduced_tag = None
|
||||||
arch_specific = False
|
arch_specific = False
|
||||||
@@ -197,7 +234,7 @@ def symbol_in_api(tags, arch, api):
|
|||||||
return api >= int(get_tag_value(introduced_tag))
|
return api >= int(get_tag_value(introduced_tag))
|
||||||
|
|
||||||
|
|
||||||
def symbol_versioned_in_api(tags, api):
|
def symbol_versioned_in_api(tags: Iterable[Tag], api: int) -> bool:
|
||||||
"""Returns true if the symbol should be versioned for the given API.
|
"""Returns true if the symbol should be versioned for the given API.
|
||||||
|
|
||||||
This models the `versioned=API` tag. This should be a very uncommonly
|
This models the `versioned=API` tag. This should be a very uncommonly
|
||||||
@@ -223,68 +260,40 @@ class ParseError(RuntimeError):
|
|||||||
|
|
||||||
class MultiplyDefinedSymbolError(RuntimeError):
|
class MultiplyDefinedSymbolError(RuntimeError):
|
||||||
"""A symbol name was multiply defined."""
|
"""A symbol name was multiply defined."""
|
||||||
def __init__(self, multiply_defined_symbols):
|
def __init__(self, multiply_defined_symbols: Iterable[str]) -> None:
|
||||||
super(MultiplyDefinedSymbolError, self).__init__(
|
super().__init__(
|
||||||
'Version script contains multiple definitions for: {}'.format(
|
'Version script contains multiple definitions for: {}'.format(
|
||||||
', '.join(multiply_defined_symbols)))
|
', '.join(multiply_defined_symbols)))
|
||||||
self.multiply_defined_symbols = multiply_defined_symbols
|
self.multiply_defined_symbols = multiply_defined_symbols
|
||||||
|
|
||||||
|
|
||||||
class Version:
|
|
||||||
"""A version block of a symbol file."""
|
|
||||||
def __init__(self, name, base, tags, symbols):
|
|
||||||
self.name = name
|
|
||||||
self.base = base
|
|
||||||
self.tags = tags
|
|
||||||
self.symbols = symbols
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
if self.name != other.name:
|
|
||||||
return False
|
|
||||||
if self.base != other.base:
|
|
||||||
return False
|
|
||||||
if self.tags != other.tags:
|
|
||||||
return False
|
|
||||||
if self.symbols != other.symbols:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class Symbol:
|
|
||||||
"""A symbol definition from a symbol file."""
|
|
||||||
def __init__(self, name, tags):
|
|
||||||
self.name = name
|
|
||||||
self.tags = tags
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.name == other.name and set(self.tags) == set(other.tags)
|
|
||||||
|
|
||||||
|
|
||||||
class SymbolFileParser:
|
class SymbolFileParser:
|
||||||
"""Parses NDK symbol files."""
|
"""Parses NDK symbol files."""
|
||||||
def __init__(self, input_file, api_map, arch, api, llndk, apex):
|
def __init__(self, input_file: TextIO, api_map: ApiMap, arch: Arch,
|
||||||
|
api: int, llndk: bool, apex: bool) -> None:
|
||||||
self.input_file = input_file
|
self.input_file = input_file
|
||||||
self.api_map = api_map
|
self.api_map = api_map
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
self.api = api
|
self.api = api
|
||||||
self.llndk = llndk
|
self.llndk = llndk
|
||||||
self.apex = apex
|
self.apex = apex
|
||||||
self.current_line = None
|
self.current_line: Optional[str] = None
|
||||||
|
|
||||||
def parse(self):
|
def parse(self) -> List[Version]:
|
||||||
"""Parses the symbol file and returns a list of Version objects."""
|
"""Parses the symbol file and returns a list of Version objects."""
|
||||||
versions = []
|
versions = []
|
||||||
while self.next_line() != '':
|
while self.next_line() != '':
|
||||||
|
assert self.current_line is not None
|
||||||
if '{' in self.current_line:
|
if '{' in self.current_line:
|
||||||
versions.append(self.parse_version())
|
versions.append(self.parse_version())
|
||||||
else:
|
else:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
'Unexpected contents at top level: ' + self.current_line)
|
f'Unexpected contents at top level: {self.current_line}')
|
||||||
|
|
||||||
self.check_no_duplicate_symbols(versions)
|
self.check_no_duplicate_symbols(versions)
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
def check_no_duplicate_symbols(self, versions):
|
def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None:
|
||||||
"""Raises errors for multiply defined symbols.
|
"""Raises errors for multiply defined symbols.
|
||||||
|
|
||||||
This situation is the normal case when symbol versioning is actually
|
This situation is the normal case when symbol versioning is actually
|
||||||
@@ -312,12 +321,13 @@ class SymbolFileParser:
|
|||||||
raise MultiplyDefinedSymbolError(
|
raise MultiplyDefinedSymbolError(
|
||||||
sorted(list(multiply_defined_symbols)))
|
sorted(list(multiply_defined_symbols)))
|
||||||
|
|
||||||
def parse_version(self):
|
def parse_version(self) -> Version:
|
||||||
"""Parses a single version section and returns a Version object."""
|
"""Parses a single version section and returns a Version object."""
|
||||||
|
assert self.current_line is not None
|
||||||
name = self.current_line.split('{')[0].strip()
|
name = self.current_line.split('{')[0].strip()
|
||||||
tags = get_tags(self.current_line)
|
tags = get_tags(self.current_line)
|
||||||
tags = decode_api_level_tags(tags, self.api_map)
|
tags = decode_api_level_tags(tags, self.api_map)
|
||||||
symbols = []
|
symbols: List[Symbol] = []
|
||||||
global_scope = True
|
global_scope = True
|
||||||
cpp_symbols = False
|
cpp_symbols = False
|
||||||
while self.next_line() != '':
|
while self.next_line() != '':
|
||||||
@@ -333,9 +343,7 @@ class SymbolFileParser:
|
|||||||
cpp_symbols = False
|
cpp_symbols = False
|
||||||
else:
|
else:
|
||||||
base = base.rstrip(';').rstrip()
|
base = base.rstrip(';').rstrip()
|
||||||
if base == '':
|
return Version(name, base or None, tags, symbols)
|
||||||
base = None
|
|
||||||
return Version(name, base, tags, symbols)
|
|
||||||
elif 'extern "C++" {' in self.current_line:
|
elif 'extern "C++" {' in self.current_line:
|
||||||
cpp_symbols = True
|
cpp_symbols = True
|
||||||
elif not cpp_symbols and ':' in self.current_line:
|
elif not cpp_symbols and ':' in self.current_line:
|
||||||
@@ -354,8 +362,9 @@ class SymbolFileParser:
|
|||||||
pass
|
pass
|
||||||
raise ParseError('Unexpected EOF in version block.')
|
raise ParseError('Unexpected EOF in version block.')
|
||||||
|
|
||||||
def parse_symbol(self):
|
def parse_symbol(self) -> Symbol:
|
||||||
"""Parses a single symbol line and returns a Symbol object."""
|
"""Parses a single symbol line and returns a Symbol object."""
|
||||||
|
assert self.current_line is not None
|
||||||
if ';' not in self.current_line:
|
if ';' not in self.current_line:
|
||||||
raise ParseError(
|
raise ParseError(
|
||||||
'Expected ; to terminate symbol: ' + self.current_line)
|
'Expected ; to terminate symbol: ' + self.current_line)
|
||||||
@@ -368,7 +377,7 @@ class SymbolFileParser:
|
|||||||
tags = decode_api_level_tags(tags, self.api_map)
|
tags = decode_api_level_tags(tags, self.api_map)
|
||||||
return Symbol(name, tags)
|
return Symbol(name, tags)
|
||||||
|
|
||||||
def next_line(self):
|
def next_line(self) -> str:
|
||||||
"""Returns the next non-empty non-comment line.
|
"""Returns the next non-empty non-comment line.
|
||||||
|
|
||||||
A return value of '' indicates EOF.
|
A return value of '' indicates EOF.
|
||||||
|
2
cc/symbolfile/mypy.ini
Normal file
2
cc/symbolfile/mypy.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[mypy]
|
||||||
|
disallow_untyped_defs = True
|
@@ -19,12 +19,13 @@ import textwrap
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import symbolfile
|
import symbolfile
|
||||||
|
from symbolfile import Arch, Tag
|
||||||
|
|
||||||
# pylint: disable=missing-docstring
|
# pylint: disable=missing-docstring
|
||||||
|
|
||||||
|
|
||||||
class DecodeApiLevelTest(unittest.TestCase):
|
class DecodeApiLevelTest(unittest.TestCase):
|
||||||
def test_decode_api_level(self):
|
def test_decode_api_level(self) -> None:
|
||||||
self.assertEqual(9, symbolfile.decode_api_level('9', {}))
|
self.assertEqual(9, symbolfile.decode_api_level('9', {}))
|
||||||
self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000}))
|
self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000}))
|
||||||
|
|
||||||
@@ -33,70 +34,73 @@ class DecodeApiLevelTest(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TagsTest(unittest.TestCase):
|
class TagsTest(unittest.TestCase):
|
||||||
def test_get_tags_no_tags(self):
|
def test_get_tags_no_tags(self) -> None:
|
||||||
self.assertEqual([], symbolfile.get_tags(''))
|
self.assertEqual([], symbolfile.get_tags(''))
|
||||||
self.assertEqual([], symbolfile.get_tags('foo bar baz'))
|
self.assertEqual([], symbolfile.get_tags('foo bar baz'))
|
||||||
|
|
||||||
def test_get_tags(self):
|
def test_get_tags(self) -> None:
|
||||||
self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar'))
|
self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar'))
|
||||||
self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz'))
|
self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz'))
|
||||||
|
|
||||||
def test_split_tag(self):
|
def test_split_tag(self) -> None:
|
||||||
self.assertTupleEqual(('foo', 'bar'), symbolfile.split_tag('foo=bar'))
|
self.assertTupleEqual(('foo', 'bar'),
|
||||||
self.assertTupleEqual(('foo', 'bar=baz'), symbolfile.split_tag('foo=bar=baz'))
|
symbolfile.split_tag(Tag('foo=bar')))
|
||||||
|
self.assertTupleEqual(('foo', 'bar=baz'),
|
||||||
|
symbolfile.split_tag(Tag('foo=bar=baz')))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
symbolfile.split_tag('foo')
|
symbolfile.split_tag(Tag('foo'))
|
||||||
|
|
||||||
def test_get_tag_value(self):
|
def test_get_tag_value(self) -> None:
|
||||||
self.assertEqual('bar', symbolfile.get_tag_value('foo=bar'))
|
self.assertEqual('bar', symbolfile.get_tag_value(Tag('foo=bar')))
|
||||||
self.assertEqual('bar=baz', symbolfile.get_tag_value('foo=bar=baz'))
|
self.assertEqual('bar=baz',
|
||||||
|
symbolfile.get_tag_value(Tag('foo=bar=baz')))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
symbolfile.get_tag_value('foo')
|
symbolfile.get_tag_value(Tag('foo'))
|
||||||
|
|
||||||
def test_is_api_level_tag(self):
|
def test_is_api_level_tag(self) -> None:
|
||||||
self.assertTrue(symbolfile.is_api_level_tag('introduced=24'))
|
self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced=24')))
|
||||||
self.assertTrue(symbolfile.is_api_level_tag('introduced-arm=24'))
|
self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced-arm=24')))
|
||||||
self.assertTrue(symbolfile.is_api_level_tag('versioned=24'))
|
self.assertTrue(symbolfile.is_api_level_tag(Tag('versioned=24')))
|
||||||
|
|
||||||
# Shouldn't try to process things that aren't a key/value tag.
|
# Shouldn't try to process things that aren't a key/value tag.
|
||||||
self.assertFalse(symbolfile.is_api_level_tag('arm'))
|
self.assertFalse(symbolfile.is_api_level_tag(Tag('arm')))
|
||||||
self.assertFalse(symbolfile.is_api_level_tag('introduced'))
|
self.assertFalse(symbolfile.is_api_level_tag(Tag('introduced')))
|
||||||
self.assertFalse(symbolfile.is_api_level_tag('versioned'))
|
self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned')))
|
||||||
|
|
||||||
# We don't support arch specific `versioned` tags.
|
# We don't support arch specific `versioned` tags.
|
||||||
self.assertFalse(symbolfile.is_api_level_tag('versioned-arm=24'))
|
self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned-arm=24')))
|
||||||
|
|
||||||
def test_decode_api_level_tags(self):
|
def test_decode_api_level_tags(self) -> None:
|
||||||
api_map = {
|
api_map = {
|
||||||
'O': 9000,
|
'O': 9000,
|
||||||
'P': 9001,
|
'P': 9001,
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
'introduced=9',
|
Tag('introduced=9'),
|
||||||
'introduced-arm=14',
|
Tag('introduced-arm=14'),
|
||||||
'versioned=16',
|
Tag('versioned=16'),
|
||||||
'arm',
|
Tag('arm'),
|
||||||
'introduced=O',
|
Tag('introduced=O'),
|
||||||
'introduced=P',
|
Tag('introduced=P'),
|
||||||
]
|
]
|
||||||
expected_tags = [
|
expected_tags = [
|
||||||
'introduced=9',
|
Tag('introduced=9'),
|
||||||
'introduced-arm=14',
|
Tag('introduced-arm=14'),
|
||||||
'versioned=16',
|
Tag('versioned=16'),
|
||||||
'arm',
|
Tag('arm'),
|
||||||
'introduced=9000',
|
Tag('introduced=9000'),
|
||||||
'introduced=9001',
|
Tag('introduced=9001'),
|
||||||
]
|
]
|
||||||
self.assertListEqual(
|
self.assertListEqual(
|
||||||
expected_tags, symbolfile.decode_api_level_tags(tags, api_map))
|
expected_tags, symbolfile.decode_api_level_tags(tags, api_map))
|
||||||
|
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
symbolfile.decode_api_level_tags(['introduced=O'], {})
|
symbolfile.decode_api_level_tags([Tag('introduced=O')], {})
|
||||||
|
|
||||||
|
|
||||||
class PrivateVersionTest(unittest.TestCase):
|
class PrivateVersionTest(unittest.TestCase):
|
||||||
def test_version_is_private(self):
|
def test_version_is_private(self) -> None:
|
||||||
self.assertFalse(symbolfile.version_is_private('foo'))
|
self.assertFalse(symbolfile.version_is_private('foo'))
|
||||||
self.assertFalse(symbolfile.version_is_private('PRIVATE'))
|
self.assertFalse(symbolfile.version_is_private('PRIVATE'))
|
||||||
self.assertFalse(symbolfile.version_is_private('PLATFORM'))
|
self.assertFalse(symbolfile.version_is_private('PLATFORM'))
|
||||||
@@ -110,191 +114,227 @@ class PrivateVersionTest(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class SymbolPresenceTest(unittest.TestCase):
|
class SymbolPresenceTest(unittest.TestCase):
|
||||||
def test_symbol_in_arch(self):
|
def test_symbol_in_arch(self) -> None:
|
||||||
self.assertTrue(symbolfile.symbol_in_arch([], 'arm'))
|
self.assertTrue(symbolfile.symbol_in_arch([], Arch('arm')))
|
||||||
self.assertTrue(symbolfile.symbol_in_arch(['arm'], 'arm'))
|
self.assertTrue(symbolfile.symbol_in_arch([Tag('arm')], Arch('arm')))
|
||||||
|
|
||||||
self.assertFalse(symbolfile.symbol_in_arch(['x86'], 'arm'))
|
self.assertFalse(symbolfile.symbol_in_arch([Tag('x86')], Arch('arm')))
|
||||||
|
|
||||||
def test_symbol_in_api(self):
|
def test_symbol_in_api(self) -> None:
|
||||||
self.assertTrue(symbolfile.symbol_in_api([], 'arm', 9))
|
self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9))
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 9))
|
self.assertTrue(
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 14))
|
symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 9))
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14))
|
self.assertTrue(
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14))
|
symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 14))
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['introduced-x86=14'], 'arm', 9))
|
self.assertTrue(
|
||||||
self.assertTrue(symbolfile.symbol_in_api(
|
symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'),
|
||||||
['introduced-arm=9', 'introduced-x86=21'], 'arm', 14))
|
14))
|
||||||
self.assertTrue(symbolfile.symbol_in_api(
|
self.assertTrue(
|
||||||
['introduced=9', 'introduced-x86=21'], 'arm', 14))
|
symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'),
|
||||||
self.assertTrue(symbolfile.symbol_in_api(
|
14))
|
||||||
['introduced=21', 'introduced-arm=9'], 'arm', 14))
|
self.assertTrue(
|
||||||
self.assertTrue(symbolfile.symbol_in_api(
|
symbolfile.symbol_in_api([Tag('introduced-x86=14')], Arch('arm'),
|
||||||
['future'], 'arm', symbolfile.FUTURE_API_LEVEL))
|
9))
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced-arm=9'),
|
||||||
|
Tag('introduced-x86=21')], Arch('arm'), 14))
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced=9'),
|
||||||
|
Tag('introduced-x86=21')], Arch('arm'), 14))
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced=21'),
|
||||||
|
Tag('introduced-arm=9')], Arch('arm'), 14))
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.symbol_in_api([Tag('future')], Arch('arm'),
|
||||||
|
symbolfile.FUTURE_API_LEVEL))
|
||||||
|
|
||||||
self.assertFalse(symbolfile.symbol_in_api(['introduced=14'], 'arm', 9))
|
self.assertFalse(
|
||||||
self.assertFalse(symbolfile.symbol_in_api(['introduced-arm=14'], 'arm', 9))
|
symbolfile.symbol_in_api([Tag('introduced=14')], Arch('arm'), 9))
|
||||||
self.assertFalse(symbolfile.symbol_in_api(['future'], 'arm', 9))
|
self.assertFalse(
|
||||||
self.assertFalse(symbolfile.symbol_in_api(
|
symbolfile.symbol_in_api([Tag('introduced-arm=14')], Arch('arm'),
|
||||||
['introduced=9', 'future'], 'arm', 14))
|
9))
|
||||||
self.assertFalse(symbolfile.symbol_in_api(
|
self.assertFalse(
|
||||||
['introduced-arm=9', 'future'], 'arm', 14))
|
symbolfile.symbol_in_api([Tag('future')], Arch('arm'), 9))
|
||||||
self.assertFalse(symbolfile.symbol_in_api(
|
self.assertFalse(
|
||||||
['introduced-arm=21', 'introduced-x86=9'], 'arm', 14))
|
symbolfile.symbol_in_api(
|
||||||
self.assertFalse(symbolfile.symbol_in_api(
|
[Tag('introduced=9'), Tag('future')], Arch('arm'), 14))
|
||||||
['introduced=9', 'introduced-arm=21'], 'arm', 14))
|
self.assertFalse(
|
||||||
self.assertFalse(symbolfile.symbol_in_api(
|
symbolfile.symbol_in_api([Tag('introduced-arm=9'),
|
||||||
['introduced=21', 'introduced-x86=9'], 'arm', 14))
|
Tag('future')], Arch('arm'), 14))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced-arm=21'),
|
||||||
|
Tag('introduced-x86=9')], Arch('arm'), 14))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced=9'),
|
||||||
|
Tag('introduced-arm=21')], Arch('arm'), 14))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.symbol_in_api(
|
||||||
|
[Tag('introduced=21'),
|
||||||
|
Tag('introduced-x86=9')], Arch('arm'), 14))
|
||||||
|
|
||||||
# Interesting edge case: this symbol should be omitted from the
|
# Interesting edge case: this symbol should be omitted from the
|
||||||
# library, but this call should still return true because none of the
|
# library, but this call should still return true because none of the
|
||||||
# tags indiciate that it's not present in this API level.
|
# tags indiciate that it's not present in this API level.
|
||||||
self.assertTrue(symbolfile.symbol_in_api(['x86'], 'arm', 9))
|
self.assertTrue(symbolfile.symbol_in_api([Tag('x86')], Arch('arm'), 9))
|
||||||
|
|
||||||
def test_verioned_in_api(self):
|
def test_verioned_in_api(self) -> None:
|
||||||
self.assertTrue(symbolfile.symbol_versioned_in_api([], 9))
|
self.assertTrue(symbolfile.symbol_versioned_in_api([], 9))
|
||||||
self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 9))
|
self.assertTrue(
|
||||||
self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 14))
|
symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 9))
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 14))
|
||||||
|
|
||||||
self.assertFalse(symbolfile.symbol_versioned_in_api(['versioned=14'], 9))
|
self.assertFalse(
|
||||||
|
symbolfile.symbol_versioned_in_api([Tag('versioned=14')], 9))
|
||||||
|
|
||||||
|
|
||||||
class OmitVersionTest(unittest.TestCase):
|
class OmitVersionTest(unittest.TestCase):
|
||||||
def test_omit_private(self):
|
def test_omit_private(self) -> None:
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, [], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||||
False))
|
False))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo_PRIVATE', None, [], []), 'arm', 9,
|
symbolfile.Version('foo_PRIVATE', None, [], []), Arch('arm'),
|
||||||
False, False))
|
9, False, False))
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo_PLATFORM', None, [], []), 'arm', 9,
|
symbolfile.Version('foo_PLATFORM', None, [], []), Arch('arm'),
|
||||||
False, False))
|
|
||||||
|
|
||||||
self.assertTrue(
|
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, ['platform-only'], []), 'arm',
|
|
||||||
9, False, False))
|
9, False, False))
|
||||||
|
|
||||||
def test_omit_llndk(self):
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9,
|
symbolfile.Version('foo', None, [Tag('platform-only')], []),
|
||||||
False, False))
|
Arch('arm'), 9, False, False))
|
||||||
|
|
||||||
self.assertFalse(
|
def test_omit_llndk(self) -> None:
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, [], []), 'arm', 9, True,
|
|
||||||
False))
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, True,
|
|
||||||
False))
|
|
||||||
|
|
||||||
def test_omit_apex(self):
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [Tag('llndk')], []),
|
||||||
False))
|
Arch('arm'), 9, False, False))
|
||||||
|
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, [], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, True,
|
||||||
|
False))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [Tag('llndk')], []),
|
||||||
|
Arch('arm'), 9, True, False))
|
||||||
|
|
||||||
|
def test_omit_apex(self) -> None:
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [Tag('apex')], []),
|
||||||
|
Arch('arm'), 9, False, False))
|
||||||
|
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||||
True))
|
True))
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [Tag('apex')], []),
|
||||||
True))
|
Arch('arm'), 9, False, True))
|
||||||
|
|
||||||
def test_omit_arch(self):
|
def test_omit_arch(self) -> None:
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, [], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||||
False))
|
False))
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, ['arm'], []), 'arm', 9, False,
|
symbolfile.Version('foo', None, [Tag('arm')], []), Arch('arm'),
|
||||||
False))
|
|
||||||
|
|
||||||
self.assertTrue(
|
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, ['x86'], []), 'arm', 9, False,
|
|
||||||
False))
|
|
||||||
|
|
||||||
def test_omit_api(self):
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, [], []), 'arm', 9, False,
|
|
||||||
False))
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_version(
|
|
||||||
symbolfile.Version('foo', None, ['introduced=9'], []), 'arm',
|
|
||||||
9, False, False))
|
9, False, False))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_version(
|
symbolfile.should_omit_version(
|
||||||
symbolfile.Version('foo', None, ['introduced=14'], []), 'arm',
|
symbolfile.Version('foo', None, [Tag('x86')], []), Arch('arm'),
|
||||||
9, False, False))
|
9, False, False))
|
||||||
|
|
||||||
|
def test_omit_api(self) -> None:
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||||
|
False))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [Tag('introduced=9')], []),
|
||||||
|
Arch('arm'), 9, False, False))
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.should_omit_version(
|
||||||
|
symbolfile.Version('foo', None, [Tag('introduced=14')], []),
|
||||||
|
Arch('arm'), 9, False, False))
|
||||||
|
|
||||||
|
|
||||||
class OmitSymbolTest(unittest.TestCase):
|
class OmitSymbolTest(unittest.TestCase):
|
||||||
def test_omit_llndk(self):
|
def test_omit_llndk(self) -> None:
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']),
|
symbolfile.should_omit_symbol(
|
||||||
'arm', 9, False, False))
|
symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9,
|
||||||
|
False, False))
|
||||||
|
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
|
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||||
9, True, False))
|
Arch('arm'), 9, True, False))
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']),
|
|
||||||
'arm', 9, True, False))
|
|
||||||
|
|
||||||
def test_omit_apex(self):
|
|
||||||
self.assertTrue(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']),
|
|
||||||
'arm', 9, False, False))
|
|
||||||
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
|
|
||||||
9, False, True))
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']),
|
|
||||||
'arm', 9, False, True))
|
|
||||||
|
|
||||||
def test_omit_arch(self):
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
|
|
||||||
9, False, False))
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['arm']),
|
|
||||||
'arm', 9, False, False))
|
|
||||||
|
|
||||||
self.assertTrue(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['x86']),
|
|
||||||
'arm', 9, False, False))
|
|
||||||
|
|
||||||
def test_omit_api(self):
|
|
||||||
self.assertFalse(
|
|
||||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
|
|
||||||
9, False, False))
|
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
symbolfile.should_omit_symbol(
|
symbolfile.should_omit_symbol(
|
||||||
symbolfile.Symbol('foo', ['introduced=9']), 'arm', 9, False,
|
symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, True,
|
||||||
|
False))
|
||||||
|
|
||||||
|
def test_omit_apex(self) -> None:
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.should_omit_symbol(
|
||||||
|
symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
|
||||||
|
False))
|
||||||
|
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||||
|
Arch('arm'), 9, False, True))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(
|
||||||
|
symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
|
||||||
|
True))
|
||||||
|
|
||||||
|
def test_omit_arch(self) -> None:
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||||
|
Arch('arm'), 9, False, False))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(
|
||||||
|
symbolfile.Symbol('foo', [Tag('arm')]), Arch('arm'), 9, False,
|
||||||
False))
|
False))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
symbolfile.should_omit_symbol(
|
symbolfile.should_omit_symbol(
|
||||||
symbolfile.Symbol('foo', ['introduced=14']), 'arm', 9, False,
|
symbolfile.Symbol('foo', [Tag('x86')]), Arch('arm'), 9, False,
|
||||||
False))
|
False))
|
||||||
|
|
||||||
|
def test_omit_api(self) -> None:
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||||
|
Arch('arm'), 9, False, False))
|
||||||
|
self.assertFalse(
|
||||||
|
symbolfile.should_omit_symbol(
|
||||||
|
symbolfile.Symbol('foo', [Tag('introduced=9')]), Arch('arm'),
|
||||||
|
9, False, False))
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
symbolfile.should_omit_symbol(
|
||||||
|
symbolfile.Symbol('foo', [Tag('introduced=14')]), Arch('arm'),
|
||||||
|
9, False, False))
|
||||||
|
|
||||||
|
|
||||||
class SymbolFileParseTest(unittest.TestCase):
|
class SymbolFileParseTest(unittest.TestCase):
|
||||||
def test_next_line(self):
|
def test_next_line(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
foo
|
foo
|
||||||
|
|
||||||
@@ -302,10 +342,12 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
# baz
|
# baz
|
||||||
qux
|
qux
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
self.assertIsNone(parser.current_line)
|
self.assertIsNone(parser.current_line)
|
||||||
|
|
||||||
self.assertEqual('foo', parser.next_line().strip())
|
self.assertEqual('foo', parser.next_line().strip())
|
||||||
|
assert parser.current_line is not None
|
||||||
self.assertEqual('foo', parser.current_line.strip())
|
self.assertEqual('foo', parser.current_line.strip())
|
||||||
|
|
||||||
self.assertEqual('bar', parser.next_line().strip())
|
self.assertEqual('bar', parser.next_line().strip())
|
||||||
@@ -317,7 +359,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
self.assertEqual('', parser.next_line())
|
self.assertEqual('', parser.next_line())
|
||||||
self.assertEqual('', parser.current_line)
|
self.assertEqual('', parser.current_line)
|
||||||
|
|
||||||
def test_parse_version(self):
|
def test_parse_version(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 { # foo bar
|
VERSION_1 { # foo bar
|
||||||
baz;
|
baz;
|
||||||
@@ -327,7 +369,8 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
VERSION_2 {
|
VERSION_2 {
|
||||||
} VERSION_1; # asdf
|
} VERSION_1; # asdf
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
|
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
version = parser.parse_version()
|
version = parser.parse_version()
|
||||||
@@ -337,7 +380,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
|
|
||||||
expected_symbols = [
|
expected_symbols = [
|
||||||
symbolfile.Symbol('baz', []),
|
symbolfile.Symbol('baz', []),
|
||||||
symbolfile.Symbol('qux', ['woodly', 'doodly']),
|
symbolfile.Symbol('qux', [Tag('woodly'), Tag('doodly')]),
|
||||||
]
|
]
|
||||||
self.assertEqual(expected_symbols, version.symbols)
|
self.assertEqual(expected_symbols, version.symbols)
|
||||||
|
|
||||||
@@ -347,32 +390,35 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
self.assertEqual('VERSION_1', version.base)
|
self.assertEqual('VERSION_1', version.base)
|
||||||
self.assertEqual([], version.tags)
|
self.assertEqual([], version.tags)
|
||||||
|
|
||||||
def test_parse_version_eof(self):
|
def test_parse_version_eof(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
|
|
||||||
def test_unknown_scope_label(self):
|
def test_unknown_scope_label(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
foo:
|
foo:
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
|
|
||||||
def test_parse_symbol(self):
|
def test_parse_symbol(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
foo;
|
foo;
|
||||||
bar; # baz qux
|
bar; # baz qux
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
|
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
symbol = parser.parse_symbol()
|
symbol = parser.parse_symbol()
|
||||||
@@ -384,48 +430,51 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
self.assertEqual('bar', symbol.name)
|
self.assertEqual('bar', symbol.name)
|
||||||
self.assertEqual(['baz', 'qux'], symbol.tags)
|
self.assertEqual(['baz', 'qux'], symbol.tags)
|
||||||
|
|
||||||
def test_wildcard_symbol_global(self):
|
def test_wildcard_symbol_global(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
|
|
||||||
def test_wildcard_symbol_local(self):
|
def test_wildcard_symbol_local(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
version = parser.parse_version()
|
version = parser.parse_version()
|
||||||
self.assertEqual([], version.symbols)
|
self.assertEqual([], version.symbols)
|
||||||
|
|
||||||
def test_missing_semicolon(self):
|
def test_missing_semicolon(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
foo
|
foo
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
|
|
||||||
def test_parse_fails_invalid_input(self):
|
def test_parse_fails_invalid_input(self) -> None:
|
||||||
with self.assertRaises(symbolfile.ParseError):
|
with self.assertRaises(symbolfile.ParseError):
|
||||||
input_file = io.StringIO('foo')
|
input_file = io.StringIO('foo')
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16,
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'),
|
||||||
False, False)
|
16, False, False)
|
||||||
parser.parse()
|
parser.parse()
|
||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
local:
|
local:
|
||||||
@@ -443,23 +492,24 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
qwerty;
|
qwerty;
|
||||||
} VERSION_1;
|
} VERSION_1;
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, False)
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
symbolfile.Version('VERSION_1', None, [], [
|
symbolfile.Version('VERSION_1', None, [], [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
symbolfile.Symbol('bar', ['baz']),
|
symbolfile.Symbol('bar', [Tag('baz')]),
|
||||||
]),
|
]),
|
||||||
symbolfile.Version('VERSION_2', 'VERSION_1', ['wasd'], [
|
symbolfile.Version('VERSION_2', 'VERSION_1', [Tag('wasd')], [
|
||||||
symbolfile.Symbol('woodly', []),
|
symbolfile.Symbol('woodly', []),
|
||||||
symbolfile.Symbol('doodly', ['asdf']),
|
symbolfile.Symbol('doodly', [Tag('asdf')]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertEqual(expected, versions)
|
self.assertEqual(expected, versions)
|
||||||
|
|
||||||
def test_parse_llndk_apex_symbol(self):
|
def test_parse_llndk_apex_symbol(self) -> None:
|
||||||
input_file = io.StringIO(textwrap.dedent("""\
|
input_file = io.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
foo;
|
foo;
|
||||||
@@ -468,7 +518,8 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
qux; # apex
|
qux; # apex
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, True)
|
parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'), 16,
|
||||||
|
False, True)
|
||||||
|
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
version = parser.parse_version()
|
version = parser.parse_version()
|
||||||
@@ -477,14 +528,14 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
|
|
||||||
expected_symbols = [
|
expected_symbols = [
|
||||||
symbolfile.Symbol('foo', []),
|
symbolfile.Symbol('foo', []),
|
||||||
symbolfile.Symbol('bar', ['llndk']),
|
symbolfile.Symbol('bar', [Tag('llndk')]),
|
||||||
symbolfile.Symbol('baz', ['llndk', 'apex']),
|
symbolfile.Symbol('baz', [Tag('llndk'), Tag('apex')]),
|
||||||
symbolfile.Symbol('qux', ['apex']),
|
symbolfile.Symbol('qux', [Tag('apex')]),
|
||||||
]
|
]
|
||||||
self.assertEqual(expected_symbols, version.symbols)
|
self.assertEqual(expected_symbols, version.symbols)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
unittest.TextTestRunner(verbosity=3).run(suite)
|
unittest.TextTestRunner(verbosity=3).run(suite)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user