blob: 8436a4804181f30cfb5883d49dcd85c08e3ec06c [file] [log] [blame]
Dan Albert8bdccb92016-07-29 13:06:22 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Tests for gen_stub_libs.py."""
18import cStringIO
19import textwrap
20import unittest
21
22import gen_stub_libs as gsl
23
24
25# pylint: disable=missing-docstring
26
27
28class TagsTest(unittest.TestCase):
29 def test_get_tags_no_tags(self):
30 self.assertEqual([], gsl.get_tags(''))
31 self.assertEqual([], gsl.get_tags('foo bar baz'))
32
33 def test_get_tags(self):
34 self.assertEqual(['foo', 'bar'], gsl.get_tags('# foo bar'))
35 self.assertEqual(['bar', 'baz'], gsl.get_tags('foo # bar baz'))
36
37 def test_get_tag_value(self):
38 self.assertEqual('bar', gsl.get_tag_value('foo=bar'))
39 self.assertEqual('bar=baz', gsl.get_tag_value('foo=bar=baz'))
40 with self.assertRaises(ValueError):
41 gsl.get_tag_value('foo')
42
43
44class PrivateVersionTest(unittest.TestCase):
45 def test_version_is_private(self):
46 self.assertFalse(gsl.version_is_private('foo'))
47 self.assertFalse(gsl.version_is_private('PRIVATE'))
48 self.assertFalse(gsl.version_is_private('PLATFORM'))
49 self.assertFalse(gsl.version_is_private('foo_private'))
50 self.assertFalse(gsl.version_is_private('foo_platform'))
51 self.assertFalse(gsl.version_is_private('foo_PRIVATE_'))
52 self.assertFalse(gsl.version_is_private('foo_PLATFORM_'))
53
54 self.assertTrue(gsl.version_is_private('foo_PRIVATE'))
55 self.assertTrue(gsl.version_is_private('foo_PLATFORM'))
56
57
58class SymbolPresenceTest(unittest.TestCase):
59 def test_symbol_in_arch(self):
60 self.assertTrue(gsl.symbol_in_arch([], 'arm'))
61 self.assertTrue(gsl.symbol_in_arch(['arm'], 'arm'))
62
63 self.assertFalse(gsl.symbol_in_arch(['x86'], 'arm'))
64
65 def test_symbol_in_api(self):
66 self.assertTrue(gsl.symbol_in_api([], 'arm', 9))
67 self.assertTrue(gsl.symbol_in_api(['introduced=9'], 'arm', 9))
68 self.assertTrue(gsl.symbol_in_api(['introduced=9'], 'arm', 14))
69 self.assertTrue(gsl.symbol_in_api(['introduced-arm=9'], 'arm', 14))
70 self.assertTrue(gsl.symbol_in_api(['introduced-arm=9'], 'arm', 14))
71 self.assertTrue(gsl.symbol_in_api(['introduced-x86=14'], 'arm', 9))
72 self.assertTrue(gsl.symbol_in_api(
73 ['introduced-arm=9', 'introduced-x86=21'], 'arm', 14))
74 self.assertTrue(gsl.symbol_in_api(
75 ['introduced=9', 'introduced-x86=21'], 'arm', 14))
76 self.assertTrue(gsl.symbol_in_api(
77 ['introduced=21', 'introduced-arm=9'], 'arm', 14))
78
79 self.assertFalse(gsl.symbol_in_api(['introduced=14'], 'arm', 9))
80 self.assertFalse(gsl.symbol_in_api(['introduced-arm=14'], 'arm', 9))
81 self.assertFalse(gsl.symbol_in_api(['future'], 'arm', 9))
82 self.assertFalse(gsl.symbol_in_api(
83 ['introduced=9', 'future'], 'arm', 14))
84 self.assertFalse(gsl.symbol_in_api(
85 ['introduced-arm=9', 'future'], 'arm', 14))
86 self.assertFalse(gsl.symbol_in_api(
87 ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14))
88 self.assertFalse(gsl.symbol_in_api(
89 ['introduced=9', 'introduced-arm=21'], 'arm', 14))
90 self.assertFalse(gsl.symbol_in_api(
91 ['introduced=21', 'introduced-x86=9'], 'arm', 14))
92
93 # Interesting edge case: this symbol should be omitted from the
94 # library, but this call should still return true because none of the
95 # tags indiciate that it's not present in this API level.
96 self.assertTrue(gsl.symbol_in_api(['x86'], 'arm', 9))
97
98 def test_verioned_in_api(self):
99 self.assertTrue(gsl.symbol_versioned_in_api([], 9))
100 self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 9))
101 self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 14))
102
103 self.assertFalse(gsl.symbol_versioned_in_api(['versioned=14'], 9))
104
105
106class OmitVersionTest(unittest.TestCase):
107 def test_omit_private(self):
108 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
109
110 self.assertTrue(gsl.should_omit_version('foo_PRIVATE', [], 'arm', 9))
111 self.assertTrue(gsl.should_omit_version('foo_PLATFORM', [], 'arm', 9))
112
113 def test_omit_arch(self):
114 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
115 self.assertFalse(gsl.should_omit_version('foo', ['arm'], 'arm', 9))
116
117 self.assertTrue(gsl.should_omit_version('foo', ['x86'], 'arm', 9))
118
119 def test_omit_api(self):
120 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
121 self.assertFalse(
122 gsl.should_omit_version('foo', ['introduced=9'], 'arm', 9))
123
124 self.assertTrue(
125 gsl.should_omit_version('foo', ['introduced=14'], 'arm', 9))
126
127
128class SymbolFileParseTest(unittest.TestCase):
129 def test_next_line(self):
130 input_file = cStringIO.StringIO(textwrap.dedent("""\
131 foo
132
133 bar
134 # baz
135 qux
136 """))
137 parser = gsl.SymbolFileParser(input_file)
138 self.assertIsNone(parser.current_line)
139
140 self.assertEqual('foo', parser.next_line().strip())
141 self.assertEqual('foo', parser.current_line.strip())
142
143 self.assertEqual('bar', parser.next_line().strip())
144 self.assertEqual('bar', parser.current_line.strip())
145
146 self.assertEqual('qux', parser.next_line().strip())
147 self.assertEqual('qux', parser.current_line.strip())
148
149 self.assertEqual('', parser.next_line())
150 self.assertEqual('', parser.current_line)
151
152 def test_parse_version(self):
153 input_file = cStringIO.StringIO(textwrap.dedent("""\
154 VERSION_1 { # foo bar
155 baz;
156 qux; # woodly doodly
157 };
158
159 VERSION_2 {
160 } VERSION_1; # asdf
161 """))
162 parser = gsl.SymbolFileParser(input_file)
163
164 parser.next_line()
165 version = parser.parse_version()
166 self.assertEqual('VERSION_1', version.name)
167 self.assertIsNone(version.base)
168 self.assertEqual(['foo', 'bar'], version.tags)
169
170 expected_symbols = [
171 gsl.Symbol('baz', []),
172 gsl.Symbol('qux', ['woodly', 'doodly']),
173 ]
174 self.assertEqual(expected_symbols, version.symbols)
175
176 parser.next_line()
177 version = parser.parse_version()
178 self.assertEqual('VERSION_2', version.name)
179 self.assertEqual('VERSION_1', version.base)
180 self.assertEqual([], version.tags)
181
182 def test_parse_version_eof(self):
183 input_file = cStringIO.StringIO(textwrap.dedent("""\
184 VERSION_1 {
185 """))
186 parser = gsl.SymbolFileParser(input_file)
187 parser.next_line()
188 with self.assertRaises(gsl.ParseError):
189 parser.parse_version()
190
191 def test_unknown_scope_label(self):
192 input_file = cStringIO.StringIO(textwrap.dedent("""\
193 VERSION_1 {
194 foo:
195 }
196 """))
197 parser = gsl.SymbolFileParser(input_file)
198 parser.next_line()
199 with self.assertRaises(gsl.ParseError):
200 parser.parse_version()
201
202 def test_parse_symbol(self):
203 input_file = cStringIO.StringIO(textwrap.dedent("""\
204 foo;
205 bar; # baz qux
206 """))
207 parser = gsl.SymbolFileParser(input_file)
208
209 parser.next_line()
210 symbol = parser.parse_symbol()
211 self.assertEqual('foo', symbol.name)
212 self.assertEqual([], symbol.tags)
213
214 parser.next_line()
215 symbol = parser.parse_symbol()
216 self.assertEqual('bar', symbol.name)
217 self.assertEqual(['baz', 'qux'], symbol.tags)
218
219 def test_wildcard_symbol_global(self):
220 input_file = cStringIO.StringIO(textwrap.dedent("""\
221 VERSION_1 {
222 *;
223 };
224 """))
225 parser = gsl.SymbolFileParser(input_file)
226 parser.next_line()
227 with self.assertRaises(gsl.ParseError):
228 parser.parse_version()
229
230 def test_wildcard_symbol_local(self):
231 input_file = cStringIO.StringIO(textwrap.dedent("""\
232 VERSION_1 {
233 local:
234 *;
235 };
236 """))
237 parser = gsl.SymbolFileParser(input_file)
238 parser.next_line()
239 version = parser.parse_version()
240 self.assertEqual([], version.symbols)
241
242 def test_missing_semicolon(self):
243 input_file = cStringIO.StringIO(textwrap.dedent("""\
244 VERSION_1 {
245 foo
246 };
247 """))
248 parser = gsl.SymbolFileParser(input_file)
249 parser.next_line()
250 with self.assertRaises(gsl.ParseError):
251 parser.parse_version()
252
253 def test_parse_fails_invalid_input(self):
254 with self.assertRaises(gsl.ParseError):
255 input_file = cStringIO.StringIO('foo')
256 parser = gsl.SymbolFileParser(input_file)
257 parser.parse()
258
259 def test_parse(self):
260 input_file = cStringIO.StringIO(textwrap.dedent("""\
261 VERSION_1 {
262 local:
263 hidden1;
264 global:
265 foo;
266 bar; # baz
267 };
268
269 VERSION_2 { # wasd
270 # Implicit global scope.
271 woodly;
272 doodly; # asdf
273 local:
274 qwerty;
275 } VERSION_1;
276 """))
277 parser = gsl.SymbolFileParser(input_file)
278 versions = parser.parse()
279
280 expected = [
281 gsl.Version('VERSION_1', None, [], [
282 gsl.Symbol('foo', []),
283 gsl.Symbol('bar', ['baz']),
284 ]),
285 gsl.Version('VERSION_2', 'VERSION_1', ['wasd'], [
286 gsl.Symbol('woodly', []),
287 gsl.Symbol('doodly', ['asdf']),
288 ]),
289 ]
290
291 self.assertEqual(expected, versions)
292
293
294class GeneratorTest(unittest.TestCase):
295 def test_omit_version(self):
296 # Thorough testing of the cases involved here is handled by
297 # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
298 src_file = cStringIO.StringIO()
299 version_file = cStringIO.StringIO()
300 generator = gsl.Generator(src_file, version_file, 'arm', 9)
301
302 version = gsl.Version('VERSION_PRIVATE', None, [], [
303 gsl.Symbol('foo', []),
304 ])
305 generator.write_version(version)
306 self.assertEqual('', src_file.getvalue())
307 self.assertEqual('', version_file.getvalue())
308
309 version = gsl.Version('VERSION', None, ['x86'], [
310 gsl.Symbol('foo', []),
311 ])
312 generator.write_version(version)
313 self.assertEqual('', src_file.getvalue())
314 self.assertEqual('', version_file.getvalue())
315
316 version = gsl.Version('VERSION', None, ['introduced=14'], [
317 gsl.Symbol('foo', []),
318 ])
319 generator.write_version(version)
320 self.assertEqual('', src_file.getvalue())
321 self.assertEqual('', version_file.getvalue())
322
323 def test_omit_symbol(self):
324 # Thorough testing of the cases involved here is handled by
325 # SymbolPresenceTest.
326 src_file = cStringIO.StringIO()
327 version_file = cStringIO.StringIO()
328 generator = gsl.Generator(src_file, version_file, 'arm', 9)
329
330 version = gsl.Version('VERSION_1', None, [], [
331 gsl.Symbol('foo', ['x86']),
332 ])
333 generator.write_version(version)
334 self.assertEqual('', src_file.getvalue())
335 self.assertEqual('', version_file.getvalue())
336
337 version = gsl.Version('VERSION_1', None, [], [
338 gsl.Symbol('foo', ['introduced=14']),
339 ])
340 generator.write_version(version)
341 self.assertEqual('', src_file.getvalue())
342 self.assertEqual('', version_file.getvalue())
343
344 def test_write(self):
345 src_file = cStringIO.StringIO()
346 version_file = cStringIO.StringIO()
347 generator = gsl.Generator(src_file, version_file, 'arm', 9)
348
349 versions = [
350 gsl.Version('VERSION_1', None, [], [
351 gsl.Symbol('foo', []),
352 gsl.Symbol('bar', ['var']),
353 ]),
354 gsl.Version('VERSION_2', 'VERSION_1', [], [
355 gsl.Symbol('baz', []),
356 ]),
357 gsl.Version('VERSION_3', 'VERSION_1', [], [
358 gsl.Symbol('qux', ['versioned=14']),
359 ]),
360 ]
361
362 generator.write(versions)
363 expected_src = textwrap.dedent("""\
364 void foo() {}
365 int bar = 0;
366 void baz() {}
367 void qux() {}
368 """)
369 self.assertEqual(expected_src, src_file.getvalue())
370
371 expected_version = textwrap.dedent("""\
372 VERSION_1 {
373 global:
374 foo;
375 bar;
376 };
377 VERSION_2 {
378 global:
379 baz;
380 } VERSION_1;
381 """)
382 self.assertEqual(expected_version, version_file.getvalue())
383
384
385class IntegrationTest(unittest.TestCase):
386 def test_integration(self):
387 input_file = cStringIO.StringIO(textwrap.dedent("""\
388 VERSION_1 {
389 global:
390 foo; # var
391 bar; # x86
392 local:
393 *;
394 };
395
396 VERSION_2 { # arm
397 baz; # introduced=9
398 qux; # versioned=14
399 } VERSION_1;
400
401 VERSION_3 { # introduced=14
402 woodly;
403 doodly; # var
404 } VERSION_2;
405 """))
406 parser = gsl.SymbolFileParser(input_file)
407 versions = parser.parse()
408
409 src_file = cStringIO.StringIO()
410 version_file = cStringIO.StringIO()
411 generator = gsl.Generator(src_file, version_file, 'arm', 9)
412 generator.write(versions)
413
414 expected_src = textwrap.dedent("""\
415 int foo = 0;
416 void baz() {}
417 void qux() {}
418 """)
419 self.assertEqual(expected_src, src_file.getvalue())
420
421 expected_version = textwrap.dedent("""\
422 VERSION_1 {
423 global:
424 foo;
425 };
426 VERSION_2 {
427 global:
428 baz;
429 } VERSION_1;
430 """)
431 self.assertEqual(expected_version, version_file.getvalue())
432
433
434def main():
435 suite = unittest.TestLoader().loadTestsFromName(__name__)
436 unittest.TextTestRunner(verbosity=3).run(suite)
437
438
439if __name__ == '__main__':
440 main()