xref: /aosp_15_r20/tools/asuite/atest/test_finders/test_finder_utils_unittest.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1#!/usr/bin/env python3
2#
3# Copyright 2018, 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"""Unittests for test_finder_utils."""
18
19# pylint: disable=invalid-name
20# pylint: disable=missing-function-docstring
21
22import os
23from pathlib import Path
24import sys
25import tempfile
26import unittest
27from unittest import mock
28
29from atest import constants
30from atest import module_info
31from atest import unittest_constants as uc
32from atest import unittest_utils
33from atest.test_finders import test_finder_utils
34from atest.test_finders import test_info
35
36JSON_FILE_PATH = os.path.join(uc.TEST_DATA_DIR, uc.JSON_FILE)
37CLASS_DIR = 'foo/bar/jank/src/android/jank/cts/ui'
38OTHER_DIR = 'other/dir/'
39OTHER_CLASS_NAME = 'test.java'
40CLASS_NAME3 = 'test2'
41INT_DIR1 = os.path.join(uc.TEST_DATA_DIR, 'integration_dir_testing/int_dir1')
42INT_DIR2 = os.path.join(uc.TEST_DATA_DIR, 'integration_dir_testing/int_dir2')
43INT_FILE_NAME = 'int_dir_testing'
44FIND_TWO = uc.ROOT + 'other/dir/test.java\n' + uc.FIND_ONE
45FIND_THREE = '/a/b/c.java\n/d/e/f.java\n/g/h/i.java'
46FIND_THREE_LIST = ['/a/b/c.java', '/d/e/f.java', '/g/h/i.java']
47VTS_XML = 'VtsAndroidTest.xml.data'
48VTS_BITNESS_XML = 'VtsBitnessAndroidTest.xml'
49VTS_PUSH_DIR = 'vts_push_files'
50VTS_PLAN_DIR = 'vts_plan_files'
51VTS_XML_TARGETS = {
52    'VtsTestName',
53    'DATA/nativetest/vts_treble_vintf_test/vts_treble_vintf_test',
54    'DATA/nativetest64/vts_treble_vintf_test/vts_treble_vintf_test',
55    'DATA/lib/libhidl-gen-hash.so',
56    'DATA/lib64/libhidl-gen-hash.so',
57    'hal-hidl-hash/frameworks/hardware/interfaces/current.txt',
58    'hal-hidl-hash/hardware/interfaces/current.txt',
59    'hal-hidl-hash/system/hardware/interfaces/current.txt',
60    'hal-hidl-hash/system/libhidl/transport/current.txt',
61    'target_with_delim',
62    'out/dir/target',
63    'push_file1_target1',
64    'push_file1_target2',
65    'push_file2_target1',
66    'push_file2_target2',
67    'CtsDeviceInfo.apk',
68    'DATA/app/sl4a/sl4a.apk',
69}
70VTS_PLAN_TARGETS = {
71    os.path.join(
72        uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'vts-staging-default.xml.data'
73    ),
74    os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'vts-aa.xml.data'),
75    os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'vts-bb.xml.data'),
76    os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'vts-cc.xml.data'),
77    os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'vts-dd.xml.data'),
78}
79XML_TARGETS = {
80    'CtsJankDeviceTestCases',
81    'perf-setup',
82    'cts-tradefed',
83    'GtsEmptyTestApp',
84}
85PATH_TO_MODULE_INFO_WITH_AUTOGEN = {
86    'foo/bar/jank': [{'auto_test_config': True}]
87}
88PATH_TO_MODULE_INFO_WITH_MULTI_AUTOGEN = {
89    'foo/bar/jank': [{'auto_test_config': True}, {'auto_test_config': True}]
90}
91PATH_TO_MODULE_INFO_WITH_MULTI_AUTOGEN_AND_ROBO = {
92    'foo/bar': [{'auto_test_config': True}, {'auto_test_config': True}],
93    'foo/bar/jank': [
94        {constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC]}
95    ],
96}
97UNIT_TEST_SEARCH_ROOT = 'my/unit/test/root'
98IT_TEST_MATCHED_1_PATH = os.path.join(UNIT_TEST_SEARCH_ROOT, 'sub1')
99UNIT_TEST_MATCHED_2_PATH = os.path.join(UNIT_TEST_SEARCH_ROOT, 'sub1', 'sub2')
100UNIT_TEST_NOT_MATCHED_1_PATH = os.path.join(
101    os.path.dirname(UNIT_TEST_SEARCH_ROOT), 'sub1'
102)
103UNIT_TEST_MODULE_1 = 'unit_test_module_1'
104UNIT_TEST_MODULE_2 = 'unit_test_module_2'
105UNIT_TEST_MODULE_3 = 'unit_test_module_3'
106DALVIK_TEST_CONFIG = 'AndroidDalvikTest.xml.data'
107LIBCORE_TEST_CONFIG = 'AndroidLibCoreTest.xml.data'
108DALVIK_XML_TARGETS = XML_TARGETS | test_finder_utils.DALVIK_TEST_DEPS
109BUILD_TOP_DIR = tempfile.TemporaryDirectory().name
110PRODUCT_OUT_DIR = os.path.join(BUILD_TOP_DIR, 'out/target/product/vsoc_x86_64')
111HOST_OUT_DIR = tempfile.NamedTemporaryFile().name
112
113
114# pylint: disable=protected-access
115# pylint: disable=too-many-public-methods
116# pylint: disable=unnecessary-comprehension
117class TestFinderUtilsUnittests(unittest.TestCase):
118  """Unit tests for test_finder_utils.py"""
119
120  @mock.patch.object(
121      test_finder_utils, 'has_method_in_file', return_value=False
122  )
123  @mock.patch('builtins.input', return_value='0')
124  def test_extract_test_path(self, _, has_method):
125    """Test extract_test_dir method."""
126    paths = [os.path.join(uc.ROOT, CLASS_DIR, uc.CLASS_NAME + '.java')]
127    unittest_utils.assert_strict_equal(
128        self, test_finder_utils.extract_test_path(uc.FIND_ONE), paths
129    )
130    paths = [os.path.join(uc.ROOT, CLASS_DIR, uc.CLASS_NAME + '.java')]
131    unittest_utils.assert_strict_equal(
132        self, test_finder_utils.extract_test_path(FIND_TWO), paths
133    )
134    has_method.return_value = True
135    paths = [os.path.join(uc.ROOT, CLASS_DIR, uc.CLASS_NAME + '.java')]
136    unittest_utils.assert_strict_equal(
137        self, test_finder_utils.extract_test_path(uc.FIND_ONE, 'method'), paths
138    )
139
140  def test_has_method_in_file(self):
141    """Test has_method_in_file method."""
142    test_path = os.path.join(
143        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.cc'
144    )
145    self.assertTrue(
146        test_finder_utils.has_method_in_file(
147            test_path, frozenset(['PrintHelloWorld'])
148        )
149    )
150    self.assertFalse(
151        test_finder_utils.has_method_in_file(
152            test_path, frozenset(['PrintHelloWorld1'])
153        )
154    )
155    test_path = os.path.join(
156        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.java'
157    )
158    self.assertTrue(
159        test_finder_utils.has_method_in_file(
160            test_path, frozenset(['testMethod1'])
161        )
162    )
163    test_path = os.path.join(
164        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.java'
165    )
166    self.assertFalse(
167        test_finder_utils.has_method_in_file(
168            test_path, frozenset(['testMethod', 'testMethod2'])
169        )
170    )
171    test_path = os.path.join(
172        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.java'
173    )
174    self.assertFalse(
175        test_finder_utils.has_method_in_file(
176            test_path, frozenset(['testMethod'])
177        )
178    )
179
180  # TODO: (b/263330492) Stop mocking build environment variables.
181  def test_has_method_in_kt_file(self):
182    """Test has_method_in_file method with kt class path."""
183    test_path = os.path.join(
184        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.kt'
185    )
186    os_environ_mock = {constants.ANDROID_BUILD_TOP: uc.TEST_DATA_DIR}
187    with mock.patch.dict('os.environ', os_environ_mock, clear=True):
188      self.assertTrue(
189          test_finder_utils.has_method_in_file(
190              test_path, frozenset(['testMethod1'])
191          )
192      )
193      self.assertFalse(
194          test_finder_utils.has_method_in_file(
195              test_path, frozenset(['testMethod'])
196          )
197      )
198      self.assertTrue(
199          test_finder_utils.has_method_in_file(
200              test_path, frozenset(['testMethod1', 'testMethod2'])
201          )
202      )
203      self.assertFalse(
204          test_finder_utils.has_method_in_file(
205              test_path, frozenset(['testMethod', 'testMethod2'])
206          )
207      )
208
209  @mock.patch('builtins.input', return_value='1')
210  def test_extract_selected_tests(self, mock_input):
211    """Test method extract_selected_tests method."""
212    tests = []
213    self.assertEqual(test_finder_utils.extract_selected_tests(tests), None)
214    paths = [os.path.join(uc.ROOT, CLASS_DIR, uc.CLASS_NAME + '.java')]
215    unittest_utils.assert_strict_equal(
216        self, test_finder_utils.extract_test_path(uc.FIND_ONE), paths
217    )
218    paths = [os.path.join(uc.ROOT, OTHER_DIR, OTHER_CLASS_NAME)]
219    mock_input.return_value = '1'
220    unittest_utils.assert_strict_equal(
221        self, test_finder_utils.extract_test_path(FIND_TWO), paths
222    )
223    # Test inputing out-of-range integer or a string
224    mock_input.return_value = '100'
225    self.assertEqual(
226        test_finder_utils.extract_selected_tests(uc.CLASS_NAME), []
227    )
228    mock_input.return_value = 'lOO'
229    self.assertEqual(
230        test_finder_utils.extract_selected_tests(uc.CLASS_NAME), []
231    )
232
233  @mock.patch('builtins.input')
234  def test_extract_test_from_multiselect(self, mock_input):
235    """Test method extract_selected_tests method."""
236    # multi-select
237    paths = ['/a/b/c.java', '/g/h/i.java']
238    mock_input.return_value = '0,2'
239
240    unittest_utils.assert_strict_equal(
241        self,
242        sorted(test_finder_utils.extract_selected_tests(FIND_THREE_LIST)),
243        sorted(paths),
244    )
245
246    # selecting a range
247    paths = ['/d/e/f.java', '/g/h/i.java']
248    mock_input.return_value = '1-2'
249
250    unittest_utils.assert_strict_equal(
251        self, test_finder_utils.extract_selected_tests(FIND_THREE_LIST), paths
252    )
253
254    # mixed formats
255    paths = ['/a/b/c.java', '/d/e/f.java', '/g/h/i.java']
256    mock_input.return_value = '0,1-2'
257
258    unittest_utils.assert_strict_equal(
259        self,
260        sorted(test_finder_utils.extract_selected_tests(FIND_THREE_LIST)),
261        sorted(paths),
262    )
263
264    # input unsupported formats, return empty
265    paths = []
266    mock_input.return_value = '?/#'
267
268    unittest_utils.assert_strict_equal(
269        self, test_finder_utils.extract_test_path(FIND_THREE), paths
270    )
271
272  @mock.patch('builtins.input')
273  @mock.patch.object(test_finder_utils, 'get_selected_indices')
274  def test_multiselect_auxiliary_menu_all_returns_all_tests(
275      self, mock_get_selected_indices, mock_input):
276    paths = ['/a/b/c.java', '/d/e/f.java', '/g/h/i.java']
277    mock_input.return_value = 'A'
278
279    unittest_utils.assert_strict_equal(
280        self,
281        sorted(test_finder_utils.extract_selected_tests(FIND_THREE_LIST)),
282        sorted(paths),
283    )
284    mock_get_selected_indices.assert_not_called()
285
286  @mock.patch('builtins.input')
287  @mock.patch.object(sys, 'exit')
288  @mock.patch.object(test_finder_utils, 'get_selected_indices')
289  def test_multiselect_auxiliary_menu_lowercase_cancel_returns_empty_list(
290      self, mock_get_selected_indices, mock_exit, mock_input):
291    # Cancelling the command
292    mock_input.return_value = 'c'
293
294    test_finder_utils.extract_selected_tests(FIND_THREE_LIST)
295
296    mock_exit.assert_called_once_with(0)
297    mock_get_selected_indices.assert_not_called()
298
299  @mock.patch('os.path.isdir')
300  def test_is_equal_or_sub_dir(self, mock_isdir):
301    """Test is_equal_or_sub_dir method."""
302    self.assertTrue(test_finder_utils.is_equal_or_sub_dir('/a/b/c', '/'))
303    self.assertTrue(test_finder_utils.is_equal_or_sub_dir('/a/b/c', '/a'))
304    self.assertTrue(test_finder_utils.is_equal_or_sub_dir('/a/b/c', '/a/b/c'))
305    self.assertFalse(test_finder_utils.is_equal_or_sub_dir('/a/b', '/a/b/c'))
306    self.assertFalse(test_finder_utils.is_equal_or_sub_dir('/a', '/f'))
307    mock_isdir.return_value = False
308    self.assertFalse(test_finder_utils.is_equal_or_sub_dir('/a/b', '/a'))
309
310  @mock.patch('os.path.isdir', return_value=True)
311  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
312  def test_find_parent_module_dir(self, _isfile, _isdir):
313    """Test _find_parent_module_dir method."""
314    abs_class_dir = '/%s' % CLASS_DIR
315    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
316    mock_module_info.path_to_module_info = {}
317    unittest_utils.assert_strict_equal(
318        self,
319        test_finder_utils.find_parent_module_dir(
320            uc.ROOT, abs_class_dir, mock_module_info
321        ),
322        uc.MODULE_DIR,
323    )
324
325  @mock.patch('os.path.isdir', return_value=True)
326  @mock.patch('os.path.isfile', return_value=False)
327  def test_find_parent_module_dir_with_autogen_config(self, _isfile, _isdir):
328    """Test _find_parent_module_dir method."""
329    abs_class_dir = '/%s' % CLASS_DIR
330    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
331    mock_module_info.path_to_module_info = PATH_TO_MODULE_INFO_WITH_AUTOGEN
332    unittest_utils.assert_strict_equal(
333        self,
334        test_finder_utils.find_parent_module_dir(
335            uc.ROOT, abs_class_dir, mock_module_info
336        ),
337        uc.MODULE_DIR,
338    )
339
340  @mock.patch('os.path.isdir', return_value=True)
341  @mock.patch('os.path.isfile', side_effect=[False] * 5 + [True])
342  def test_find_parent_module_dir_with_autogen_subconfig(self, _isfile, _isdir):
343    """Test _find_parent_module_dir method.
344
345    This case is testing when the auto generated config is in a
346    sub-directory of a larger test that contains a test config in a parent
347    directory.
348    """
349    abs_class_dir = '/%s' % CLASS_DIR
350    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
351    mock_module_info.path_to_module_info = (
352        PATH_TO_MODULE_INFO_WITH_MULTI_AUTOGEN
353    )
354    unittest_utils.assert_strict_equal(
355        self,
356        test_finder_utils.find_parent_module_dir(
357            uc.ROOT, abs_class_dir, mock_module_info
358        ),
359        uc.MODULE_DIR,
360    )
361
362  @mock.patch('os.path.isdir', return_value=True)
363  @mock.patch('os.path.isfile', return_value=False)
364  def test_find_parent_module_dir_with_multi_autogens(self, _isfile, _isdir):
365    """Test _find_parent_module_dir method.
366
367    This case returns folders with multiple autogenerated configs defined.
368    """
369    abs_class_dir = '/%s' % CLASS_DIR
370    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
371    mock_module_info.path_to_module_info = (
372        PATH_TO_MODULE_INFO_WITH_MULTI_AUTOGEN
373    )
374    unittest_utils.assert_strict_equal(
375        self,
376        test_finder_utils.find_parent_module_dir(
377            uc.ROOT, abs_class_dir, mock_module_info
378        ),
379        uc.MODULE_DIR,
380    )
381
382  @mock.patch('os.path.isdir', return_value=True)
383  @mock.patch('os.path.isfile', return_value=False)
384  def test_find_parent_module_dir_with_robo_and_autogens(self, _isfile, _isdir):
385    """Test _find_parent_module_dir method.
386
387    This case returns folders with multiple autogenerated configs defined
388    with a Robo test above them, which is the expected result.
389    """
390    abs_class_dir = '/%s' % CLASS_DIR
391    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
392    mock_module_info.path_to_module_info = (
393        PATH_TO_MODULE_INFO_WITH_MULTI_AUTOGEN_AND_ROBO
394    )
395    unittest_utils.assert_strict_equal(
396        self,
397        test_finder_utils.find_parent_module_dir(
398            uc.ROOT, abs_class_dir, mock_module_info
399        ),
400        uc.MODULE_DIR,
401    )
402
403  @mock.patch('os.path.isdir', return_value=True)
404  @mock.patch('os.path.isfile', return_value=False)
405  def test_find_parent_module_dir_robo(self, _isfile, _isdir):
406    """Test _find_parent_module_dir method.
407
408    Make sure we behave as expected when we encounter a robo module path.
409    """
410    abs_class_dir = '/%s' % CLASS_DIR
411    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
412    mock_module_info.is_legacy_robolectric_class.return_value = True
413    rel_class_dir_path = os.path.relpath(abs_class_dir, uc.ROOT)
414    mock_module_info.path_to_module_info = {rel_class_dir_path: [{}]}
415    unittest_utils.assert_strict_equal(
416        self,
417        test_finder_utils.find_parent_module_dir(
418            uc.ROOT, abs_class_dir, mock_module_info
419        ),
420        rel_class_dir_path,
421    )
422
423  def test_get_targets_from_xml(self):
424    """Test get_targets_from_xml method."""
425    # Mocking Etree is near impossible, so use a real file, but mocking
426    # ModuleInfo is still fine. Just have it return False when it finds a
427    # module that states it's not a module.
428    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
429    mock_module_info.is_module.side_effect = lambda module: (
430        not module == 'is_not_module'
431    )
432    xml_file = os.path.join(uc.TEST_DATA_DIR, constants.MODULE_CONFIG + '.data')
433    unittest_utils.assert_strict_equal(
434        self,
435        test_finder_utils.get_targets_from_xml(xml_file, mock_module_info),
436        XML_TARGETS,
437    )
438
439  def test_get_targets_from_dalvik_xml(self):
440    """Test get_targets_from_xml method with dalvik class."""
441    # Mocking Etree is near impossible, so use a real file, but mocking
442    # ModuleInfo is still fine. Just have it return False when it finds a
443    # module that states it's not a module.
444    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
445    mock_module_info.is_module.side_effect = lambda module: (
446        not module == 'is_not_module'
447    )
448    xml_file = os.path.join(uc.TEST_DATA_DIR, DALVIK_TEST_CONFIG)
449    unittest_utils.assert_strict_equal(
450        self,
451        test_finder_utils.get_targets_from_xml(xml_file, mock_module_info),
452        DALVIK_XML_TARGETS,
453    )
454
455  def test_get_targets_from_libcore_xml(self):
456    """Test get_targets_from_xml method with libcore class."""
457    # Mocking Etree is near impossible, so use a real file, but mocking
458    # ModuleInfo is still fine. Just have it return False when it finds a
459    # module that states it's not a module.
460    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
461    mock_module_info.is_module.side_effect = lambda module: (
462        not module == 'is_not_module'
463    )
464    xml_file = os.path.join(uc.TEST_DATA_DIR, LIBCORE_TEST_CONFIG)
465    unittest_utils.assert_strict_equal(
466        self,
467        test_finder_utils.get_targets_from_xml(xml_file, mock_module_info),
468        DALVIK_XML_TARGETS,
469    )
470
471  @mock.patch.object(
472      test_finder_utils,
473      '_VTS_PUSH_DIR',
474      os.path.join(uc.TEST_DATA_DIR, VTS_PUSH_DIR),
475  )
476  def test_get_targets_from_vts_xml(self):
477    """Test get_targets_from_vts_xml method."""
478    # Mocking Etree is near impossible, so use a real file, but mock out
479    # ModuleInfo,
480    mock_module_info = mock.Mock(spec=module_info.ModuleInfo)
481    mock_module_info.is_module.return_value = True
482    xml_file = os.path.join(uc.TEST_DATA_DIR, VTS_XML)
483    unittest_utils.assert_strict_equal(
484        self,
485        test_finder_utils.get_targets_from_vts_xml(
486            xml_file, '', mock_module_info
487        ),
488        VTS_XML_TARGETS,
489    )
490
491  @mock.patch('builtins.input', return_value='0')
492  def test_search_integration_dirs(self, mock_input):
493    """Test search_integration_dirs."""
494    mock_input.return_value = '0'
495    paths = [os.path.join(uc.ROOT, INT_DIR1, INT_FILE_NAME + '.xml')]
496    int_dirs = [INT_DIR1]
497    test_result = test_finder_utils.search_integration_dirs(
498        INT_FILE_NAME, int_dirs
499    )
500    unittest_utils.assert_strict_equal(self, test_result, paths)
501    int_dirs = [INT_DIR1, INT_DIR2]
502    test_result = test_finder_utils.search_integration_dirs(
503        INT_FILE_NAME, int_dirs
504    )
505    unittest_utils.assert_strict_equal(self, test_result, paths)
506
507  @mock.patch('os.path.isfile', return_value=False)
508  @mock.patch('os.environ.get', return_value=uc.TEST_CONFIG_DATA_DIR)
509  @mock.patch('builtins.input', return_value='0')
510  # pylint: disable=too-many-statements
511  def test_find_class_file(self, mock_input, _mock_env, _mock_isfile):
512    """Test find_class_file."""
513    # 1. Java class(find).
514    java_tmp_test_result = []
515    mock_input.return_value = '0'
516    java_class = os.path.join(
517        uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA + '.java'
518    )
519    java_tmp_test_result.extend(
520        test_finder_utils.find_class_file(
521            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA
522        )
523    )
524    mock_input.return_value = '1'
525    kt_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA + '.kt')
526    java_tmp_test_result.extend(
527        test_finder_utils.find_class_file(
528            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA
529        )
530    )
531    self.assertTrue(java_class in java_tmp_test_result)
532    self.assertTrue(kt_class in java_tmp_test_result)
533
534    # 2. Java class(read index).
535    del java_tmp_test_result[:]
536    mock_input.return_value = '0'
537    _mock_isfile = True
538    java_class = os.path.join(
539        uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA + '.java'
540    )
541    java_tmp_test_result.extend(
542        test_finder_utils.find_class_file(
543            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA
544        )
545    )
546    mock_input.return_value = '1'
547    kt_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA + '.kt')
548    java_tmp_test_result.extend(
549        test_finder_utils.find_class_file(
550            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_JAVA
551        )
552    )
553    self.assertTrue(java_class in java_tmp_test_result)
554    self.assertTrue(kt_class in java_tmp_test_result)
555
556    # 3. Qualified Java class(find).
557    del java_tmp_test_result[:]
558    mock_input.return_value = '0'
559    _mock_isfile = False
560    java_qualified_class = '{0}.{1}'.format(
561        uc.FIND_PATH_FOLDER, uc.FIND_PATH_TESTCASE_JAVA
562    )
563    java_tmp_test_result.extend(
564        test_finder_utils.find_class_file(uc.FIND_PATH, java_qualified_class)
565    )
566    mock_input.return_value = '1'
567    java_tmp_test_result.extend(
568        test_finder_utils.find_class_file(uc.FIND_PATH, java_qualified_class)
569    )
570    self.assertTrue(java_class in java_tmp_test_result)
571    self.assertTrue(kt_class in java_tmp_test_result)
572
573    # 4. Qualified Java class(read index).
574    del java_tmp_test_result[:]
575    mock_input.return_value = '0'
576    _mock_isfile = True
577    java_qualified_class = '{0}.{1}'.format(
578        uc.FIND_PATH_FOLDER, uc.FIND_PATH_TESTCASE_JAVA
579    )
580    java_tmp_test_result.extend(
581        test_finder_utils.find_class_file(uc.FIND_PATH, java_qualified_class)
582    )
583    mock_input.return_value = '1'
584    java_tmp_test_result.extend(
585        test_finder_utils.find_class_file(uc.FIND_PATH, java_qualified_class)
586    )
587    self.assertTrue(java_class in java_tmp_test_result)
588    self.assertTrue(kt_class in java_tmp_test_result)
589
590    # 5. CC class(find).
591    cc_tmp_test_result = []
592    _mock_isfile = False
593    mock_input.return_value = '0'
594    cpp_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_FILENAME_CC + '.cpp')
595    cc_tmp_test_result.extend(
596        test_finder_utils.find_class_file(
597            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_CC, True
598        )
599    )
600    mock_input.return_value = '1'
601    cc_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_FILENAME_CC + '.cc')
602    cc_tmp_test_result.extend(
603        test_finder_utils.find_class_file(
604            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_CC, True
605        )
606    )
607    self.assertTrue(cpp_class in cc_tmp_test_result)
608    self.assertTrue(cc_class in cc_tmp_test_result)
609
610    # 6. CC class(read index).
611    del cc_tmp_test_result[:]
612    mock_input.return_value = '0'
613    _mock_isfile = True
614    cpp_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_FILENAME_CC + '.cpp')
615    cc_tmp_test_result.extend(
616        test_finder_utils.find_class_file(
617            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_CC, True
618        )
619    )
620    mock_input.return_value = '1'
621    cc_class = os.path.join(uc.FIND_PATH, uc.FIND_PATH_FILENAME_CC + '.cc')
622    cc_tmp_test_result.extend(
623        test_finder_utils.find_class_file(
624            uc.FIND_PATH, uc.FIND_PATH_TESTCASE_CC, True
625        )
626    )
627    self.assertTrue(cpp_class in cc_tmp_test_result)
628    self.assertTrue(cc_class in cc_tmp_test_result)
629
630  @mock.patch('builtins.input', return_value='0')
631  @mock.patch.object(test_finder_utils, 'get_dir_path_and_filename')
632  @mock.patch('os.path.exists', return_value=True)
633  def test_get_int_dir_from_path(self, _exists, _find, mock_input):
634    """Test get_int_dir_from_path."""
635    mock_input.return_value = '0'
636    int_dirs = [INT_DIR1]
637    path = os.path.join(uc.ROOT, INT_DIR1, INT_FILE_NAME + '.xml')
638    _find.return_value = (INT_DIR1, INT_FILE_NAME + '.xml')
639    test_result = test_finder_utils.get_int_dir_from_path(path, int_dirs)
640    unittest_utils.assert_strict_equal(self, test_result, INT_DIR1)
641    _find.return_value = (INT_DIR1, None)
642    test_result = test_finder_utils.get_int_dir_from_path(path, int_dirs)
643    unittest_utils.assert_strict_equal(self, test_result, None)
644    int_dirs = [INT_DIR1, INT_DIR2]
645    _find.return_value = (INT_DIR1, INT_FILE_NAME + '.xml')
646    test_result = test_finder_utils.get_int_dir_from_path(path, int_dirs)
647    unittest_utils.assert_strict_equal(self, test_result, INT_DIR1)
648
649  def test_get_install_locations(self):
650    """Test get_install_locations."""
651    host_installed_paths = ['out/host/a/b']
652    host_expect = set(['host'])
653    self.assertEqual(
654        test_finder_utils.get_install_locations(host_installed_paths),
655        host_expect,
656    )
657    device_installed_paths = ['out/target/c/d']
658    device_expect = set(['device'])
659    self.assertEqual(
660        test_finder_utils.get_install_locations(device_installed_paths),
661        device_expect,
662    )
663    both_installed_paths = ['out/host/e', 'out/target/f']
664    both_expect = set(['host', 'device'])
665    self.assertEqual(
666        test_finder_utils.get_install_locations(both_installed_paths),
667        both_expect,
668    )
669    no_installed_paths = []
670    no_expect = set()
671    self.assertEqual(
672        test_finder_utils.get_install_locations(no_installed_paths), no_expect
673    )
674
675  # Disable the fail test due to the breakage if test xml rename to xml.data.
676  # pylint: disable=pointless-string-statement
677  '''
678    def test_get_plans_from_vts_xml(self):
679        """Test get_plans_from_vts_xml method."""
680        xml_path = os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR,
681                                'vts-staging-default.xml.data')
682        self.assertEqual(
683            test_finder_utils.get_plans_from_vts_xml(xml_path),
684            VTS_PLAN_TARGETS)
685        xml_path = os.path.join(uc.TEST_DATA_DIR, VTS_PLAN_DIR, 'NotExist.xml')
686        self.assertRaises(atest_error.XmlNotExistError,
687                          test_finder_utils.get_plans_from_vts_xml, xml_path)
688    '''
689
690  def test_get_levenshtein_distance(self):
691    """Test get_levenshetine distance module correctly returns distance."""
692    self.assertEqual(
693        test_finder_utils.get_levenshtein_distance(uc.MOD1, uc.FUZZY_MOD1), 1
694    )
695
696    self.assertEqual(
697        test_finder_utils.get_levenshtein_distance(
698            uc.MOD2, uc.FUZZY_MOD2, dir_costs=(1, 2, 3)
699        ),
700        3,
701    )
702
703    self.assertEqual(
704        test_finder_utils.get_levenshtein_distance(
705            uc.MOD3, uc.FUZZY_MOD3, dir_costs=(1, 2, 1)
706        ),
707        8,
708    )
709
710  # pylint: disable=consider-iterating-dictionary
711  def test_get_cc_class_info(self):
712    """Test get_cc_class_info method."""
713    file_path = os.path.join(uc.TEST_DATA_DIR, 'my_cc_test.cc')
714    class_info = test_finder_utils.get_cc_class_info(file_path)
715
716    # 1. Ensure all classes are in the class info dict.
717    expect_classes = {
718        'Class1',
719        'FClass',
720        'FlagClass1',
721        'FFlagClass',
722        'ValueParamClass1',
723        'ValueParamClass2',
724        'TypedTestClass',
725        'TypedParamTestClass',
726    }
727    self.assertEqual({key for key in class_info.keys()}, expect_classes)
728
729    # 2. Ensure methods are correctly mapping to the right class.
730    self.assertEqual(class_info['ValueParamClass1']['methods'], {'VPMethod1'})
731    self.assertEqual(class_info['ValueParamClass2']['methods'], {'VPMethod2'})
732    self.assertEqual(class_info['TypedTestClass']['methods'], {'TypedTestName'})
733    self.assertEqual(
734        class_info['TypedParamTestClass']['methods'], {'TypedParamTestName'}
735    )
736    self.assertEqual(class_info['Class1']['methods'], {'Method1', 'Method2'})
737    self.assertEqual(class_info['FClass']['methods'], {'FMethod1', 'FMethod2'})
738    self.assertEqual(
739        class_info['FlagClass1']['methods'], {'Method1', 'Method2'}
740    )
741    self.assertEqual(
742        class_info['FFlagClass']['methods'], {'FMethod1', 'FMethod2'}
743    )
744
745    # 3. Ensure prefixes are correctly mapping to the right class.
746    self.assertEqual(
747        class_info['TypedParamTestClass']['prefixes'],
748        {'Instantiation3', 'Instantiation4'},
749    )
750    self.assertEqual(
751        class_info['ValueParamClass1']['prefixes'], {'Instantiation1'}
752    )
753    self.assertEqual(
754        class_info['ValueParamClass2']['prefixes'], {'Instantiation2'}
755    )
756
757    # 4. Ensure we can tell typed test.
758    self.assertTrue(class_info['TypedParamTestClass']['typed'])
759    self.assertTrue(class_info['TypedTestClass']['typed'])
760    self.assertFalse(class_info['ValueParamClass1']['typed'])
761    self.assertFalse(class_info['FClass']['typed'])
762    self.assertFalse(class_info['Class1']['typed'])
763    self.assertFalse(class_info['FFlagClass']['typed'])
764    self.assertFalse(class_info['FlagClass1']['typed'])
765
766  def test_get_java_method(self):
767    """Test get_java_method"""
768    expect_methods = {'testMethod1', 'testMethod2'}
769    target_java = os.path.join(
770        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.java'
771    )
772    self.assertEqual(
773        expect_methods, test_finder_utils.get_java_methods(target_java)
774    )
775    target_kt = os.path.join(
776        uc.TEST_DATA_DIR, 'class_file_path_testing', 'hello_world_test.kt'
777    )
778    self.assertEqual(
779        expect_methods, test_finder_utils.get_java_methods(target_kt)
780    )
781
782  def test_get_parent_cls_name(self):
783    """Test get_parent_cls_name"""
784    parent_cls = 'AtestClass'
785    target_java = os.path.join(
786        uc.TEST_DATA_DIR, 'path_testing', 'PathTesting.java'
787    )
788    self.assertEqual(
789        parent_cls, test_finder_utils.get_parent_cls_name(target_java)
790    )
791    parent_cls = 'AtestClassKt'
792    target_java = os.path.join(
793        uc.TEST_DATA_DIR, 'path_testing', 'PathTesting.kt'
794    )
795    self.assertEqual(
796        parent_cls, test_finder_utils.get_parent_cls_name(target_java)
797    )
798
799  @staticmethod
800  def _get_paths_side_effect(module_name):
801    """Mock return values for module_info.get_paths."""
802    if module_name == UNIT_TEST_MODULE_1:
803      return [IT_TEST_MATCHED_1_PATH]
804    if module_name == UNIT_TEST_MODULE_2:
805      return [UNIT_TEST_MATCHED_2_PATH]
806    if module_name == UNIT_TEST_MODULE_3:
807      return [UNIT_TEST_NOT_MATCHED_1_PATH]
808    return []
809
810  @mock.patch.object(
811      module_info.ModuleInfo,
812      'get_all_host_unit_tests',
813      return_value=[UNIT_TEST_MODULE_1, UNIT_TEST_MODULE_2, UNIT_TEST_MODULE_3],
814  )
815  @mock.patch.object(
816      module_info.ModuleInfo,
817      'get_paths',
818  )
819  def test_find_host_unit_tests(self, _get_paths, _mock_get_unit_tests):
820    """Test find_host_unit_tests"""
821    mod_info = module_info.load_from_file(module_file=JSON_FILE_PATH)
822    _get_paths.side_effect = self._get_paths_side_effect
823    expect_unit_tests = [UNIT_TEST_MODULE_1, UNIT_TEST_MODULE_2]
824    self.assertEqual(
825        sorted(expect_unit_tests),
826        sorted(
827            test_finder_utils.find_host_unit_tests(
828                mod_info, UNIT_TEST_SEARCH_ROOT
829            )
830        ),
831    )
832
833  def test_get_annotated_methods(self):
834    """Test get_annotated_methods"""
835    sample_path = os.path.join(uc.TEST_DATA_DIR, 'annotation', 'sample.txt')
836    real_methods = list(
837        test_finder_utils.get_annotated_methods('TestAnnotation1', sample_path)
838    )
839    real_methods.sort()
840    expect_methods = ['annotation1_method1', 'annotation1_method2']
841    expect_methods.sort()
842    self.assertEqual(expect_methods, real_methods)
843
844  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
845  def test_get_test_config_use_androidtestxml(self, _isfile):
846    """Test get_test_config_and_srcs using default AndroidTest.xml"""
847    android_root = '/'
848    mod_info = module_info.load_from_file(module_file=JSON_FILE_PATH)
849    t_info = test_info.TestInfo(
850        'androidtest_config_module', 'mock_runner', build_targets=set()
851    )
852    expect_config = os.path.join(
853        android_root, uc.ANDTEST_CONFIG_PATH, constants.MODULE_CONFIG
854    )
855    result, _ = test_finder_utils.get_test_config_and_srcs(t_info, mod_info)
856    self.assertEqual(expect_config, result)
857
858  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
859  def test_get_test_config_single_config(self, _isfile):
860    """Test get_test_config_and_srcs manually set it's config"""
861    android_root = '/'
862    mod_info = module_info.load_from_file(module_file=JSON_FILE_PATH)
863    t_info = test_info.TestInfo(
864        'single_config_module', 'mock_runner', build_targets=set()
865    )
866    expect_config = os.path.join(
867        android_root, uc.SINGLE_CONFIG_PATH, uc.SINGLE_CONFIG_NAME
868    )
869    result, _ = test_finder_utils.get_test_config_and_srcs(t_info, mod_info)
870    self.assertEqual(expect_config, result)
871
872  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
873  def test_get_test_config_main_multiple_config(self, _isfile):
874    """Test get_test_config_and_srcs which is the main module of multiple config"""
875    android_root = '/'
876    mod_info = module_info.load_from_file(module_file=JSON_FILE_PATH)
877    t_info = test_info.TestInfo(
878        'multiple_config_module', 'mock_runner', build_targets=set()
879    )
880    expect_config = os.path.join(
881        android_root, uc.MULTIPLE_CONFIG_PATH, uc.MAIN_CONFIG_NAME
882    )
883    result, _ = test_finder_utils.get_test_config_and_srcs(t_info, mod_info)
884    self.assertEqual(expect_config, result)
885
886  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
887  def test_get_test_config_subtest_in_multiple_config(self, _isfile):
888    """Test get_test_config_and_srcs not the main module of multiple config"""
889    android_root = '/'
890    mock_dict = {
891        'ANDROID_BUILD_TOP': android_root,
892        'ANDROID_PRODUCT_OUT': PRODUCT_OUT_DIR,
893        'ANDROID_HOST_OUT': HOST_OUT_DIR,
894    }
895    with mock.patch.dict('os.environ', mock_dict, clear=True):
896      mod_info = module_info.load_from_file(module_file=JSON_FILE_PATH)
897      t_info = test_info.TestInfo(
898          'Multiple2', 'mock_runner', build_targets=set()
899      )
900      expect_config = Path(
901          android_root, uc.MULTIPLE_CONFIG_PATH, uc.SUB_CONFIG_NAME_2
902      )
903
904      result, _ = test_finder_utils.get_test_config_and_srcs(t_info, mod_info)
905
906      self.assertEqual(expect_config, result)
907
908  def test_is_test_from_kernel_xml_input_xml_not_exist_return_false(self):
909    not_exist_xml = 'not/exist/xml/path'
910    test_name = 'test_name'
911
912    exist = test_finder_utils.is_test_from_kernel_xml(not_exist_xml, test_name)
913
914    self.assertEqual(exist, False)
915
916  def test_parse_test_reference_input_module_class_method_match(self):
917    test_module = 'myModule'
918    test_class = 'myClass'
919    test_method = 'myTest::Method'
920    test_ref = f'{test_module}:{test_class}#{test_method}'
921
922    result = test_finder_utils.parse_test_reference(test_ref)
923
924    self.assertEqual(test_module, result['module_name'])
925    self.assertEqual(test_class, result['pkg_class_name'])
926    self.assertEqual(test_method, result['method_name'])
927
928  def test_parse_test_reference_input_module_class_match(self):
929    test_module = 'myModule'
930    test_class = 'myClass'
931    test_ref = f'{test_module}:{test_class}'
932
933    result = test_finder_utils.parse_test_reference(test_ref)
934
935    self.assertEqual(test_module, result['module_name'])
936    self.assertEqual(test_class, result['pkg_class_name'])
937    self.assertEqual('', result.get('method_name', ''))
938
939  def test_parse_test_reference_input_module_class_parameter_method_match(self):
940    test_module = 'myModule'
941    test_class = 'myClass'
942    test_method = 'myTest::Method[0]'
943    test_ref = f'{test_module}:{test_class}#{test_method}'
944
945    result = test_finder_utils.parse_test_reference(test_ref)
946
947    self.assertEqual(test_module, result['module_name'])
948    self.assertEqual(test_class, result['pkg_class_name'])
949    self.assertEqual(test_method, result['method_name'])
950
951  def test_parse_test_reference_input_module_class_multiple_methods_match(self):
952    test_module = 'myModule'
953    test_class = 'myClass'
954    test_method = 'myTest::Method[0],myTest::Method[1]'
955    test_ref = f'{test_module}:{test_class}#{test_method}'
956
957    result = test_finder_utils.parse_test_reference(test_ref)
958
959    self.assertEqual(test_module, result['module_name'])
960    self.assertEqual(test_class, result['pkg_class_name'])
961    self.assertEqual(test_method, result['method_name'])
962
963  def test_parse_test_reference_input_class_method_not_match(self):
964    test_class = 'myClass'
965    test_method = 'myTest::Method'
966    test_ref = f'{test_class}#{test_method}'
967
968    result = test_finder_utils.parse_test_reference(test_ref)
969
970    self.assertEqual(result, dict())
971
972  def test_parse_test_reference_input_module_dashed_match(self):
973    test_module = 'my-module'
974    test_class = 'BR/EI/ZH'
975    test_ref = f'{test_module}:{test_class}'
976
977    result = test_finder_utils.parse_test_reference(test_ref)
978
979    self.assertEqual(test_module, result['module_name'])
980    self.assertEqual(test_class, result['pkg_class_name'])
981
982  def test_parse_test_reference_input_module_pkg_method_match(self):
983    test_module = 'myModule'
984    test_package = 'my.package'
985    test_method = 'myTest::Method'
986    test_ref = f'{test_module}:{test_package}#{test_method}'
987
988    result = test_finder_utils.parse_test_reference(test_ref)
989
990    self.assertEqual(test_module, result['module_name'])
991    self.assertEqual(test_package, result['pkg_class_name'])
992    self.assertEqual(test_method, result['method_name'])
993
994  def test_parse_test_reference_input_plan_class_match(self):
995    test_module = 'my/Module'
996    test_class = 'class'
997    test_ref = f'{test_module}:{test_class}'
998
999    result = test_finder_utils.parse_test_reference(test_ref)
1000
1001    self.assertEqual(test_module, result['module_name'])
1002    self.assertEqual(test_class, result['pkg_class_name'])
1003    self.assertEqual('', result.get('method_name', ''))
1004
1005  def test_parse_test_reference_input_module_parameter_class_and_method_match(
1006      self,
1007  ):
1008    test_module = 'myModule'
1009    test_class = 'myClass/abc0'
1010    test_method = 'myTest0/Method[0]'
1011    test_ref = f'{test_module}:{test_class}#{test_method}'
1012
1013    result = test_finder_utils.parse_test_reference(test_ref)
1014
1015    self.assertEqual(test_module, result['module_name'])
1016    self.assertEqual(test_class, result['pkg_class_name'])
1017    self.assertEqual(test_method, result['method_name'])
1018
1019
1020if __name__ == '__main__':
1021  unittest.main()
1022