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