blob: e9e72498925bce5088bccf444679fd6ddd8dcd4f [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):
110 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
111
112 self.assertTrue(gsl.should_omit_version('foo_PRIVATE', [], 'arm', 9))
113 self.assertTrue(gsl.should_omit_version('foo_PLATFORM', [], 'arm', 9))
114
Dan Albert300cb2f2016-11-04 14:52:30 -0700115 self.assertTrue(gsl.should_omit_version(
116 'foo', ['platform-only'], 'arm', 9))
117
Dan Albert8bdccb92016-07-29 13:06:22 -0700118 def test_omit_arch(self):
119 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
120 self.assertFalse(gsl.should_omit_version('foo', ['arm'], 'arm', 9))
121
122 self.assertTrue(gsl.should_omit_version('foo', ['x86'], 'arm', 9))
123
124 def test_omit_api(self):
125 self.assertFalse(gsl.should_omit_version('foo', [], 'arm', 9))
126 self.assertFalse(
127 gsl.should_omit_version('foo', ['introduced=9'], 'arm', 9))
128
129 self.assertTrue(
130 gsl.should_omit_version('foo', ['introduced=14'], 'arm', 9))
131
132
133class SymbolFileParseTest(unittest.TestCase):
134 def test_next_line(self):
135 input_file = cStringIO.StringIO(textwrap.dedent("""\
136 foo
137
138 bar
139 # baz
140 qux
141 """))
142 parser = gsl.SymbolFileParser(input_file)
143 self.assertIsNone(parser.current_line)
144
145 self.assertEqual('foo', parser.next_line().strip())
146 self.assertEqual('foo', parser.current_line.strip())
147
148 self.assertEqual('bar', parser.next_line().strip())
149 self.assertEqual('bar', parser.current_line.strip())
150
151 self.assertEqual('qux', parser.next_line().strip())
152 self.assertEqual('qux', parser.current_line.strip())
153
154 self.assertEqual('', parser.next_line())
155 self.assertEqual('', parser.current_line)
156
157 def test_parse_version(self):
158 input_file = cStringIO.StringIO(textwrap.dedent("""\
159 VERSION_1 { # foo bar
160 baz;
161 qux; # woodly doodly
162 };
163
164 VERSION_2 {
165 } VERSION_1; # asdf
166 """))
167 parser = gsl.SymbolFileParser(input_file)
168
169 parser.next_line()
170 version = parser.parse_version()
171 self.assertEqual('VERSION_1', version.name)
172 self.assertIsNone(version.base)
173 self.assertEqual(['foo', 'bar'], version.tags)
174
175 expected_symbols = [
176 gsl.Symbol('baz', []),
177 gsl.Symbol('qux', ['woodly', 'doodly']),
178 ]
179 self.assertEqual(expected_symbols, version.symbols)
180
181 parser.next_line()
182 version = parser.parse_version()
183 self.assertEqual('VERSION_2', version.name)
184 self.assertEqual('VERSION_1', version.base)
185 self.assertEqual([], version.tags)
186
187 def test_parse_version_eof(self):
188 input_file = cStringIO.StringIO(textwrap.dedent("""\
189 VERSION_1 {
190 """))
191 parser = gsl.SymbolFileParser(input_file)
192 parser.next_line()
193 with self.assertRaises(gsl.ParseError):
194 parser.parse_version()
195
196 def test_unknown_scope_label(self):
197 input_file = cStringIO.StringIO(textwrap.dedent("""\
198 VERSION_1 {
199 foo:
200 }
201 """))
202 parser = gsl.SymbolFileParser(input_file)
203 parser.next_line()
204 with self.assertRaises(gsl.ParseError):
205 parser.parse_version()
206
207 def test_parse_symbol(self):
208 input_file = cStringIO.StringIO(textwrap.dedent("""\
209 foo;
210 bar; # baz qux
211 """))
212 parser = gsl.SymbolFileParser(input_file)
213
214 parser.next_line()
215 symbol = parser.parse_symbol()
216 self.assertEqual('foo', symbol.name)
217 self.assertEqual([], symbol.tags)
218
219 parser.next_line()
220 symbol = parser.parse_symbol()
221 self.assertEqual('bar', symbol.name)
222 self.assertEqual(['baz', 'qux'], symbol.tags)
223
224 def test_wildcard_symbol_global(self):
225 input_file = cStringIO.StringIO(textwrap.dedent("""\
226 VERSION_1 {
227 *;
228 };
229 """))
230 parser = gsl.SymbolFileParser(input_file)
231 parser.next_line()
232 with self.assertRaises(gsl.ParseError):
233 parser.parse_version()
234
235 def test_wildcard_symbol_local(self):
236 input_file = cStringIO.StringIO(textwrap.dedent("""\
237 VERSION_1 {
238 local:
239 *;
240 };
241 """))
242 parser = gsl.SymbolFileParser(input_file)
243 parser.next_line()
244 version = parser.parse_version()
245 self.assertEqual([], version.symbols)
246
247 def test_missing_semicolon(self):
248 input_file = cStringIO.StringIO(textwrap.dedent("""\
249 VERSION_1 {
250 foo
251 };
252 """))
253 parser = gsl.SymbolFileParser(input_file)
254 parser.next_line()
255 with self.assertRaises(gsl.ParseError):
256 parser.parse_version()
257
258 def test_parse_fails_invalid_input(self):
259 with self.assertRaises(gsl.ParseError):
260 input_file = cStringIO.StringIO('foo')
261 parser = gsl.SymbolFileParser(input_file)
262 parser.parse()
263
264 def test_parse(self):
265 input_file = cStringIO.StringIO(textwrap.dedent("""\
266 VERSION_1 {
267 local:
268 hidden1;
269 global:
270 foo;
271 bar; # baz
272 };
273
274 VERSION_2 { # wasd
275 # Implicit global scope.
276 woodly;
277 doodly; # asdf
278 local:
279 qwerty;
280 } VERSION_1;
281 """))
282 parser = gsl.SymbolFileParser(input_file)
283 versions = parser.parse()
284
285 expected = [
286 gsl.Version('VERSION_1', None, [], [
287 gsl.Symbol('foo', []),
288 gsl.Symbol('bar', ['baz']),
289 ]),
290 gsl.Version('VERSION_2', 'VERSION_1', ['wasd'], [
291 gsl.Symbol('woodly', []),
292 gsl.Symbol('doodly', ['asdf']),
293 ]),
294 ]
295
296 self.assertEqual(expected, versions)
297
298
299class GeneratorTest(unittest.TestCase):
300 def test_omit_version(self):
301 # Thorough testing of the cases involved here is handled by
302 # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
303 src_file = cStringIO.StringIO()
304 version_file = cStringIO.StringIO()
305 generator = gsl.Generator(src_file, version_file, 'arm', 9)
306
307 version = gsl.Version('VERSION_PRIVATE', None, [], [
308 gsl.Symbol('foo', []),
309 ])
310 generator.write_version(version)
311 self.assertEqual('', src_file.getvalue())
312 self.assertEqual('', version_file.getvalue())
313
314 version = gsl.Version('VERSION', None, ['x86'], [
315 gsl.Symbol('foo', []),
316 ])
317 generator.write_version(version)
318 self.assertEqual('', src_file.getvalue())
319 self.assertEqual('', version_file.getvalue())
320
321 version = gsl.Version('VERSION', None, ['introduced=14'], [
322 gsl.Symbol('foo', []),
323 ])
324 generator.write_version(version)
325 self.assertEqual('', src_file.getvalue())
326 self.assertEqual('', version_file.getvalue())
327
328 def test_omit_symbol(self):
329 # Thorough testing of the cases involved here is handled by
330 # SymbolPresenceTest.
331 src_file = cStringIO.StringIO()
332 version_file = cStringIO.StringIO()
333 generator = gsl.Generator(src_file, version_file, 'arm', 9)
334
335 version = gsl.Version('VERSION_1', None, [], [
336 gsl.Symbol('foo', ['x86']),
337 ])
338 generator.write_version(version)
339 self.assertEqual('', src_file.getvalue())
340 self.assertEqual('', version_file.getvalue())
341
342 version = gsl.Version('VERSION_1', None, [], [
343 gsl.Symbol('foo', ['introduced=14']),
344 ])
345 generator.write_version(version)
346 self.assertEqual('', src_file.getvalue())
347 self.assertEqual('', version_file.getvalue())
348
349 def test_write(self):
350 src_file = cStringIO.StringIO()
351 version_file = cStringIO.StringIO()
352 generator = gsl.Generator(src_file, version_file, 'arm', 9)
353
354 versions = [
355 gsl.Version('VERSION_1', None, [], [
356 gsl.Symbol('foo', []),
357 gsl.Symbol('bar', ['var']),
358 ]),
359 gsl.Version('VERSION_2', 'VERSION_1', [], [
360 gsl.Symbol('baz', []),
361 ]),
362 gsl.Version('VERSION_3', 'VERSION_1', [], [
363 gsl.Symbol('qux', ['versioned=14']),
364 ]),
365 ]
366
367 generator.write(versions)
368 expected_src = textwrap.dedent("""\
369 void foo() {}
370 int bar = 0;
371 void baz() {}
372 void qux() {}
373 """)
374 self.assertEqual(expected_src, src_file.getvalue())
375
376 expected_version = textwrap.dedent("""\
377 VERSION_1 {
378 global:
379 foo;
380 bar;
381 };
382 VERSION_2 {
383 global:
384 baz;
385 } VERSION_1;
386 """)
387 self.assertEqual(expected_version, version_file.getvalue())
388
389
390class IntegrationTest(unittest.TestCase):
391 def test_integration(self):
392 input_file = cStringIO.StringIO(textwrap.dedent("""\
393 VERSION_1 {
394 global:
395 foo; # var
396 bar; # x86
397 local:
398 *;
399 };
400
401 VERSION_2 { # arm
402 baz; # introduced=9
403 qux; # versioned=14
404 } VERSION_1;
405
406 VERSION_3 { # introduced=14
407 woodly;
408 doodly; # var
409 } VERSION_2;
410 """))
411 parser = gsl.SymbolFileParser(input_file)
412 versions = parser.parse()
413
414 src_file = cStringIO.StringIO()
415 version_file = cStringIO.StringIO()
416 generator = gsl.Generator(src_file, version_file, 'arm', 9)
417 generator.write(versions)
418
419 expected_src = textwrap.dedent("""\
420 int foo = 0;
421 void baz() {}
422 void qux() {}
423 """)
424 self.assertEqual(expected_src, src_file.getvalue())
425
426 expected_version = textwrap.dedent("""\
427 VERSION_1 {
428 global:
429 foo;
430 };
431 VERSION_2 {
432 global:
433 baz;
434 } VERSION_1;
435 """)
436 self.assertEqual(expected_version, version_file.getvalue())
437
438
439def main():
440 suite = unittest.TestLoader().loadTestsFromName(__name__)
441 unittest.TextTestRunner(verbosity=3).run(suite)
442
443
444if __name__ == '__main__':
445 main()