blob: 8611ef3c3b1aae60f83416d1532433d57a3563ab [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))
Dan Albertfd86e9e2016-11-08 13:35:12 -080078 self.assertTrue(gsl.symbol_in_api(
79 ['future'], 'arm', gsl.FUTURE_API_LEVEL))
Dan Albert8bdccb92016-07-29 13:06:22 -070080
81 self.assertFalse(gsl.symbol_in_api(['introduced=14'], 'arm', 9))
82 self.assertFalse(gsl.symbol_in_api(['introduced-arm=14'], 'arm', 9))
83 self.assertFalse(gsl.symbol_in_api(['future'], 'arm', 9))
84 self.assertFalse(gsl.symbol_in_api(
85 ['introduced=9', 'future'], 'arm', 14))
86 self.assertFalse(gsl.symbol_in_api(
87 ['introduced-arm=9', 'future'], 'arm', 14))
88 self.assertFalse(gsl.symbol_in_api(
89 ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14))
90 self.assertFalse(gsl.symbol_in_api(
91 ['introduced=9', 'introduced-arm=21'], 'arm', 14))
92 self.assertFalse(gsl.symbol_in_api(
93 ['introduced=21', 'introduced-x86=9'], 'arm', 14))
94
95 # Interesting edge case: this symbol should be omitted from the
96 # library, but this call should still return true because none of the
97 # tags indiciate that it's not present in this API level.
98 self.assertTrue(gsl.symbol_in_api(['x86'], 'arm', 9))
99
100 def test_verioned_in_api(self):
101 self.assertTrue(gsl.symbol_versioned_in_api([], 9))
102 self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 9))
103 self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 14))
104
105 self.assertFalse(gsl.symbol_versioned_in_api(['versioned=14'], 9))
106
107
108class OmitVersionTest(unittest.TestCase):
109 def test_omit_private(self):
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700110 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700111
Dan Albert300cb2f2016-11-04 14:52:30 -0700112 self.assertTrue(gsl.should_omit_version(
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700113 'foo_PRIVATE', [], 'arm', 9, False))
114 self.assertTrue(gsl.should_omit_version(
115 'foo_PLATFORM', [], 'arm', 9, False))
116
117 self.assertTrue(gsl.should_omit_version(
118 'foo', ['platform-only'], 'arm', 9, False))
119
120 def test_omit_vndk(self):
121 self.assertTrue(gsl.should_omit_version(
122 'foo', ['vndk'], 'arm', 9, False))
123
124 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9, True))
125 self.assertFalse(gsl.should_omit_version(
126 'foo', ['vndk'], 'arm', 9, True))
Dan Albert300cb2f2016-11-04 14:52:30 -0700127
Dan Albert8bdccb92016-07-29 13:06:22 -0700128 def test_omit_arch(self):
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700129 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9, False))
130 self.assertFalse(gsl.should_omit_version(
131 'foo', ['arm'], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700132
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700133 self.assertTrue(gsl.should_omit_version(
134 'foo', ['x86'], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700135
136 def test_omit_api(self):
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700137 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700138 self.assertFalse(
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700139 gsl.should_omit_version('foo', ['introduced=9'], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700140
141 self.assertTrue(
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700142 gsl.should_omit_version('foo', ['introduced=14'], 'arm', 9, False))
Dan Albert8bdccb92016-07-29 13:06:22 -0700143
144
145class SymbolFileParseTest(unittest.TestCase):
146 def test_next_line(self):
147 input_file = cStringIO.StringIO(textwrap.dedent("""\
148 foo
149
150 bar
151 # baz
152 qux
153 """))
154 parser = gsl.SymbolFileParser(input_file)
155 self.assertIsNone(parser.current_line)
156
157 self.assertEqual('foo', parser.next_line().strip())
158 self.assertEqual('foo', parser.current_line.strip())
159
160 self.assertEqual('bar', parser.next_line().strip())
161 self.assertEqual('bar', parser.current_line.strip())
162
163 self.assertEqual('qux', parser.next_line().strip())
164 self.assertEqual('qux', parser.current_line.strip())
165
166 self.assertEqual('', parser.next_line())
167 self.assertEqual('', parser.current_line)
168
169 def test_parse_version(self):
170 input_file = cStringIO.StringIO(textwrap.dedent("""\
171 VERSION_1 { # foo bar
172 baz;
173 qux; # woodly doodly
174 };
175
176 VERSION_2 {
177 } VERSION_1; # asdf
178 """))
179 parser = gsl.SymbolFileParser(input_file)
180
181 parser.next_line()
182 version = parser.parse_version()
183 self.assertEqual('VERSION_1', version.name)
184 self.assertIsNone(version.base)
185 self.assertEqual(['foo', 'bar'], version.tags)
186
187 expected_symbols = [
188 gsl.Symbol('baz', []),
189 gsl.Symbol('qux', ['woodly', 'doodly']),
190 ]
191 self.assertEqual(expected_symbols, version.symbols)
192
193 parser.next_line()
194 version = parser.parse_version()
195 self.assertEqual('VERSION_2', version.name)
196 self.assertEqual('VERSION_1', version.base)
197 self.assertEqual([], version.tags)
198
199 def test_parse_version_eof(self):
200 input_file = cStringIO.StringIO(textwrap.dedent("""\
201 VERSION_1 {
202 """))
203 parser = gsl.SymbolFileParser(input_file)
204 parser.next_line()
205 with self.assertRaises(gsl.ParseError):
206 parser.parse_version()
207
208 def test_unknown_scope_label(self):
209 input_file = cStringIO.StringIO(textwrap.dedent("""\
210 VERSION_1 {
211 foo:
212 }
213 """))
214 parser = gsl.SymbolFileParser(input_file)
215 parser.next_line()
216 with self.assertRaises(gsl.ParseError):
217 parser.parse_version()
218
219 def test_parse_symbol(self):
220 input_file = cStringIO.StringIO(textwrap.dedent("""\
221 foo;
222 bar; # baz qux
223 """))
224 parser = gsl.SymbolFileParser(input_file)
225
226 parser.next_line()
227 symbol = parser.parse_symbol()
228 self.assertEqual('foo', symbol.name)
229 self.assertEqual([], symbol.tags)
230
231 parser.next_line()
232 symbol = parser.parse_symbol()
233 self.assertEqual('bar', symbol.name)
234 self.assertEqual(['baz', 'qux'], symbol.tags)
235
236 def test_wildcard_symbol_global(self):
237 input_file = cStringIO.StringIO(textwrap.dedent("""\
238 VERSION_1 {
239 *;
240 };
241 """))
242 parser = gsl.SymbolFileParser(input_file)
243 parser.next_line()
244 with self.assertRaises(gsl.ParseError):
245 parser.parse_version()
246
247 def test_wildcard_symbol_local(self):
248 input_file = cStringIO.StringIO(textwrap.dedent("""\
249 VERSION_1 {
250 local:
251 *;
252 };
253 """))
254 parser = gsl.SymbolFileParser(input_file)
255 parser.next_line()
256 version = parser.parse_version()
257 self.assertEqual([], version.symbols)
258
259 def test_missing_semicolon(self):
260 input_file = cStringIO.StringIO(textwrap.dedent("""\
261 VERSION_1 {
262 foo
263 };
264 """))
265 parser = gsl.SymbolFileParser(input_file)
266 parser.next_line()
267 with self.assertRaises(gsl.ParseError):
268 parser.parse_version()
269
270 def test_parse_fails_invalid_input(self):
271 with self.assertRaises(gsl.ParseError):
272 input_file = cStringIO.StringIO('foo')
273 parser = gsl.SymbolFileParser(input_file)
274 parser.parse()
275
276 def test_parse(self):
277 input_file = cStringIO.StringIO(textwrap.dedent("""\
278 VERSION_1 {
279 local:
280 hidden1;
281 global:
282 foo;
283 bar; # baz
284 };
285
286 VERSION_2 { # wasd
287 # Implicit global scope.
288 woodly;
289 doodly; # asdf
290 local:
291 qwerty;
292 } VERSION_1;
293 """))
294 parser = gsl.SymbolFileParser(input_file)
295 versions = parser.parse()
296
297 expected = [
298 gsl.Version('VERSION_1', None, [], [
299 gsl.Symbol('foo', []),
300 gsl.Symbol('bar', ['baz']),
301 ]),
302 gsl.Version('VERSION_2', 'VERSION_1', ['wasd'], [
303 gsl.Symbol('woodly', []),
304 gsl.Symbol('doodly', ['asdf']),
305 ]),
306 ]
307
308 self.assertEqual(expected, versions)
309
310
311class GeneratorTest(unittest.TestCase):
312 def test_omit_version(self):
313 # Thorough testing of the cases involved here is handled by
314 # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
315 src_file = cStringIO.StringIO()
316 version_file = cStringIO.StringIO()
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700317 generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
Dan Albert8bdccb92016-07-29 13:06:22 -0700318
319 version = gsl.Version('VERSION_PRIVATE', None, [], [
320 gsl.Symbol('foo', []),
321 ])
322 generator.write_version(version)
323 self.assertEqual('', src_file.getvalue())
324 self.assertEqual('', version_file.getvalue())
325
326 version = gsl.Version('VERSION', None, ['x86'], [
327 gsl.Symbol('foo', []),
328 ])
329 generator.write_version(version)
330 self.assertEqual('', src_file.getvalue())
331 self.assertEqual('', version_file.getvalue())
332
333 version = gsl.Version('VERSION', None, ['introduced=14'], [
334 gsl.Symbol('foo', []),
335 ])
336 generator.write_version(version)
337 self.assertEqual('', src_file.getvalue())
338 self.assertEqual('', version_file.getvalue())
339
340 def test_omit_symbol(self):
341 # Thorough testing of the cases involved here is handled by
342 # SymbolPresenceTest.
343 src_file = cStringIO.StringIO()
344 version_file = cStringIO.StringIO()
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700345 generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
Dan Albert8bdccb92016-07-29 13:06:22 -0700346
347 version = gsl.Version('VERSION_1', None, [], [
348 gsl.Symbol('foo', ['x86']),
349 ])
350 generator.write_version(version)
351 self.assertEqual('', src_file.getvalue())
352 self.assertEqual('', version_file.getvalue())
353
354 version = gsl.Version('VERSION_1', None, [], [
355 gsl.Symbol('foo', ['introduced=14']),
356 ])
357 generator.write_version(version)
358 self.assertEqual('', src_file.getvalue())
359 self.assertEqual('', version_file.getvalue())
360
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700361 version = gsl.Version('VERSION_1', None, [], [
362 gsl.Symbol('foo', ['vndk']),
363 ])
364 generator.write_version(version)
365 self.assertEqual('', src_file.getvalue())
366 self.assertEqual('', version_file.getvalue())
367
Dan Albert8bdccb92016-07-29 13:06:22 -0700368 def test_write(self):
369 src_file = cStringIO.StringIO()
370 version_file = cStringIO.StringIO()
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700371 generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
Dan Albert8bdccb92016-07-29 13:06:22 -0700372
373 versions = [
374 gsl.Version('VERSION_1', None, [], [
375 gsl.Symbol('foo', []),
376 gsl.Symbol('bar', ['var']),
377 ]),
378 gsl.Version('VERSION_2', 'VERSION_1', [], [
379 gsl.Symbol('baz', []),
380 ]),
381 gsl.Version('VERSION_3', 'VERSION_1', [], [
382 gsl.Symbol('qux', ['versioned=14']),
383 ]),
384 ]
385
386 generator.write(versions)
387 expected_src = textwrap.dedent("""\
388 void foo() {}
389 int bar = 0;
390 void baz() {}
391 void qux() {}
392 """)
393 self.assertEqual(expected_src, src_file.getvalue())
394
395 expected_version = textwrap.dedent("""\
396 VERSION_1 {
397 global:
398 foo;
399 bar;
400 };
401 VERSION_2 {
402 global:
403 baz;
404 } VERSION_1;
405 """)
406 self.assertEqual(expected_version, version_file.getvalue())
407
408
409class IntegrationTest(unittest.TestCase):
410 def test_integration(self):
411 input_file = cStringIO.StringIO(textwrap.dedent("""\
412 VERSION_1 {
413 global:
414 foo; # var
415 bar; # x86
416 local:
417 *;
418 };
419
420 VERSION_2 { # arm
421 baz; # introduced=9
422 qux; # versioned=14
423 } VERSION_1;
424
425 VERSION_3 { # introduced=14
426 woodly;
427 doodly; # var
428 } VERSION_2;
Dan Albertae452cc2017-01-03 14:27:41 -0800429
430 VERSION_4 { # versioned=9
431 wibble;
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700432 wizzes; # vndk
Dan Albertae452cc2017-01-03 14:27:41 -0800433 } VERSION_2;
434
435 VERSION_5 { # versioned=14
436 wobble;
437 } VERSION_4;
Dan Albert8bdccb92016-07-29 13:06:22 -0700438 """))
439 parser = gsl.SymbolFileParser(input_file)
440 versions = parser.parse()
441
442 src_file = cStringIO.StringIO()
443 version_file = cStringIO.StringIO()
Dan Willemsenb01e7f72017-04-03 14:28:36 -0700444 generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
Dan Albert8bdccb92016-07-29 13:06:22 -0700445 generator.write(versions)
446
447 expected_src = textwrap.dedent("""\
448 int foo = 0;
449 void baz() {}
450 void qux() {}
Dan Albertae452cc2017-01-03 14:27:41 -0800451 void wibble() {}
452 void wobble() {}
Dan Albert8bdccb92016-07-29 13:06:22 -0700453 """)
454 self.assertEqual(expected_src, src_file.getvalue())
455
456 expected_version = textwrap.dedent("""\
457 VERSION_1 {
458 global:
459 foo;
460 };
461 VERSION_2 {
462 global:
463 baz;
464 } VERSION_1;
Dan Albertae452cc2017-01-03 14:27:41 -0800465 VERSION_4 {
466 global:
467 wibble;
468 } VERSION_2;
Dan Albert8bdccb92016-07-29 13:06:22 -0700469 """)
470 self.assertEqual(expected_version, version_file.getvalue())
471
472
473def main():
474 suite = unittest.TestLoader().loadTestsFromName(__name__)
475 unittest.TextTestRunner(verbosity=3).run(suite)
476
477
478if __name__ == '__main__':
479 main()