Merge changes Ic32cfb3e,I282be134
* changes: Add support for named versions in NDK map files. Generate stub libraries for unreleased API levels.
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#
|
#
|
||||||
"""Generates source for stub shared libraries for the NDK."""
|
"""Generates source for stub shared libraries for the NDK."""
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -40,27 +41,56 @@ def logger():
|
|||||||
return logging.getLogger(__name__)
|
return logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def api_level_arg(api_str):
|
|
||||||
"""Parses an API level, handling the "current" special case.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
api_str: (string) Either a numeric API level or "current".
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(int) FUTURE_API_LEVEL if `api_str` is "current", else `api_str` parsed
|
|
||||||
as an integer.
|
|
||||||
"""
|
|
||||||
if api_str == "current":
|
|
||||||
return FUTURE_API_LEVEL
|
|
||||||
return int(api_str)
|
|
||||||
|
|
||||||
|
|
||||||
def get_tags(line):
|
def get_tags(line):
|
||||||
"""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 [e for e in re.split(r'\s+', all_tags) if e.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def is_api_level_tag(tag):
|
||||||
|
"""Returns true if this tag has an API level that may need decoding."""
|
||||||
|
if tag.startswith('introduced='):
|
||||||
|
return True
|
||||||
|
if tag.startswith('introduced-'):
|
||||||
|
return True
|
||||||
|
if tag.startswith('versioned='):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def decode_api_level_tags(tags, api_map):
|
||||||
|
"""Decodes API level code names in a list of tags.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ParseError: An unknown version name was found in a tag.
|
||||||
|
"""
|
||||||
|
for idx, tag in enumerate(tags):
|
||||||
|
if not is_api_level_tag(tag):
|
||||||
|
continue
|
||||||
|
name, value = split_tag(tag)
|
||||||
|
|
||||||
|
try:
|
||||||
|
decoded = str(decode_api_level(value, api_map))
|
||||||
|
tags[idx] = '='.join([name, decoded])
|
||||||
|
except KeyError:
|
||||||
|
raise ParseError('Unknown version name in tag: {}'.format(tag))
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def split_tag(tag):
|
||||||
|
"""Returns a key/value tuple of the tag.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Tag is not a key/value type tag.
|
||||||
|
|
||||||
|
Returns: Tuple of (key, value) of the tag. Both components are strings.
|
||||||
|
"""
|
||||||
|
if '=' not in tag:
|
||||||
|
raise ValueError('Not a key/value tag: ' + tag)
|
||||||
|
key, _, value = tag.partition('=')
|
||||||
|
return key, value
|
||||||
|
|
||||||
|
|
||||||
def get_tag_value(tag):
|
def get_tag_value(tag):
|
||||||
"""Returns the value of a key/value tag.
|
"""Returns the value of a key/value tag.
|
||||||
|
|
||||||
@@ -69,9 +99,7 @@ def get_tag_value(tag):
|
|||||||
|
|
||||||
Returns: Value part of tag as a string.
|
Returns: Value part of tag as a string.
|
||||||
"""
|
"""
|
||||||
if '=' not in tag:
|
return split_tag(tag)[1]
|
||||||
raise ValueError('Not a key/value tag: ' + tag)
|
|
||||||
return tag.partition('=')[2]
|
|
||||||
|
|
||||||
|
|
||||||
def version_is_private(version):
|
def version_is_private(version):
|
||||||
@@ -193,8 +221,9 @@ class Symbol(object):
|
|||||||
|
|
||||||
class SymbolFileParser(object):
|
class SymbolFileParser(object):
|
||||||
"""Parses NDK symbol files."""
|
"""Parses NDK symbol files."""
|
||||||
def __init__(self, input_file):
|
def __init__(self, input_file, api_map):
|
||||||
self.input_file = input_file
|
self.input_file = input_file
|
||||||
|
self.api_map = api_map
|
||||||
self.current_line = None
|
self.current_line = None
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
@@ -212,6 +241,7 @@ class SymbolFileParser(object):
|
|||||||
"""Parses a single version section and returns a Version object."""
|
"""Parses a single version section and returns a Version object."""
|
||||||
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)
|
||||||
symbols = []
|
symbols = []
|
||||||
global_scope = True
|
global_scope = True
|
||||||
while self.next_line() != '':
|
while self.next_line() != '':
|
||||||
@@ -253,6 +283,7 @@ class SymbolFileParser(object):
|
|||||||
# Line is now in the format "<symbol-name>; # tags"
|
# Line is now in the format "<symbol-name>; # tags"
|
||||||
name, _, _ = self.current_line.strip().partition(';')
|
name, _, _ = self.current_line.strip().partition(';')
|
||||||
tags = get_tags(self.current_line)
|
tags = get_tags(self.current_line)
|
||||||
|
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):
|
||||||
@@ -326,6 +357,24 @@ class Generator(object):
|
|||||||
self.version_script.write('}' + base + ';\n')
|
self.version_script.write('}' + base + ';\n')
|
||||||
|
|
||||||
|
|
||||||
|
def decode_api_level(api, api_map):
|
||||||
|
"""Decodes the API level argument into the API level number.
|
||||||
|
|
||||||
|
For the average case, this just decodes the integer value from the string,
|
||||||
|
but for unreleased APIs we need to translate from the API codename (like
|
||||||
|
"O") to the future API level for that codename.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return int(api)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if api == "current":
|
||||||
|
return FUTURE_API_LEVEL
|
||||||
|
|
||||||
|
return api_map[api]
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
"""Parses and returns command line arguments."""
|
"""Parses and returns command line arguments."""
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
@@ -333,14 +382,17 @@ def parse_args():
|
|||||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--api', type=api_level_arg, required=True,
|
'--api', required=True, help='API level being targeted.')
|
||||||
help='API level being targeted.')
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--arch', choices=ALL_ARCHITECTURES, required=True,
|
'--arch', choices=ALL_ARCHITECTURES, required=True,
|
||||||
help='Architecture being targeted.')
|
help='Architecture being targeted.')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--vndk', action='store_true', help='Use the VNDK variant.')
|
'--vndk', action='store_true', help='Use the VNDK variant.')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--api-map', type=os.path.realpath, required=True,
|
||||||
|
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, help='Path to symbol file.')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -357,6 +409,10 @@ def main():
|
|||||||
"""Program entry point."""
|
"""Program entry point."""
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
|
with open(args.api_map) as map_file:
|
||||||
|
api_map = json.load(map_file)
|
||||||
|
api = decode_api_level(args.api, api_map)
|
||||||
|
|
||||||
verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
|
verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
|
||||||
verbosity = args.verbose
|
verbosity = args.verbose
|
||||||
if verbosity > 2:
|
if verbosity > 2:
|
||||||
@@ -364,11 +420,11 @@ def main():
|
|||||||
logging.basicConfig(level=verbose_map[verbosity])
|
logging.basicConfig(level=verbose_map[verbosity])
|
||||||
|
|
||||||
with open(args.symbol_file) as symbol_file:
|
with open(args.symbol_file) as symbol_file:
|
||||||
versions = SymbolFileParser(symbol_file).parse()
|
versions = SymbolFileParser(symbol_file, api_map).parse()
|
||||||
|
|
||||||
with open(args.stub_src, 'w') as src_file:
|
with open(args.stub_src, 'w') as src_file:
|
||||||
with open(args.version_script, 'w') as version_file:
|
with open(args.version_script, 'w') as version_file:
|
||||||
generator = Generator(src_file, version_file, args.arch, args.api,
|
generator = Generator(src_file, version_file, args.arch, api,
|
||||||
args.vndk)
|
args.vndk)
|
||||||
generator.write(versions)
|
generator.write(versions)
|
||||||
|
|
||||||
|
@@ -30,10 +30,11 @@ var (
|
|||||||
|
|
||||||
genStubSrc = pctx.AndroidStaticRule("genStubSrc",
|
genStubSrc = pctx.AndroidStaticRule("genStubSrc",
|
||||||
blueprint.RuleParams{
|
blueprint.RuleParams{
|
||||||
Command: "$toolPath --arch $arch --api $apiLevel $vndk $in $out",
|
Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
|
||||||
|
"$apiMap $vndk $in $out",
|
||||||
Description: "genStubSrc $out",
|
Description: "genStubSrc $out",
|
||||||
CommandDeps: []string{"$toolPath"},
|
CommandDeps: []string{"$toolPath"},
|
||||||
}, "arch", "apiLevel", "vndk")
|
}, "arch", "apiLevel", "apiMap", "vndk")
|
||||||
|
|
||||||
ndkLibrarySuffix = ".ndk"
|
ndkLibrarySuffix = ".ndk"
|
||||||
|
|
||||||
@@ -205,6 +206,7 @@ func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorat
|
|||||||
for version := firstGenVersion; version <= platformVersion; version++ {
|
for version := firstGenVersion; version <= platformVersion; version++ {
|
||||||
versionStrs = append(versionStrs, strconv.Itoa(version))
|
versionStrs = append(versionStrs, strconv.Itoa(version))
|
||||||
}
|
}
|
||||||
|
versionStrs = append(versionStrs, mctx.AConfig().PlatformVersionAllCodenames()...)
|
||||||
versionStrs = append(versionStrs, "current")
|
versionStrs = append(versionStrs, "current")
|
||||||
|
|
||||||
modules := mctx.CreateVariations(versionStrs...)
|
modules := mctx.CreateVariations(versionStrs...)
|
||||||
@@ -247,13 +249,16 @@ func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, vn
|
|||||||
stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
|
stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
|
||||||
versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
|
versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
|
||||||
symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
|
symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
|
||||||
|
apiLevelsJson := android.GetApiLevelsJson(ctx)
|
||||||
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
|
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
|
||||||
Rule: genStubSrc,
|
Rule: genStubSrc,
|
||||||
Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
|
Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
|
||||||
Input: symbolFilePath,
|
Input: symbolFilePath,
|
||||||
|
Implicits: []android.Path{apiLevelsJson},
|
||||||
Args: map[string]string{
|
Args: map[string]string{
|
||||||
"arch": arch,
|
"arch": arch,
|
||||||
"apiLevel": apiLevel,
|
"apiLevel": apiLevel,
|
||||||
|
"apiMap": apiLevelsJson.String(),
|
||||||
"vndk": vndk,
|
"vndk": vndk,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@@ -25,6 +25,15 @@ import gen_stub_libs as gsl
|
|||||||
# pylint: disable=missing-docstring
|
# pylint: disable=missing-docstring
|
||||||
|
|
||||||
|
|
||||||
|
class DecodeApiLevelTest(unittest.TestCase):
|
||||||
|
def test_decode_api_level(self):
|
||||||
|
self.assertEqual(9, gsl.decode_api_level('9', {}))
|
||||||
|
self.assertEqual(9000, gsl.decode_api_level('O', {'O': 9000}))
|
||||||
|
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
gsl.decode_api_level('O', {})
|
||||||
|
|
||||||
|
|
||||||
class TagsTest(unittest.TestCase):
|
class TagsTest(unittest.TestCase):
|
||||||
def test_get_tags_no_tags(self):
|
def test_get_tags_no_tags(self):
|
||||||
self.assertEqual([], gsl.get_tags(''))
|
self.assertEqual([], gsl.get_tags(''))
|
||||||
@@ -34,12 +43,59 @@ class TagsTest(unittest.TestCase):
|
|||||||
self.assertEqual(['foo', 'bar'], gsl.get_tags('# foo bar'))
|
self.assertEqual(['foo', 'bar'], gsl.get_tags('# foo bar'))
|
||||||
self.assertEqual(['bar', 'baz'], gsl.get_tags('foo # bar baz'))
|
self.assertEqual(['bar', 'baz'], gsl.get_tags('foo # bar baz'))
|
||||||
|
|
||||||
|
def test_split_tag(self):
|
||||||
|
self.assertTupleEqual(('foo', 'bar'), gsl.split_tag('foo=bar'))
|
||||||
|
self.assertTupleEqual(('foo', 'bar=baz'), gsl.split_tag('foo=bar=baz'))
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
gsl.split_tag('foo')
|
||||||
|
|
||||||
def test_get_tag_value(self):
|
def test_get_tag_value(self):
|
||||||
self.assertEqual('bar', gsl.get_tag_value('foo=bar'))
|
self.assertEqual('bar', gsl.get_tag_value('foo=bar'))
|
||||||
self.assertEqual('bar=baz', gsl.get_tag_value('foo=bar=baz'))
|
self.assertEqual('bar=baz', gsl.get_tag_value('foo=bar=baz'))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
gsl.get_tag_value('foo')
|
gsl.get_tag_value('foo')
|
||||||
|
|
||||||
|
def test_is_api_level_tag(self):
|
||||||
|
self.assertTrue(gsl.is_api_level_tag('introduced=24'))
|
||||||
|
self.assertTrue(gsl.is_api_level_tag('introduced-arm=24'))
|
||||||
|
self.assertTrue(gsl.is_api_level_tag('versioned=24'))
|
||||||
|
|
||||||
|
# Shouldn't try to process things that aren't a key/value tag.
|
||||||
|
self.assertFalse(gsl.is_api_level_tag('arm'))
|
||||||
|
self.assertFalse(gsl.is_api_level_tag('introduced'))
|
||||||
|
self.assertFalse(gsl.is_api_level_tag('versioned'))
|
||||||
|
|
||||||
|
# We don't support arch specific `versioned` tags.
|
||||||
|
self.assertFalse(gsl.is_api_level_tag('versioned-arm=24'))
|
||||||
|
|
||||||
|
def test_decode_api_level_tags(self):
|
||||||
|
api_map = {
|
||||||
|
'O': 9000,
|
||||||
|
'P': 9001,
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [
|
||||||
|
'introduced=9',
|
||||||
|
'introduced-arm=14',
|
||||||
|
'versioned=16',
|
||||||
|
'arm',
|
||||||
|
'introduced=O',
|
||||||
|
'introduced=P',
|
||||||
|
]
|
||||||
|
expected_tags = [
|
||||||
|
'introduced=9',
|
||||||
|
'introduced-arm=14',
|
||||||
|
'versioned=16',
|
||||||
|
'arm',
|
||||||
|
'introduced=9000',
|
||||||
|
'introduced=9001',
|
||||||
|
]
|
||||||
|
self.assertListEqual(
|
||||||
|
expected_tags, gsl.decode_api_level_tags(tags, api_map))
|
||||||
|
|
||||||
|
with self.assertRaises(gsl.ParseError):
|
||||||
|
gsl.decode_api_level_tags(['introduced=O'], {})
|
||||||
|
|
||||||
|
|
||||||
class PrivateVersionTest(unittest.TestCase):
|
class PrivateVersionTest(unittest.TestCase):
|
||||||
def test_version_is_private(self):
|
def test_version_is_private(self):
|
||||||
@@ -151,7 +207,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
# baz
|
# baz
|
||||||
qux
|
qux
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
self.assertIsNone(parser.current_line)
|
self.assertIsNone(parser.current_line)
|
||||||
|
|
||||||
self.assertEqual('foo', parser.next_line().strip())
|
self.assertEqual('foo', parser.next_line().strip())
|
||||||
@@ -176,7 +232,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
VERSION_2 {
|
VERSION_2 {
|
||||||
} VERSION_1; # asdf
|
} VERSION_1; # asdf
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
|
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
version = parser.parse_version()
|
version = parser.parse_version()
|
||||||
@@ -200,7 +256,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
input_file = cStringIO.StringIO(textwrap.dedent("""\
|
input_file = cStringIO.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(gsl.ParseError):
|
with self.assertRaises(gsl.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
@@ -211,7 +267,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
foo:
|
foo:
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(gsl.ParseError):
|
with self.assertRaises(gsl.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
@@ -221,7 +277,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
foo;
|
foo;
|
||||||
bar; # baz qux
|
bar; # baz qux
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
|
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
symbol = parser.parse_symbol()
|
symbol = parser.parse_symbol()
|
||||||
@@ -239,7 +295,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(gsl.ParseError):
|
with self.assertRaises(gsl.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
@@ -251,7 +307,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
version = parser.parse_version()
|
version = parser.parse_version()
|
||||||
self.assertEqual([], version.symbols)
|
self.assertEqual([], version.symbols)
|
||||||
@@ -262,7 +318,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
foo
|
foo
|
||||||
};
|
};
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.next_line()
|
parser.next_line()
|
||||||
with self.assertRaises(gsl.ParseError):
|
with self.assertRaises(gsl.ParseError):
|
||||||
parser.parse_version()
|
parser.parse_version()
|
||||||
@@ -270,7 +326,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
def test_parse_fails_invalid_input(self):
|
def test_parse_fails_invalid_input(self):
|
||||||
with self.assertRaises(gsl.ParseError):
|
with self.assertRaises(gsl.ParseError):
|
||||||
input_file = cStringIO.StringIO('foo')
|
input_file = cStringIO.StringIO('foo')
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
parser.parse()
|
parser.parse()
|
||||||
|
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
@@ -291,7 +347,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
|||||||
qwerty;
|
qwerty;
|
||||||
} VERSION_1;
|
} VERSION_1;
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, {})
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
@@ -408,11 +464,18 @@ class GeneratorTest(unittest.TestCase):
|
|||||||
|
|
||||||
class IntegrationTest(unittest.TestCase):
|
class IntegrationTest(unittest.TestCase):
|
||||||
def test_integration(self):
|
def test_integration(self):
|
||||||
|
api_map = {
|
||||||
|
'O': 9000,
|
||||||
|
'P': 9001,
|
||||||
|
}
|
||||||
|
|
||||||
input_file = cStringIO.StringIO(textwrap.dedent("""\
|
input_file = cStringIO.StringIO(textwrap.dedent("""\
|
||||||
VERSION_1 {
|
VERSION_1 {
|
||||||
global:
|
global:
|
||||||
foo; # var
|
foo; # var
|
||||||
bar; # x86
|
bar; # x86
|
||||||
|
fizz; # introduced=O
|
||||||
|
buzz; # introduced=P
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
@@ -436,7 +499,7 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
wobble;
|
wobble;
|
||||||
} VERSION_4;
|
} VERSION_4;
|
||||||
"""))
|
"""))
|
||||||
parser = gsl.SymbolFileParser(input_file)
|
parser = gsl.SymbolFileParser(input_file, api_map)
|
||||||
versions = parser.parse()
|
versions = parser.parse()
|
||||||
|
|
||||||
src_file = cStringIO.StringIO()
|
src_file = cStringIO.StringIO()
|
||||||
@@ -469,6 +532,46 @@ class IntegrationTest(unittest.TestCase):
|
|||||||
""")
|
""")
|
||||||
self.assertEqual(expected_version, version_file.getvalue())
|
self.assertEqual(expected_version, version_file.getvalue())
|
||||||
|
|
||||||
|
def test_integration_future_api(self):
|
||||||
|
api_map = {
|
||||||
|
'O': 9000,
|
||||||
|
'P': 9001,
|
||||||
|
'Q': 9002,
|
||||||
|
}
|
||||||
|
|
||||||
|
input_file = cStringIO.StringIO(textwrap.dedent("""\
|
||||||
|
VERSION_1 {
|
||||||
|
global:
|
||||||
|
foo; # introduced=O
|
||||||
|
bar; # introduced=P
|
||||||
|
baz; # introduced=Q
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
||||||
|
"""))
|
||||||
|
parser = gsl.SymbolFileParser(input_file, api_map)
|
||||||
|
versions = parser.parse()
|
||||||
|
|
||||||
|
src_file = cStringIO.StringIO()
|
||||||
|
version_file = cStringIO.StringIO()
|
||||||
|
generator = gsl.Generator(src_file, version_file, 'arm', 9001, False)
|
||||||
|
generator.write(versions)
|
||||||
|
|
||||||
|
expected_src = textwrap.dedent("""\
|
||||||
|
void foo() {}
|
||||||
|
void bar() {}
|
||||||
|
""")
|
||||||
|
self.assertEqual(expected_src, src_file.getvalue())
|
||||||
|
|
||||||
|
expected_version = textwrap.dedent("""\
|
||||||
|
VERSION_1 {
|
||||||
|
global:
|
||||||
|
foo;
|
||||||
|
bar;
|
||||||
|
};
|
||||||
|
""")
|
||||||
|
self.assertEqual(expected_version, version_file.getvalue())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
suite = unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
Reference in New Issue
Block a user