blob: 8b412b98af0b581d043722937aecb3837727e4df [file] [log] [blame]
Dan Albert06f58af2020-06-22 15:10:31 -07001#
2# Copyright (C) 2016 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16"""Tests for symbolfile."""
17import io
18import textwrap
19import unittest
20
21import symbolfile
Jiyong Park3f9c41d2022-07-16 23:30:09 +090022from symbolfile import Arch, Tag, Tags, Version, Symbol, Filter
23from copy import copy
Dan Albert06f58af2020-06-22 15:10:31 -070024
25# pylint: disable=missing-docstring
26
27
28class DecodeApiLevelTest(unittest.TestCase):
Dan Albertaf7b36d2020-06-23 11:21:21 -070029 def test_decode_api_level(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -070030 self.assertEqual(9, symbolfile.decode_api_level('9', {}))
31 self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000}))
32
33 with self.assertRaises(KeyError):
34 symbolfile.decode_api_level('O', {})
35
36
37class TagsTest(unittest.TestCase):
Dan Albertaf7b36d2020-06-23 11:21:21 -070038 def test_get_tags_no_tags(self) -> None:
Dan Albertead21552021-06-04 14:30:40 -070039 self.assertEqual(Tags(), symbolfile.get_tags('', {}))
40 self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {}))
Dan Albert06f58af2020-06-22 15:10:31 -070041
Dan Albertaf7b36d2020-06-23 11:21:21 -070042 def test_get_tags(self) -> None:
Steven Moreland8d5b9d02023-12-21 02:21:47 +000043 self.assertEqual(Tags.from_strs(['llndk', 'apex']),
44 symbolfile.get_tags('# llndk apex', {}))
45 self.assertEqual(Tags.from_strs(['llndk', 'apex']),
46 symbolfile.get_tags('foo # llndk apex', {}))
47
48 def test_get_unrecognized_tags(self) -> None:
49 with self.assertRaises(symbolfile.ParseError):
50 symbolfile.get_tags('# bar', {})
51 with self.assertRaises(symbolfile.ParseError):
52 symbolfile.get_tags('foo # bar', {})
53 with self.assertRaises(symbolfile.ParseError):
54 symbolfile.get_tags('# #', {})
55 with self.assertRaises(symbolfile.ParseError):
56 symbolfile.get_tags('# apex # llndk', {})
Dan Albert06f58af2020-06-22 15:10:31 -070057
Dan Albertaf7b36d2020-06-23 11:21:21 -070058 def test_split_tag(self) -> None:
59 self.assertTupleEqual(('foo', 'bar'),
60 symbolfile.split_tag(Tag('foo=bar')))
61 self.assertTupleEqual(('foo', 'bar=baz'),
62 symbolfile.split_tag(Tag('foo=bar=baz')))
Dan Albert06f58af2020-06-22 15:10:31 -070063 with self.assertRaises(ValueError):
Dan Albertaf7b36d2020-06-23 11:21:21 -070064 symbolfile.split_tag(Tag('foo'))
Dan Albert06f58af2020-06-22 15:10:31 -070065
Dan Albertaf7b36d2020-06-23 11:21:21 -070066 def test_get_tag_value(self) -> None:
67 self.assertEqual('bar', symbolfile.get_tag_value(Tag('foo=bar')))
68 self.assertEqual('bar=baz',
69 symbolfile.get_tag_value(Tag('foo=bar=baz')))
Dan Albert06f58af2020-06-22 15:10:31 -070070 with self.assertRaises(ValueError):
Dan Albertaf7b36d2020-06-23 11:21:21 -070071 symbolfile.get_tag_value(Tag('foo'))
Dan Albert06f58af2020-06-22 15:10:31 -070072
Dan Albertaf7b36d2020-06-23 11:21:21 -070073 def test_is_api_level_tag(self) -> None:
74 self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced=24')))
75 self.assertTrue(symbolfile.is_api_level_tag(Tag('introduced-arm=24')))
76 self.assertTrue(symbolfile.is_api_level_tag(Tag('versioned=24')))
Dan Albert06f58af2020-06-22 15:10:31 -070077
78 # Shouldn't try to process things that aren't a key/value tag.
Dan Albertaf7b36d2020-06-23 11:21:21 -070079 self.assertFalse(symbolfile.is_api_level_tag(Tag('arm')))
80 self.assertFalse(symbolfile.is_api_level_tag(Tag('introduced')))
81 self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned')))
Dan Albert06f58af2020-06-22 15:10:31 -070082
83 # We don't support arch specific `versioned` tags.
Dan Albertaf7b36d2020-06-23 11:21:21 -070084 self.assertFalse(symbolfile.is_api_level_tag(Tag('versioned-arm=24')))
Dan Albert06f58af2020-06-22 15:10:31 -070085
Dan Albertaf7b36d2020-06-23 11:21:21 -070086 def test_decode_api_level_tags(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -070087 api_map = {
88 'O': 9000,
89 'P': 9001,
90 }
91
92 tags = [
Dan Albertead21552021-06-04 14:30:40 -070093 symbolfile.decode_api_level_tag(t, api_map) for t in (
94 Tag('introduced=9'),
95 Tag('introduced-arm=14'),
96 Tag('versioned=16'),
97 Tag('arm'),
98 Tag('introduced=O'),
99 Tag('introduced=P'),
100 )
Dan Albert06f58af2020-06-22 15:10:31 -0700101 ]
102 expected_tags = [
Dan Albertaf7b36d2020-06-23 11:21:21 -0700103 Tag('introduced=9'),
104 Tag('introduced-arm=14'),
105 Tag('versioned=16'),
106 Tag('arm'),
107 Tag('introduced=9000'),
108 Tag('introduced=9001'),
Dan Albert06f58af2020-06-22 15:10:31 -0700109 ]
Dan Albertead21552021-06-04 14:30:40 -0700110 self.assertListEqual(expected_tags, tags)
Dan Albert06f58af2020-06-22 15:10:31 -0700111
112 with self.assertRaises(symbolfile.ParseError):
Dan Albertead21552021-06-04 14:30:40 -0700113 symbolfile.decode_api_level_tag(Tag('introduced=O'), {})
Dan Albert06f58af2020-06-22 15:10:31 -0700114
115
116class PrivateVersionTest(unittest.TestCase):
Dan Albertaf7b36d2020-06-23 11:21:21 -0700117 def test_version_is_private(self) -> None:
Dan Albertead21552021-06-04 14:30:40 -0700118 def mock_version(name: str) -> Version:
119 return Version(name, base=None, tags=Tags(), symbols=[])
Dan Albert06f58af2020-06-22 15:10:31 -0700120
Dan Albertead21552021-06-04 14:30:40 -0700121 self.assertFalse(mock_version('foo').is_private)
122 self.assertFalse(mock_version('PRIVATE').is_private)
123 self.assertFalse(mock_version('PLATFORM').is_private)
124 self.assertFalse(mock_version('foo_private').is_private)
125 self.assertFalse(mock_version('foo_platform').is_private)
126 self.assertFalse(mock_version('foo_PRIVATE_').is_private)
127 self.assertFalse(mock_version('foo_PLATFORM_').is_private)
128
129 self.assertTrue(mock_version('foo_PRIVATE').is_private)
130 self.assertTrue(mock_version('foo_PLATFORM').is_private)
Dan Albert06f58af2020-06-22 15:10:31 -0700131
132
133class SymbolPresenceTest(unittest.TestCase):
Dan Albertaf7b36d2020-06-23 11:21:21 -0700134 def test_symbol_in_arch(self) -> None:
Dan Albertead21552021-06-04 14:30:40 -0700135 self.assertTrue(symbolfile.symbol_in_arch(Tags(), Arch('arm')))
136 self.assertTrue(
137 symbolfile.symbol_in_arch(Tags.from_strs(['arm']), Arch('arm')))
Dan Albert06f58af2020-06-22 15:10:31 -0700138
Dan Albertead21552021-06-04 14:30:40 -0700139 self.assertFalse(
140 symbolfile.symbol_in_arch(Tags.from_strs(['x86']), Arch('arm')))
Dan Albert06f58af2020-06-22 15:10:31 -0700141
Dan Albertaf7b36d2020-06-23 11:21:21 -0700142 def test_symbol_in_api(self) -> None:
143 self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9))
144 self.assertTrue(
145 symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 9))
146 self.assertTrue(
147 symbolfile.symbol_in_api([Tag('introduced=9')], Arch('arm'), 14))
148 self.assertTrue(
149 symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'),
150 14))
151 self.assertTrue(
152 symbolfile.symbol_in_api([Tag('introduced-arm=9')], Arch('arm'),
153 14))
154 self.assertTrue(
155 symbolfile.symbol_in_api([Tag('introduced-x86=14')], Arch('arm'),
156 9))
157 self.assertTrue(
158 symbolfile.symbol_in_api(
159 [Tag('introduced-arm=9'),
160 Tag('introduced-x86=21')], Arch('arm'), 14))
161 self.assertTrue(
162 symbolfile.symbol_in_api(
163 [Tag('introduced=9'),
164 Tag('introduced-x86=21')], Arch('arm'), 14))
165 self.assertTrue(
166 symbolfile.symbol_in_api(
167 [Tag('introduced=21'),
168 Tag('introduced-arm=9')], Arch('arm'), 14))
169 self.assertTrue(
170 symbolfile.symbol_in_api([Tag('future')], Arch('arm'),
171 symbolfile.FUTURE_API_LEVEL))
Dan Albert06f58af2020-06-22 15:10:31 -0700172
Dan Albertaf7b36d2020-06-23 11:21:21 -0700173 self.assertFalse(
174 symbolfile.symbol_in_api([Tag('introduced=14')], Arch('arm'), 9))
175 self.assertFalse(
176 symbolfile.symbol_in_api([Tag('introduced-arm=14')], Arch('arm'),
177 9))
178 self.assertFalse(
179 symbolfile.symbol_in_api([Tag('future')], Arch('arm'), 9))
180 self.assertFalse(
181 symbolfile.symbol_in_api(
182 [Tag('introduced=9'), Tag('future')], Arch('arm'), 14))
183 self.assertFalse(
184 symbolfile.symbol_in_api([Tag('introduced-arm=9'),
185 Tag('future')], Arch('arm'), 14))
186 self.assertFalse(
187 symbolfile.symbol_in_api(
188 [Tag('introduced-arm=21'),
189 Tag('introduced-x86=9')], Arch('arm'), 14))
190 self.assertFalse(
191 symbolfile.symbol_in_api(
192 [Tag('introduced=9'),
193 Tag('introduced-arm=21')], Arch('arm'), 14))
194 self.assertFalse(
195 symbolfile.symbol_in_api(
196 [Tag('introduced=21'),
197 Tag('introduced-x86=9')], Arch('arm'), 14))
Dan Albert06f58af2020-06-22 15:10:31 -0700198
199 # Interesting edge case: this symbol should be omitted from the
200 # library, but this call should still return true because none of the
201 # tags indiciate that it's not present in this API level.
Dan Albertaf7b36d2020-06-23 11:21:21 -0700202 self.assertTrue(symbolfile.symbol_in_api([Tag('x86')], Arch('arm'), 9))
Dan Albert06f58af2020-06-22 15:10:31 -0700203
Dan Albertaf7b36d2020-06-23 11:21:21 -0700204 def test_verioned_in_api(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700205 self.assertTrue(symbolfile.symbol_versioned_in_api([], 9))
Dan Albertaf7b36d2020-06-23 11:21:21 -0700206 self.assertTrue(
207 symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 9))
208 self.assertTrue(
209 symbolfile.symbol_versioned_in_api([Tag('versioned=9')], 14))
Dan Albert06f58af2020-06-22 15:10:31 -0700210
Dan Albertaf7b36d2020-06-23 11:21:21 -0700211 self.assertFalse(
212 symbolfile.symbol_versioned_in_api([Tag('versioned=14')], 9))
Dan Albert06f58af2020-06-22 15:10:31 -0700213
214
215class OmitVersionTest(unittest.TestCase):
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900216 def setUp(self) -> None:
217 self.filter = Filter(arch = Arch('arm'), api = 9)
218 self.version = Version('foo', None, Tags(), [])
219
220 def assertOmit(self, f: Filter, v: Version) -> None:
221 self.assertTrue(f.should_omit_version(v))
222
223 def assertInclude(self, f: Filter, v: Version) -> None:
224 self.assertFalse(f.should_omit_version(v))
225
Dan Albertaf7b36d2020-06-23 11:21:21 -0700226 def test_omit_private(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900227 f = self.filter
228 v = self.version
Dan Albert06f58af2020-06-22 15:10:31 -0700229
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900230 self.assertInclude(f, v)
Dan Albert06f58af2020-06-22 15:10:31 -0700231
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900232 v.name = 'foo_PRIVATE'
233 self.assertOmit(f, v)
234
235 v.name = 'foo_PLATFORM'
236 self.assertOmit(f, v)
237
238 v.name = 'foo'
239 v.tags = Tags.from_strs(['platform-only'])
240 self.assertOmit(f, v)
Dan Albert06f58af2020-06-22 15:10:31 -0700241
Dan Albertaf7b36d2020-06-23 11:21:21 -0700242 def test_omit_llndk(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900243 f = self.filter
244 v = self.version
245 v_llndk = copy(v)
246 v_llndk.tags = Tags.from_strs(['llndk'])
Dan Albert06f58af2020-06-22 15:10:31 -0700247
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900248 self.assertOmit(f, v_llndk)
249
250 f.llndk = True
251 self.assertInclude(f, v)
252 self.assertInclude(f, v_llndk)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700253
254 def test_omit_apex(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900255 f = self.filter
256 v = self.version
257 v_apex = copy(v)
258 v_apex.tags = Tags.from_strs(['apex'])
Jiyong Park85cc35a2022-07-17 11:30:47 +0900259 v_systemapi = copy(v)
260 v_systemapi.tags = Tags.from_strs(['systemapi'])
Dan Albertaf7b36d2020-06-23 11:21:21 -0700261
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900262 self.assertOmit(f, v_apex)
263
264 f.apex = True
265 self.assertInclude(f, v)
266 self.assertInclude(f, v_apex)
Jiyong Park85cc35a2022-07-17 11:30:47 +0900267 self.assertOmit(f, v_systemapi)
Dan Albert06f58af2020-06-22 15:10:31 -0700268
Dan Albert56f52de2021-06-04 14:31:58 -0700269 def test_omit_systemapi(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900270 f = self.filter
271 v = self.version
Jiyong Park85cc35a2022-07-17 11:30:47 +0900272 v_apex = copy(v)
273 v_apex.tags = Tags.from_strs(['apex'])
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900274 v_systemapi = copy(v)
275 v_systemapi.tags = Tags.from_strs(['systemapi'])
Dan Albert56f52de2021-06-04 14:31:58 -0700276
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900277 self.assertOmit(f, v_systemapi)
278
Jiyong Park85cc35a2022-07-17 11:30:47 +0900279 f.systemapi = True
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900280 self.assertInclude(f, v)
281 self.assertInclude(f, v_systemapi)
Jiyong Park85cc35a2022-07-17 11:30:47 +0900282 self.assertOmit(f, v_apex)
Dan Albert56f52de2021-06-04 14:31:58 -0700283
Dan Albertaf7b36d2020-06-23 11:21:21 -0700284 def test_omit_arch(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900285 f_arm = self.filter
286 v_none = self.version
287 self.assertInclude(f_arm, v_none)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700288
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900289 v_arm = copy(v_none)
290 v_arm.tags = Tags.from_strs(['arm'])
291 self.assertInclude(f_arm, v_arm)
292
293 v_x86 = copy(v_none)
294 v_x86.tags = Tags.from_strs(['x86'])
295 self.assertOmit(f_arm, v_x86)
Dan Albertead21552021-06-04 14:30:40 -0700296
297 def test_omit_api(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900298 f_api9 = self.filter
299 v_none = self.version
300 self.assertInclude(f_api9, v_none)
Dan Albertead21552021-06-04 14:30:40 -0700301
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900302 v_api9 = copy(v_none)
303 v_api9.tags = Tags.from_strs(['introduced=9'])
304 self.assertInclude(f_api9, v_api9)
305
306 v_api14 = copy(v_none)
307 v_api14.tags = Tags.from_strs(['introduced=14'])
308 self.assertOmit(f_api9, v_api14)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700309
Dan Albert06f58af2020-06-22 15:10:31 -0700310
311class OmitSymbolTest(unittest.TestCase):
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900312 def setUp(self) -> None:
313 self.filter = Filter(arch = Arch('arm'), api = 9)
Dan Albert06f58af2020-06-22 15:10:31 -0700314
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900315 def assertOmit(self, f: Filter, s: Symbol) -> None:
316 self.assertTrue(f.should_omit_symbol(s))
317
318 def assertInclude(self, f: Filter, s: Symbol) -> None:
319 self.assertFalse(f.should_omit_symbol(s))
320
Jiyong Park4ecbdb62022-09-26 20:58:27 +0900321 def test_omit_ndk(self) -> None:
322 f_ndk = self.filter
323 f_nondk = copy(f_ndk)
324 f_nondk.ndk = False
325 f_nondk.apex = True
326
327 s_ndk = Symbol('foo', Tags())
328 s_nonndk = Symbol('foo', Tags.from_strs(['apex']))
329
330 self.assertInclude(f_ndk, s_ndk)
331 self.assertOmit(f_ndk, s_nonndk)
332 self.assertOmit(f_nondk, s_ndk)
333 self.assertInclude(f_nondk, s_nonndk)
334
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900335 def test_omit_llndk(self) -> None:
336 f_none = self.filter
337 f_llndk = copy(f_none)
338 f_llndk.llndk = True
339
340 s_none = Symbol('foo', Tags())
341 s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
342
343 self.assertOmit(f_none, s_llndk)
344 self.assertInclude(f_llndk, s_none)
345 self.assertInclude(f_llndk, s_llndk)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700346
Jooyung Han33eb6152024-03-11 15:46:48 +0900347 def test_omit_llndk_versioned(self) -> None:
348 f_ndk = self.filter
349 f_ndk.api = 35
350
351 f_llndk = copy(f_ndk)
352 f_llndk.llndk = True
353 f_llndk.api = 202404
354
355 s = Symbol('foo', Tags())
356 s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
357 s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404']))
358 s_34 = Symbol('foo', Tags.from_strs(['introduced=34']))
359 s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk']))
360 s_35 = Symbol('foo', Tags.from_strs(['introduced=35']))
361 s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404']))
362 s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504']))
363
364 # When targeting NDK, omit LLNDK tags
365 self.assertInclude(f_ndk, s)
366 self.assertOmit(f_ndk, s_llndk)
367 self.assertOmit(f_ndk, s_llndk_202404)
368 self.assertInclude(f_ndk, s_34)
369 self.assertOmit(f_ndk, s_34_llndk)
370 self.assertInclude(f_ndk, s_35)
371 self.assertOmit(f_ndk, s_35_llndk_202404)
372 self.assertOmit(f_ndk, s_35_llndk_202504)
373
374 # When targeting LLNDK, old symbols without any mode tags are included as LLNDK
375 self.assertInclude(f_llndk, s)
376 # When targeting LLNDK, old symbols with #llndk are included as LLNDK
377 self.assertInclude(f_llndk, s_llndk)
378 self.assertInclude(f_llndk, s_llndk_202404)
379 self.assertInclude(f_llndk, s_34)
380 self.assertInclude(f_llndk, s_34_llndk)
381 # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=.
382 self.assertOmit(f_llndk, s_35)
383 self.assertInclude(f_llndk, s_35_llndk_202404)
384 self.assertOmit(f_llndk, s_35_llndk_202504)
385
Dan Albertaf7b36d2020-06-23 11:21:21 -0700386 def test_omit_apex(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900387 f_none = self.filter
388 f_apex = copy(f_none)
389 f_apex.apex = True
Dan Albertaf7b36d2020-06-23 11:21:21 -0700390
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900391 s_none = Symbol('foo', Tags())
392 s_apex = Symbol('foo', Tags.from_strs(['apex']))
Jiyong Park85cc35a2022-07-17 11:30:47 +0900393 s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900394
395 self.assertOmit(f_none, s_apex)
396 self.assertInclude(f_apex, s_none)
397 self.assertInclude(f_apex, s_apex)
Jiyong Park85cc35a2022-07-17 11:30:47 +0900398 self.assertOmit(f_apex, s_systemapi)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700399
Dan Albert56f52de2021-06-04 14:31:58 -0700400 def test_omit_systemapi(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900401 f_none = self.filter
402 f_systemapi = copy(f_none)
Jiyong Park85cc35a2022-07-17 11:30:47 +0900403 f_systemapi.systemapi = True
Dan Albert56f52de2021-06-04 14:31:58 -0700404
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900405 s_none = Symbol('foo', Tags())
Jiyong Park85cc35a2022-07-17 11:30:47 +0900406 s_apex = Symbol('foo', Tags.from_strs(['apex']))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900407 s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
408
409 self.assertOmit(f_none, s_systemapi)
410 self.assertInclude(f_systemapi, s_none)
411 self.assertInclude(f_systemapi, s_systemapi)
Jiyong Park85cc35a2022-07-17 11:30:47 +0900412 self.assertOmit(f_systemapi, s_apex)
413
414 def test_omit_apex_and_systemapi(self) -> None:
415 f = self.filter
416 f.systemapi = True
417 f.apex = True
418
419 s_none = Symbol('foo', Tags())
420 s_apex = Symbol('foo', Tags.from_strs(['apex']))
421 s_systemapi = Symbol('foo', Tags.from_strs(['systemapi']))
422 self.assertInclude(f, s_none)
423 self.assertInclude(f, s_apex)
424 self.assertInclude(f, s_systemapi)
Dan Albert56f52de2021-06-04 14:31:58 -0700425
Dan Albertaf7b36d2020-06-23 11:21:21 -0700426 def test_omit_arch(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900427 f_arm = self.filter
428 s_none = Symbol('foo', Tags())
429 s_arm = Symbol('foo', Tags.from_strs(['arm']))
430 s_x86 = Symbol('foo', Tags.from_strs(['x86']))
Dan Albert06f58af2020-06-22 15:10:31 -0700431
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900432 self.assertInclude(f_arm, s_none)
433 self.assertInclude(f_arm, s_arm)
434 self.assertOmit(f_arm, s_x86)
Dan Albert06f58af2020-06-22 15:10:31 -0700435
Dan Albertaf7b36d2020-06-23 11:21:21 -0700436 def test_omit_api(self) -> None:
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900437 f_api9 = self.filter
438 s_none = Symbol('foo', Tags())
439 s_api9 = Symbol('foo', Tags.from_strs(['introduced=9']))
440 s_api14 = Symbol('foo', Tags.from_strs(['introduced=14']))
Dan Albertaf7b36d2020-06-23 11:21:21 -0700441
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900442 self.assertInclude(f_api9, s_none)
443 self.assertInclude(f_api9, s_api9)
444 self.assertOmit(f_api9, s_api14)
Dan Albertaf7b36d2020-06-23 11:21:21 -0700445
Dan Albert06f58af2020-06-22 15:10:31 -0700446
447class SymbolFileParseTest(unittest.TestCase):
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900448 def setUp(self) -> None:
449 self.filter = Filter(arch = Arch('arm'), api = 16)
450
Dan Albertaf7b36d2020-06-23 11:21:21 -0700451 def test_next_line(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700452 input_file = io.StringIO(textwrap.dedent("""\
453 foo
454
455 bar
456 # baz
457 qux
458 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900459 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700460 self.assertIsNone(parser.current_line)
461
462 self.assertEqual('foo', parser.next_line().strip())
Dan Albertaf7b36d2020-06-23 11:21:21 -0700463 assert parser.current_line is not None
Dan Albert06f58af2020-06-22 15:10:31 -0700464 self.assertEqual('foo', parser.current_line.strip())
465
466 self.assertEqual('bar', parser.next_line().strip())
467 self.assertEqual('bar', parser.current_line.strip())
468
469 self.assertEqual('qux', parser.next_line().strip())
470 self.assertEqual('qux', parser.current_line.strip())
471
472 self.assertEqual('', parser.next_line())
473 self.assertEqual('', parser.current_line)
474
Dan Albertaf7b36d2020-06-23 11:21:21 -0700475 def test_parse_version(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700476 input_file = io.StringIO(textwrap.dedent("""\
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000477 VERSION_1 { # weak introduced=35
Dan Albert06f58af2020-06-22 15:10:31 -0700478 baz;
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000479 qux; # apex llndk
Dan Albert06f58af2020-06-22 15:10:31 -0700480 };
481
482 VERSION_2 {
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000483 } VERSION_1; # not-a-tag
Dan Albert06f58af2020-06-22 15:10:31 -0700484 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900485 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700486
487 parser.next_line()
488 version = parser.parse_version()
489 self.assertEqual('VERSION_1', version.name)
490 self.assertIsNone(version.base)
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000491 self.assertEqual(Tags.from_strs(['weak', 'introduced=35']), version.tags)
Dan Albert06f58af2020-06-22 15:10:31 -0700492
Jooyung Han33eb6152024-03-11 15:46:48 +0900493 # Inherit introduced= tags from version block so that
494 # should_omit_tags() can differently based on introduced API level when treating
495 # LLNDK-available symbols.
Dan Albert06f58af2020-06-22 15:10:31 -0700496 expected_symbols = [
Jooyung Han33eb6152024-03-11 15:46:48 +0900497 Symbol('baz', Tags.from_strs(['introduced=35'])),
498 Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])),
Dan Albert06f58af2020-06-22 15:10:31 -0700499 ]
500 self.assertEqual(expected_symbols, version.symbols)
501
502 parser.next_line()
503 version = parser.parse_version()
504 self.assertEqual('VERSION_2', version.name)
505 self.assertEqual('VERSION_1', version.base)
Dan Albertead21552021-06-04 14:30:40 -0700506 self.assertEqual(Tags(), version.tags)
Dan Albert06f58af2020-06-22 15:10:31 -0700507
Dan Albertaf7b36d2020-06-23 11:21:21 -0700508 def test_parse_version_eof(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700509 input_file = io.StringIO(textwrap.dedent("""\
510 VERSION_1 {
511 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900512 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700513 parser.next_line()
514 with self.assertRaises(symbolfile.ParseError):
515 parser.parse_version()
516
Dan Albertaf7b36d2020-06-23 11:21:21 -0700517 def test_unknown_scope_label(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700518 input_file = io.StringIO(textwrap.dedent("""\
519 VERSION_1 {
520 foo:
521 }
522 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900523 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700524 parser.next_line()
525 with self.assertRaises(symbolfile.ParseError):
526 parser.parse_version()
527
Dan Albertaf7b36d2020-06-23 11:21:21 -0700528 def test_parse_symbol(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700529 input_file = io.StringIO(textwrap.dedent("""\
530 foo;
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000531 bar; # llndk apex
Dan Albert06f58af2020-06-22 15:10:31 -0700532 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900533 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700534
535 parser.next_line()
536 symbol = parser.parse_symbol()
537 self.assertEqual('foo', symbol.name)
Dan Albertead21552021-06-04 14:30:40 -0700538 self.assertEqual(Tags(), symbol.tags)
Dan Albert06f58af2020-06-22 15:10:31 -0700539
540 parser.next_line()
541 symbol = parser.parse_symbol()
542 self.assertEqual('bar', symbol.name)
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000543 self.assertEqual(Tags.from_strs(['llndk', 'apex']), symbol.tags)
Dan Albert06f58af2020-06-22 15:10:31 -0700544
Dan Albertaf7b36d2020-06-23 11:21:21 -0700545 def test_wildcard_symbol_global(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700546 input_file = io.StringIO(textwrap.dedent("""\
547 VERSION_1 {
548 *;
549 };
550 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900551 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700552 parser.next_line()
553 with self.assertRaises(symbolfile.ParseError):
554 parser.parse_version()
555
Dan Albertaf7b36d2020-06-23 11:21:21 -0700556 def test_wildcard_symbol_local(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700557 input_file = io.StringIO(textwrap.dedent("""\
558 VERSION_1 {
559 local:
560 *;
561 };
562 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900563 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700564 parser.next_line()
565 version = parser.parse_version()
566 self.assertEqual([], version.symbols)
567
Dan Albertaf7b36d2020-06-23 11:21:21 -0700568 def test_missing_semicolon(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700569 input_file = io.StringIO(textwrap.dedent("""\
570 VERSION_1 {
571 foo
572 };
573 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900574 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700575 parser.next_line()
576 with self.assertRaises(symbolfile.ParseError):
577 parser.parse_version()
578
Dan Albertaf7b36d2020-06-23 11:21:21 -0700579 def test_parse_fails_invalid_input(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700580 with self.assertRaises(symbolfile.ParseError):
581 input_file = io.StringIO('foo')
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900582 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700583 parser.parse()
584
Dan Albertaf7b36d2020-06-23 11:21:21 -0700585 def test_parse(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700586 input_file = io.StringIO(textwrap.dedent("""\
587 VERSION_1 {
588 local:
589 hidden1;
590 global:
591 foo;
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000592 bar; # llndk
Dan Albert06f58af2020-06-22 15:10:31 -0700593 };
594
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000595 VERSION_2 { # weak
Dan Albert06f58af2020-06-22 15:10:31 -0700596 # Implicit global scope.
597 woodly;
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000598 doodly; # llndk
Dan Albert06f58af2020-06-22 15:10:31 -0700599 local:
600 qwerty;
601 } VERSION_1;
602 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900603 parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
Dan Albert06f58af2020-06-22 15:10:31 -0700604 versions = parser.parse()
605
606 expected = [
Dan Albertead21552021-06-04 14:30:40 -0700607 symbolfile.Version('VERSION_1', None, Tags(), [
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900608 Symbol('foo', Tags()),
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000609 Symbol('bar', Tags.from_strs(['llndk'])),
Dan Albert06f58af2020-06-22 15:10:31 -0700610 ]),
Dan Albertead21552021-06-04 14:30:40 -0700611 symbolfile.Version(
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000612 'VERSION_2', 'VERSION_1', Tags.from_strs(['weak']), [
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900613 Symbol('woodly', Tags()),
Steven Moreland8d5b9d02023-12-21 02:21:47 +0000614 Symbol('doodly', Tags.from_strs(['llndk'])),
Dan Albertead21552021-06-04 14:30:40 -0700615 ]),
Dan Albert06f58af2020-06-22 15:10:31 -0700616 ]
617
618 self.assertEqual(expected, versions)
619
Dan Albertaf7b36d2020-06-23 11:21:21 -0700620 def test_parse_llndk_apex_symbol(self) -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700621 input_file = io.StringIO(textwrap.dedent("""\
622 VERSION_1 {
623 foo;
624 bar; # llndk
625 baz; # llndk apex
626 qux; # apex
627 };
628 """))
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900629 f = copy(self.filter)
630 f.llndk = True
631 parser = symbolfile.SymbolFileParser(input_file, {}, f)
Dan Albert06f58af2020-06-22 15:10:31 -0700632
633 parser.next_line()
634 version = parser.parse_version()
635 self.assertEqual('VERSION_1', version.name)
636 self.assertIsNone(version.base)
637
638 expected_symbols = [
Jiyong Park3f9c41d2022-07-16 23:30:09 +0900639 Symbol('foo', Tags()),
640 Symbol('bar', Tags.from_strs(['llndk'])),
641 Symbol('baz', Tags.from_strs(['llndk', 'apex'])),
642 Symbol('qux', Tags.from_strs(['apex'])),
Dan Albert06f58af2020-06-22 15:10:31 -0700643 ]
644 self.assertEqual(expected_symbols, version.symbols)
645
Jooyung Han33eb6152024-03-11 15:46:48 +0900646 def test_parse_llndk_version_is_missing(self) -> None:
647 input_file = io.StringIO(textwrap.dedent("""\
648 VERSION_1 { # introduced=35
649 foo;
650 bar; # llndk
651 };
652 """))
653 f = copy(self.filter)
654 f.llndk = True
655 parser = symbolfile.SymbolFileParser(input_file, {}, f)
656 with self.assertRaises(symbolfile.ParseError):
657 parser.parse()
658
Dan Albert06f58af2020-06-22 15:10:31 -0700659
Dan Albertaf7b36d2020-06-23 11:21:21 -0700660def main() -> None:
Dan Albert06f58af2020-06-22 15:10:31 -0700661 suite = unittest.TestLoader().loadTestsFromName(__name__)
662 unittest.TextTestRunner(verbosity=3).run(suite)
663
664
665if __name__ == '__main__':
666 main()