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