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