#!/usr/bin/env python3
#
# Copyright 2018, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Unittests for module_finder."""

# pylint: disable=invalid-name
# pylint: disable=missing-function-docstring
# pylint: disable=too-many-lines
# pylint: disable=unsubscriptable-object

import copy
import os
import pathlib
import re
import tempfile
import unittest
from unittest import mock
from atest import atest_error
from atest import atest_utils
from atest import constants
from atest import module_info
from atest import module_info_unittest_base
from atest import unittest_constants as uc
from atest import unittest_utils
from atest.test_finders import module_finder
from atest.test_finders import test_filter_utils
from atest.test_finders import test_finder_utils
from atest.test_finders import test_info
from atest.test_runners import atest_tf_test_runner as atf_tr
from pyfakefs import fake_filesystem_unittest

MODULE_CLASS = '%s:%s' % (uc.MODULE_NAME, uc.CLASS_NAME)
MODULE_PACKAGE = '%s:%s' % (uc.MODULE_NAME, uc.PACKAGE)
CC_MODULE_CLASS = '%s:%s' % (uc.CC_MODULE_NAME, uc.CC_CLASS_NAME)
KERNEL_TEST_CLASS = 'test_class_1'
KERNEL_TEST_CONFIG = 'KernelTest.xml.data'
KERNEL_MODULE_CLASS = '%s:%s' % (
    constants.REQUIRED_LTP_TEST_MODULES[0],
    KERNEL_TEST_CLASS,
)
KERNEL_CONFIG_FILE = os.path.join(uc.TEST_DATA_DIR, KERNEL_TEST_CONFIG)
KERNEL_CLASS_FILTER = test_info.TestFilter(KERNEL_TEST_CLASS, frozenset())
KERNEL_MODULE_CLASS_DATA = {
    constants.TI_REL_CONFIG: KERNEL_CONFIG_FILE,
    constants.TI_FILTER: frozenset([KERNEL_CLASS_FILTER]),
}
KERNEL_MODULE_CLASS_INFO = test_info.TestInfo(
    constants.REQUIRED_LTP_TEST_MODULES[0],
    atf_tr.AtestTradefedTestRunner.NAME,
    uc.CLASS_BUILD_TARGETS,
    KERNEL_MODULE_CLASS_DATA,
)
FLAT_METHOD_INFO = test_info.TestInfo(
    uc.MODULE_NAME,
    atf_tr.AtestTradefedTestRunner.NAME,
    uc.MODULE_BUILD_TARGETS,
    data={
        constants.TI_FILTER: frozenset([uc.FLAT_METHOD_FILTER]),
        constants.TI_REL_CONFIG: uc.CONFIG_FILE,
    },
)
MODULE_CLASS_METHOD = '%s#%s' % (MODULE_CLASS, uc.METHOD_NAME)
CC_MODULE_CLASS_METHOD = '%s#%s' % (CC_MODULE_CLASS, uc.CC_METHOD_NAME)
CLASS_INFO_MODULE_2 = test_info.TestInfo(
    uc.MODULE2_NAME,
    atf_tr.AtestTradefedTestRunner.NAME,
    uc.CLASS_BUILD_TARGETS,
    data={
        constants.TI_FILTER: frozenset([uc.CLASS_FILTER]),
        constants.TI_REL_CONFIG: uc.CONFIG2_FILE,
    },
)
CC_CLASS_INFO_MODULE_2 = test_info.TestInfo(
    uc.CC_MODULE2_NAME,
    atf_tr.AtestTradefedTestRunner.NAME,
    uc.CLASS_BUILD_TARGETS,
    data={
        constants.TI_FILTER: frozenset([uc.CC_CLASS_FILTER]),
        constants.TI_REL_CONFIG: uc.CC_CONFIG2_FILE,
    },
)
DEFAULT_INSTALL_PATH = ['/path/to/install']
ROBO_MOD_PATH = ['/shared/robo/path']
NON_RUN_ROBO_MOD_NAME = 'robo_mod'
RUN_ROBO_MOD_NAME = 'run_robo_mod'
NON_RUN_ROBO_MOD = {
    constants.MODULE_NAME: NON_RUN_ROBO_MOD_NAME,
    constants.MODULE_PATH: ROBO_MOD_PATH,
    constants.MODULE_CLASS: ['random_class'],
}
RUN_ROBO_MOD = {
    constants.MODULE_NAME: RUN_ROBO_MOD_NAME,
    constants.MODULE_PATH: ROBO_MOD_PATH,
    constants.MODULE_CLASS: [constants.MODULE_CLASS_ROBOLECTRIC],
}

SEARCH_DIR_RE = re.compile(r'^find ([^ ]*).*$')


# pylint: disable=unused-argument
def classoutside_side_effect(find_cmd, shell=False):
  """Mock the check output of a find cmd where class outside module path."""
  search_dir = SEARCH_DIR_RE.match(find_cmd).group(1).strip()
  if search_dir == uc.ROOT:
    return uc.FIND_ONE
  return None


class ModuleFinderFindTestByModuleClassName(
    module_info_unittest_base.ModuleInfoTest
):

  def setUp(self):
    super().setUp()
    self.build_top = pathlib.Path('/main')

  def test_find_test_by_module_name_single_module_exists(self):
    module_name = 'SingleModuleTestCases'
    test_module = module_info_unittest_base.device_driven_test_module(
        name=module_name,
    )
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_module_name(module_name=module_name)

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_name_is_module_name'):
      self.assert_test_info_has_test_name(t_infos[0], module_name)
      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
    with self.subTest(name='contains_expected_build_targets'):
      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[0],
          'example_module-project',
      )

  @mock.patch(
      'subprocess.check_output',
      return_value=(
          'path/to/testmodule/src/com/android/myjavatests/MyJavaTestClass.java'
      ),
  )
  def test_find_test_by_module_class_name_native_found(self, find_cmd):
    module_name = 'MyModuleTestCases'
    test_module = module_info_unittest_base.device_driven_test_module(
        name=module_name, class_type=['NATIVE_TESTS']
    )
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_module_and_class(
        'MyModuleTestCases:MyJavaTestClass'
    )

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_name_is_module_name'):
      self.assert_test_info_has_test_name(t_infos[0], module_name)
      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
    with self.subTest(name='contains_expected_filters'):
      self.assert_test_info_has_class_filter(t_infos[0], 'MyJavaTestClass')
    with self.subTest(name='contains_expected_build_targets'):
      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[0],
          'example_module-project',
      )

  @mock.patch(
      'subprocess.check_output',
  )
  def test_find_test_by_module_class_module_name_unknown_test_info_is_none(
      self, find_cmd
  ):
    self.create_module_paths(['/project/module'])
    test_file_src = self.create_class_in_module(
        module_path='/project/module', class_name='MyJavaTestClass.java'
    )
    test_module = module_info_unittest_base.device_driven_test_module(
        name='MyModuleTestCases',
        class_type=['NATIVE_TESTS'],
        module_path='project/module',
        srcs=[test_file_src],
    )
    find_cmd.return_value = test_file_src
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_class_name(
        class_name='MyJavaTestClass', module_name='Unknown'
    )

    self.assertIsNone(t_infos)

  @mock.patch(
      'subprocess.check_output',
      return_value=[
          'example_module/project/src/com/android/myjavatests/MyJavaTestClass.java'
      ],
  )
  @mock.patch.object(
      test_finder_utils, 'get_multiple_selection_answer', return_value='A'
  )
  def test_find_test_by_module_class_multiple_configs_tests_found(
      self, mock_test_selection, mock_run_cmd
  ):
    module_name = 'MyModuleTestCases'
    test_module = (
        module_info_unittest_base.device_driven_multi_config_test_module(
            name=module_name,
            class_type=['NATIVE_TESTS'],
        )
    )
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_module_and_class(
        'MyModuleTestCases:MyMultiConfigJavaTestClass'
    )

    with self.subTest(name='first_test_name_corresponds_to_module_name'):
      self.assert_test_info_has_test_name(t_infos[0], module_name)
    with self.subTest(name='second_test_name_corresponds_to_config_name'):
      self.assert_test_info_has_test_name(t_infos[1], 'Config2')
    with self.subTest(name='raw_test_name_corresponds_to_module_name'):
      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
      self.assert_test_info_has_raw_test_name(t_infos[1], module_name)
    with self.subTest(name='contains_expected_filters'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'MyMultiConfigJavaTestClass'
      )
      self.assert_test_info_has_config(
          t_infos[0], 'example_module/project/configs/Config1.xml'
      )
      self.assert_test_info_has_class_filter(
          t_infos[1], 'MyMultiConfigJavaTestClass'
      )
      self.assert_test_info_has_config(
          t_infos[1], 'example_module/project/configs/Config2.xml'
      )
    with self.subTest(name='contains_expected_build_targets'):
      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[0],
          'example_module-project',
      )
      self.assert_test_info_contains_build_targets(t_infos[1], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[1],
          'example_module-project',
      )

  @mock.patch('subprocess.check_output')
  def test_find_test_by_class_unique_class_name_finds_class(self, mock_run_cmd):
    self.create_module_paths(['/project/tests/module1'])
    test_file_src = self.create_class_in_module(
        '/project/tests/module1', 'ClassOneTest.java'
    )
    mock_run_cmd.return_value = test_file_src
    test_module = module_info_unittest_base.device_driven_test_module(
        name='module_name',
        module_path='project/tests/module1',
        srcs=[
            test_file_src,
            '/project/tests/module1/src/tests/test2/ClassTwoTest.java',
        ],
    )
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_class_name(class_name='ClassOneTest')

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_info_has_expected_module_name'):
      self.assert_test_info_has_test_name(
          t_infos[0], test_module.get(constants.MODULE_NAME, [])
      )
    with self.subTest(name='contains_expected_class_filter'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'project.tests.module1.ClassOneTest'
      )

  @mock.patch.object(test_finder_utils, 'get_multiple_selection_answer')
  @mock.patch('subprocess.check_output')
  def test_find_test_by_class_multiple_class_names_returns_selection_menu(
      self, mock_run_cmd, mock_test_selection
  ):
    self.create_module_paths(
        ['/tests/android/module1', '/tests/android/module2']
    )
    test1_file_src = self.create_class_in_module(
        '/tests/android/module1', 'ClassOneTest.java'
    )
    test2_file_src = self.create_class_in_module(
        '/tests/android/module2', 'ClassOneTest.java'
    )
    mock_run_cmd.return_value = test1_file_src + '\n' + test2_file_src
    mock_test_selection.return_value = '0'
    test1_module = module_info_unittest_base.device_driven_test_module(
        name='module1',
        module_path='tests/android/module1',
        srcs=[test1_file_src],
    )
    test2_module = module_info_unittest_base.device_driven_test_module(
        name='module2',
        module_path='tests/android/module2',
        srcs=[test2_file_src],
    )
    finder = self.create_finder_with_multiple_modules(
        [test1_module, test2_module]
    )

    t_infos = finder.find_test_by_class_name(class_name='ClassOneTest')

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_info_has_expected_module_name'):
      self.assert_test_info_has_test_name(
          t_infos[0], test1_module.get(constants.MODULE_NAME, [])
      )
    with self.subTest(name='contains_expected_class_filter'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'tests.android.module1.ClassOneTest'
      )

  @mock.patch('subprocess.check_output')
  def test_find_test_by_class_multiple_classes_in_module_finds_class(
      self, mock_run_cmd
  ):
    self.create_module_paths(['/tests/android/module'])
    test1_file_src = self.create_class_in_module(
        '/tests/android/module', 'ClassOneTest.java'
    )
    test2_file_src = self.create_class_in_module(
        '/tests/android/module', 'ClassTwoTest.java'
    )
    mock_run_cmd.return_value = test1_file_src
    test_module = module_info_unittest_base.device_driven_test_module(
        name='module1',
        module_path='tests/android/module',
        srcs=[test1_file_src, test2_file_src],
    )
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_class_name(class_name='ClassOneTest')

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_info_has_expected_module_name'):
      self.assert_test_info_has_test_name(
          t_infos[0], test_module.get(constants.MODULE_NAME, [])
      )
    with self.subTest(name='contains_expected_class_filter'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'tests.android.module.ClassOneTest'
      )

  @mock.patch('atest.module_info.Loader.get_testable_module_from_memory')
  @mock.patch('subprocess.check_output')
  def test_find_test_by_class_multiple_modules_with_same_path_finds_class(
      self, mock_run_cmd, mock_loader
  ):
    self.create_module_paths(['/tests/android/multi_module'])
    test1_file_src = self.create_class_in_module(
        '/tests/android/multi_module', 'ClassOneTest.java'
    )
    test2_file_src = self.create_class_in_module(
        '/tests/android/multi_module', 'ClassTwoTest.java'
    )
    mock_run_cmd.return_value = test1_file_src
    test1_module = module_info_unittest_base.device_driven_test_module(
        name='multi_module1',
        module_path='tests/android/multi_module',
        srcs=[test1_file_src],
    )
    test2_module = module_info_unittest_base.device_driven_test_module(
        name='multi_module2',
        module_path='tests/android/multi_module',
        srcs=[test2_file_src],
    )
    finder = self.create_finder_with_multiple_modules(
        [test1_module, test2_module]
    )
    mock_loader.return_value = set(
        finder.module_info.name_to_module_info.keys()
    )

    t_infos = finder.find_test_by_class_name(class_name='ClassOneTest')

    with self.subTest(name='returns_one_test_info'):
      self.assertEqual(len(t_infos), 1)
    with self.subTest(name='test_info_has_expected_module_name'):
      self.assert_test_info_has_test_name(
          t_infos[0], test1_module.get(constants.MODULE_NAME, [])
      )
    with self.subTest(name='contains_expected_class_filter'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'tests.android.multi_module.ClassOneTest'
      )

  @mock.patch.object(test_finder_utils, 'get_multiple_selection_answer')
  @mock.patch('subprocess.check_output')
  def test_find_test_by_class_multiple_configs_one_test_per_config_found(
      self, mock_run_cmd, mock_test_selection
  ):
    module_name = 'multi_config_module'
    module_path = 'tests/android/multi_config_module'
    mock_test_selection.return_value = 'A'
    test1_file_src = self.create_class_in_module(
        '/tests/android/multi_config_module', 'ClassOneTest.java'
    )
    test_module = (
        module_info_unittest_base.device_driven_multi_config_test_module(
            name=module_name,
            module_path=module_path,
            srcs=[test1_file_src],
        )
    )
    mock_run_cmd.return_value = test1_file_src
    finder = self.create_finder_with_module(test_module)

    t_infos = finder.find_test_by_class_name(class_name='ClassOneTest')

    with self.subTest(name='returns_two_test_info'):
      self.assertEqual(len(t_infos), 2)
    with self.subTest(name='first_test_name_corresponds_to_module_name'):
      self.assert_test_info_has_test_name(t_infos[0], module_name)
    with self.subTest(name='second_test_name_corresponds_to_config_name'):
      self.assert_test_info_has_test_name(t_infos[1], 'Config2')
    with self.subTest(name='contains_expected_class_filter'):
      self.assert_test_info_has_class_filter(
          t_infos[0], 'tests.android.multi_config_module.ClassOneTest'
      )
      self.assert_test_info_has_config(
          t_infos[0], f'{module_path}/configs/Config1.xml'
      )
      self.assert_test_info_has_class_filter(
          t_infos[1], 'tests.android.multi_config_module.ClassOneTest'
      )
      self.assert_test_info_has_config(
          t_infos[1], f'{module_path}/configs/Config2.xml'
      )
    with self.subTest(name='raw_test_name_corresponds_to_module_name'):
      self.assert_test_info_has_raw_test_name(t_infos[0], module_name)
      self.assert_test_info_has_raw_test_name(t_infos[1], module_name)
    with self.subTest(name='contains_expected_build_targets'):
      self.assert_test_info_contains_build_targets(t_infos[0], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[0],
          module_name,
      )
      self.assert_test_info_contains_build_targets(t_infos[1], module_name)
      self.assert_test_info_contains_build_targets(
          t_infos[1],
          module_name,
      )

  def create_class_in_module(self, module_path: str, class_name: str) -> str:
    file_path = module_path + '/src/' + class_name
    self.fs.create_file(
        file_path, contents='package ' + module_path[1:].replace('/', '.')
    )
    return file_path

  def create_module_paths(self, modules: list[str]):
    for m in modules:
      module_path = pathlib.Path(m)
      module_path.mkdir(parents=True, exist_ok=True)

  def create_finder_with_module(
      self, test_module: dict
  ) -> module_finder.ModuleFinder:
    return module_finder.ModuleFinder(self.create_module_info([test_module]))

  def create_finder_with_multiple_modules(
      self, test_modules: list[dict]
  ) -> module_finder.ModuleFinder:
    return module_finder.ModuleFinder(self.create_module_info(test_modules))

  def assert_test_info_has_test_name(
      self, t_info: test_info.TestInfo, test_name: str
  ):
    self.assertEqual(t_info.test_name, test_name)

  def assert_test_info_has_raw_test_name(
      self, t_info: test_info.TestInfo, test_name: str
  ):
    self.assertEqual(t_info.raw_test_name, test_name)

  def assert_test_info_has_class_filter(
      self, t_info: test_info.TestInfo, class_name: str
  ):
    self.assertSetEqual(
        frozenset([test_info.TestFilter(class_name, frozenset())]),
        t_info.data[constants.TI_FILTER],
    )

  def assert_test_info_has_config(
      self, t_info: test_info.TestInfo, config: str
  ):
    self.assertEqual(config, t_info.data[constants.TI_REL_CONFIG])

  def assert_test_info_contains_build_targets(
      self, t_info: test_info.TestInfo, expected_build_target: str
  ):
    self.assertTrue(
        any(expected_build_target in target for target in t_info.build_targets)
    )


class ModuleFinderFindTestByPath(fake_filesystem_unittest.TestCase):
  """Test cases that invoke find_test_by_path."""

  def setUp(self):
    super().setUp()
    self.setUpPyfakefs()

  # pylint: disable=protected-access
  def create_empty_module_info(self):
    fake_temp_file_name = next(tempfile._get_candidate_names())
    self.fs.create_file(fake_temp_file_name, contents='{}')
    return module_info.load_from_file(module_file=fake_temp_file_name)

  def create_module_info(self, modules=None):
    modules = modules or []
    name_to_module_info = {}

    for m in modules:
      name_to_module_info[m['module_name']] = m

    return module_info.load_from_dict(name_to_module_info=name_to_module_info)

  # TODO: remove below mocks and hide unnecessary information.
  @mock.patch.object(module_finder.ModuleFinder, '_get_test_info_filter')
  @mock.patch.object(
      test_finder_utils, 'find_parent_module_dir', return_value=None
  )
  # pylint: disable=unused-argument
  def test_find_test_by_path_belong_to_dependencies(
      self, _mock_find_parent, _mock_test_filter
  ):
    """Test find_test_by_path if belong to test dependencies."""
    test1 = module(
        name='test1',
        classes=['class'],
        dependencies=['lib1'],
        installed=['install/test1'],
        auto_test_config=[True],
    )
    test2 = module(
        name='test2',
        classes=['class'],
        dependencies=['lib2'],
        installed=['install/test2'],
        auto_test_config=[True],
    )
    lib1 = module(name='lib1', srcs=['path/src1'])
    lib2 = module(name='lib2', srcs=['path/src2'])
    mod_info = self.create_module_info([test1, test2, lib1, lib2])
    mod_finder = module_finder.ModuleFinder(module_info=mod_info)
    self.fs.create_file('path/src1/main.cpp', contents='')
    test1_filter = test_info.TestFilter('test1Filter', frozenset())
    _mock_test_filter.return_value = test1_filter

    t_infos = mod_finder.find_test_by_path('path/src1')

    unittest_utils.assert_equal_testinfos(
        self,
        test_info.TestInfo(
            'test1',
            atf_tr.AtestTradefedTestRunner.NAME,
            {'test1', 'MODULES-IN-'},
            {
                constants.TI_FILTER: test1_filter,
                constants.TI_REL_CONFIG: 'AndroidTest.xml',
            },
            module_class=['class'],
        ),
        t_infos[0],
    )


# pylint: disable=protected-access
class ModuleFinderUnittests(unittest.TestCase):
  """Unit tests for module_finder.py"""

  def setUp(self):
    """Set up stuff for testing."""
    super().setUp()
    self.mod_finder = module_finder.ModuleFinder()
    self.mod_finder.module_info = mock.Mock(spec=module_info.ModuleInfo)
    self.mod_finder.module_info.path_to_module_info = {}
    self.mod_finder.module_info.is_mobly_module.return_value = False
    self.mod_finder.root_dir = uc.ROOT

  def test_is_vts_module(self):
    """Test _load_module_info_file regular operation."""
    mod_name = 'mod'
    is_vts_module_info = {'compatibility_suites': ['vts10', 'tests']}
    self.mod_finder.module_info.get_module_info.return_value = (
        is_vts_module_info
    )
    self.assertTrue(self.mod_finder._is_vts_module(mod_name))

    is_not_vts_module = {'compatibility_suites': ['vts10', 'cts']}
    self.mod_finder.module_info.get_module_info.return_value = is_not_vts_module
    self.assertFalse(self.mod_finder._is_vts_module(mod_name))

  # pylint: disable=unused-argument
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_build_targets',
      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
  )
  def test_find_test_by_module_name(self, _get_targ):
    """Test find_test_by_module_name."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    self.mod_finder.module_info.has_test_config.return_value = True
    mod_info = {
        'installed': ['/path/to/install'],
        'path': [uc.MODULE_DIR],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    t_infos = self.mod_finder.find_test_by_module_name(uc.MODULE_NAME)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.MODULE_INFO)
    self.mod_finder.module_info.get_module_info.return_value = None
    self.mod_finder.module_info.is_testable_module.return_value = False
    self.assertIsNone(self.mod_finder.find_test_by_module_name('Not_Module'))

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_class_name(
      self,
      _isdir,
      _isfile,
      _fqcn,
      mock_checkoutput,
      mock_build,
      _vts,
      _has_method_in_file,
      _is_parameterized,
      _is_build_file,
      _mock_unit_tests,
      mods_to_test,
  ):
    """Test find_test_by_class_name."""
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    mods_to_test.return_value = [uc.MODULE_NAME]
    t_infos = self.mod_finder.find_test_by_class_name(uc.CLASS_NAME)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)

    # with method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME)
    t_infos = self.mod_finder.find_test_by_class_name(class_with_method)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
    t_infos = self.mod_finder.find_test_by_class_name(class_methods)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO)
    # module and rel_config passed in
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    t_infos = self.mod_finder.find_test_by_class_name(
        uc.CLASS_NAME, uc.MODULE_NAME, uc.CONFIG_FILE
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
    # find output fails to find class file
    mock_checkoutput.return_value = ''
    self.assertIsNone(self.mod_finder.find_test_by_class_name('Not class'))
    # class is outside given module path
    mock_checkoutput.side_effect = classoutside_side_effect
    t_infos = self.mod_finder.find_test_by_class_name(
        uc.CLASS_NAME, uc.MODULE2_NAME, uc.CONFIG2_FILE
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], CLASS_INFO_MODULE_2)

  @mock.patch.object(
      test_finder_utils, 'find_parent_module_dir', return_value='foo/bar/jank'
  )
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  # pylint: disable=unused-argument
  def test_find_test_by_module_and_class(
      self,
      _isfile,
      _fqcn,
      mock_checkoutput,
      mock_build,
      _vts,
      _has_method_in_file,
      _is_parameterized,
      mock_parent_dir,
  ):
    """Test find_test_by_module_and_class."""
    # Native test was tested in test_find_test_by_cc_class_name().
    self.mod_finder.module_info.is_native_test.return_value = False
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    mod_info = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_PATH: [uc.MODULE_DIR],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)
    # with method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_module_and_class(MODULE_CLASS_METHOD)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)
    self.mod_finder.module_info.is_testable_module.return_value = False
    # bad module, good class, returns None
    bad_module = '%s:%s' % ('BadMod', uc.CLASS_NAME)
    self.mod_finder.module_info.get_module_info.return_value = None
    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module))
    # find output fails to find class file
    mock_checkoutput.return_value = ''
    bad_class = '%s:%s' % (uc.MODULE_NAME, 'Anything')
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_class))

  @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info')
  @mock.patch.object(
      module_finder.ModuleFinder,
      'find_test_by_kernel_class_name',
      return_value=None,
  )
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE)
  @mock.patch.object(
      test_finder_utils, 'find_class_file', side_effect=[None, None, '/']
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  # pylint: disable=unused-argument
  def test_find_test_by_module_and_class_part_2(
      self,
      _isfile,
      mock_fcf,
      mock_checkoutput,
      mock_build,
      _vts,
      _find_kernel,
      _class_info,
  ):
    """Test find_test_by_module_and_class for MODULE:CC_CLASS."""
    # Native test was tested in test_find_test_by_cc_class_name()
    self.mod_finder.module_info.is_native_test.return_value = False
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_paths.return_value = []
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    mod_info = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_PATH: [uc.CC_MODULE_DIR],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    _class_info.return_value = {
        'PFTest': {
            'methods': {'test1', 'test2'},
            'prefixes': set(),
            'typed': False,
        }
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_module_and_class(CC_MODULE_CLASS)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.CC_MODULE_CLASS_INFO
    )
    # with method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    mock_fcf.side_effect = [None, None, '/']
    t_infos = self.mod_finder.find_test_by_module_and_class(
        CC_MODULE_CLASS_METHOD
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD3_INFO)
    # bad module, good class, returns None
    bad_module = '%s:%s' % ('BadMod', uc.CC_CLASS_NAME)
    self.mod_finder.module_info.get_module_info.return_value = None
    self.mod_finder.module_info.is_testable_module.return_value = False
    self.assertIsNone(self.mod_finder.find_test_by_module_and_class(bad_module))

  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_module_test_config',
      return_value=[KERNEL_CONFIG_FILE],
  )
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_CC_ONE)
  @mock.patch.object(
      test_finder_utils, 'find_class_file', side_effect=[None, None, '/']
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  # pylint: disable=unused-argument
  def test_find_test_by_module_and_class_for_kernel_test(
      self, _isfile, mock_fcf, mock_checkoutput, mock_build, _vts, _test_config
  ):
    """Test find_test_by_module_and_class for MODULE:CC_CLASS."""
    # Kernel test was tested in find_test_by_kernel_class_name()
    self.mod_finder.module_info.is_native_test.return_value = False
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_paths.return_value = []
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    mod_info = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_PATH: [uc.CC_MODULE_DIR],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_module_and_class(KERNEL_MODULE_CLASS)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], KERNEL_MODULE_CLASS_INFO
    )

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_package_name(
      self,
      _isdir,
      _isfile,
      mock_checkoutput,
      mock_build,
      _vts,
      _mock_unit_tests,
      mods_to_test,
  ):
    """Test find_test_by_package_name."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    mods_to_test.return_value = [uc.MODULE_NAME]
    t_infos = self.mod_finder.find_test_by_package_name(uc.PACKAGE)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
    # with method, should raise
    pkg_with_method = '%s#%s' % (uc.PACKAGE, uc.METHOD_NAME)
    self.assertRaises(
        atest_error.MethodWithoutClassError,
        self.mod_finder.find_test_by_package_name,
        pkg_with_method,
    )
    # module and rel_config passed in
    t_infos = self.mod_finder.find_test_by_package_name(
        uc.PACKAGE, uc.MODULE_NAME, uc.CONFIG_FILE
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)
    # find output fails to find class file
    mock_checkoutput.return_value = ''
    self.assertIsNone(self.mod_finder.find_test_by_package_name('Not pkg'))

  @mock.patch('os.path.isdir', return_value=False)
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_PKG)
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  # pylint: disable=unused-argument
  def test_find_test_by_module_and_package(
      self, _isfile, mock_checkoutput, mock_build, _vts, _isdir
  ):
    """Test find_test_by_module_and_package."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_paths.return_value = []
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    mod_info = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_PATH: [uc.MODULE_DIR],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE)
    self.assertEqual(t_infos, None)
    _isdir.return_value = True
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    t_infos = self.mod_finder.find_test_by_module_and_package(MODULE_PACKAGE)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)

    # with method, raises
    module_pkg_with_method = '%s:%s#%s' % (
        uc.MODULE2_NAME,
        uc.PACKAGE,
        uc.METHOD_NAME,
    )
    self.assertRaises(
        atest_error.MethodWithoutClassError,
        self.mod_finder.find_test_by_module_and_package,
        module_pkg_with_method,
    )
    # bad module, good pkg, returns None
    self.mod_finder.module_info.is_testable_module.return_value = False
    bad_module = '%s:%s' % ('BadMod', uc.PACKAGE)
    self.mod_finder.module_info.get_module_info.return_value = None
    self.assertIsNone(
        self.mod_finder.find_test_by_module_and_package(bad_module)
    )
    # find output fails to find package path
    mock_checkoutput.return_value = ''
    bad_pkg = '%s:%s' % (uc.MODULE_NAME, 'Anything')
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.assertIsNone(self.mod_finder.find_test_by_module_and_package(bad_pkg))

  # TODO: Move and rewite it to ModuleFinderFindTestByPath.
  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
  @mock.patch.object(test_finder_utils, 'get_cc_class_info', return_value={})
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch(
      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
  @mock.patch('os.path.exists')
  # pylint: disable=unused-argument
  def test_find_test_by_path(
      self,
      mock_pathexists,
      mock_dir,
      _isfile,
      _real,
      _fqcn,
      _vts,
      mock_build,
      _has_cc_class,
      _has_method_in_file,
      _is_parameterized,
      _is_build_file,
      _get_cc_class_info,
      _mock_unit_tests,
      mods_to_test,
  ):
    """Test find_test_by_path."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_modules_by_include_deps.return_value = set()
    mock_build.return_value = set()
    mods_to_test.return_value = [uc.MODULE_NAME]
    # Check that we don't return anything with invalid test references.
    mock_pathexists.return_value = False
    unittest_utils.assert_equal_testinfos(
        self, None, self.mod_finder.find_test_by_path('bad/path')
    )
    mock_pathexists.return_value = True
    mock_dir.return_value = None
    unittest_utils.assert_equal_testinfos(
        self, None, self.mod_finder.find_test_by_path('no/module')
    )
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }

    # Happy path testing.
    mock_dir.return_value = uc.MODULE_DIR

    class_path = '%s.kt' % uc.CLASS_NAME
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])

    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_path(class_with_method)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)

    class_path = '%s.java' % uc.CLASS_NAME
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])

    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_path(class_with_method)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.METHOD_INFO)

    class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_path(class_with_methods)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], FLAT_METHOD_INFO)

    # Cc path testing.
    mods_to_test.return_value = [uc.CC_MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.CC_MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    mock_dir.return_value = uc.CC_MODULE_DIR
    class_path = '%s' % uc.CC_PATH
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO2, t_infos[0])

  # TODO: Move and rewite it to ModuleFinderFindTestByPath.
  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_build_targets',
      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
  )
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      test_finder_utils,
      'find_parent_module_dir',
      return_value=os.path.relpath(uc.TEST_DATA_DIR, uc.ROOT),
  )
  # pylint: disable=unused-argument
  def test_find_test_by_path_part_2(
      self, _find_parent, _is_vts, _get_build, mods_to_test
  ):
    """Test find_test_by_path for directories."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    # Dir with java files in it, should run as package
    class_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing')
    mods_to_test.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_path(class_dir)
    unittest_utils.assert_equal_testinfos(self, uc.PATH_INFO, t_infos[0])
    # Dir with no java files in it, should run whole module
    empty_dir = os.path.join(uc.TEST_DATA_DIR, 'path_testing_empty')
    t_infos = self.mod_finder.find_test_by_path(empty_dir)
    unittest_utils.assert_equal_testinfos(self, uc.EMPTY_PATH_INFO, t_infos[0])
    # Dir with cc files in it, should run as cc class
    class_dir = os.path.join(uc.TEST_DATA_DIR, 'cc_path_testing')
    mods_to_test.return_value = [uc.CC_MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.CC_MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    t_infos = self.mod_finder.find_test_by_path(class_dir)
    unittest_utils.assert_equal_testinfos(self, uc.CC_PATH_INFO, t_infos[0])

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(module_finder.test_finder_utils, 'get_cc_class_info')
  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.CC_FIND_ONE)
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_cc_class_name(
      self,
      _isdir,
      _isfile,
      mock_checkoutput,
      mock_build,
      _vts,
      _has_method,
      _is_build_file,
      _mock_unit_tests,
      _class_info,
      candicate_mods,
  ):
    """Test find_test_by_cc_class_name."""
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    candicate_mods.return_value = [uc.CC_MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.CC_MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    _class_info.return_value = {
        'PFTest': {
            'methods': {'test1', 'test2'},
            'prefixes': set(),
            'typed': False,
        }
    }
    t_infos = self.mod_finder.find_test_by_cc_class_name(uc.CC_CLASS_NAME)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO)

    # with method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    class_with_method = '%s#%s' % (uc.CC_CLASS_NAME, uc.CC_METHOD_NAME)
    t_infos = self.mod_finder.find_test_by_cc_class_name(class_with_method)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD_INFO)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    class_methods = '%s,%s' % (class_with_method, uc.CC_METHOD2_NAME)
    t_infos = self.mod_finder.find_test_by_cc_class_name(class_methods)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_METHOD2_INFO)
    # module and rel_config passed in
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    t_infos = self.mod_finder.find_test_by_cc_class_name(
        uc.CC_CLASS_NAME, uc.CC_MODULE_NAME, uc.CC_CONFIG_FILE
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CC_CLASS_INFO)
    # find output fails to find class file
    mock_checkoutput.return_value = ''
    self.assertIsNone(self.mod_finder.find_test_by_cc_class_name('Not class'))
    # class is outside given module path
    mock_checkoutput.return_value = uc.CC_FIND_ONE
    t_infos = self.mod_finder.find_test_by_cc_class_name(
        uc.CC_CLASS_NAME, uc.CC_MODULE2_NAME, uc.CC_CONFIG2_FILE
    )
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], CC_CLASS_INFO_MODULE_2
    )

  def test_get_testable_modules_with_ld(self):
    """Test get_testable_modules_with_ld"""
    self.mod_finder.module_info.get_testable_modules.return_value = [
        uc.MODULE_NAME,
        uc.MODULE2_NAME,
    ]
    # Without a misfit constraint
    ld1 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME)
    self.assertEqual([[16, uc.MODULE2_NAME], [1, uc.MODULE_NAME]], ld1)
    # With a misfit constraint
    ld2 = self.mod_finder.get_testable_modules_with_ld(uc.TYPO_MODULE_NAME, 2)
    self.assertEqual([[1, uc.MODULE_NAME]], ld2)

  def test_get_fuzzy_searching_modules(self):
    """Test get_fuzzy_searching_modules"""
    self.mod_finder.module_info.get_testable_modules.return_value = [
        uc.MODULE_NAME,
        uc.MODULE2_NAME,
    ]
    result = self.mod_finder.get_fuzzy_searching_results(uc.TYPO_MODULE_NAME)
    self.assertEqual(uc.MODULE_NAME, result[0])

  def test_get_build_targets_w_vts_core(self):
    """Test _get_build_targets."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
    self.mod_finder.module_info.get_paths.return_value = []
    mod_info = {
        constants.MODULE_COMPATIBILITY_SUITES: [constants.VTS_CORE_SUITE]
    }
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.assertEqual(
        self.mod_finder._get_build_targets('', ''),
        {constants.VTS_CORE_TF_MODULE},
    )

  def test_get_build_targets_w_mts(self):
    """Test _get_build_targets if module belong to mts."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
    self.mod_finder.module_info.get_paths.return_value = []
    mod_info = {constants.MODULE_COMPATIBILITY_SUITES: [constants.MTS_SUITE]}
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    self.assertEqual(
        self.mod_finder._get_build_targets('', ''), {constants.CTS_JAR}
    )

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value='')
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_class_name_w_module(
      self,
      _isdir,
      _isfile,
      _fqcn,
      mock_checkoutput,
      mock_build,
      _vts,
      _is_parameterized,
      mods_to_test,
  ):
    """Test test_find_test_by_class_name with module but without class found."""
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mods_to_test.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG]
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_class_name(
        uc.FULL_CLASS_NAME,
        module_name=uc.MODULE_NAME,
        rel_config_path=uc.CONFIG_FILE,
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.CLASS_INFO)

  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value='')
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_package_name_w_module(
      self, _isdir, _isfile, mock_checkoutput, mock_build, _vts
  ):
    """Test find_test_by_package_name with module but without package found."""
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.get_module_names.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_paths.return_value = [uc.TEST_DATA_CONFIG]
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    t_infos = self.mod_finder.find_test_by_package_name(
        uc.PACKAGE, module_name=uc.MODULE_NAME, rel_config=uc.CONFIG_FILE
    )
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.PACKAGE_INFO)

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=True
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch(
      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
  @mock.patch('os.path.exists')
  # pylint: disable=unused-argument
  def test_find_test_by_path_is_parameterized_java(
      self,
      mock_pathexists,
      mock_dir,
      _isfile,
      _real,
      _fqcn,
      _vts,
      mock_build,
      _has_cc_class,
      _has_method_in_file,
      _is_parameterized,
      _is_build_file,
      mods_to_test,
  ):
    """Test find_test_by_path and input path is parameterized class."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mock_build.return_value = set()
    mock_pathexists.return_value = True
    mods_to_test.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    # Happy path testing.
    mock_dir.return_value = uc.MODULE_DIR
    class_path = '%s.java' % uc.CLASS_NAME
    # Input include only one method
    class_with_method = '%s#%s' % (class_path, uc.METHOD_NAME)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_path(class_with_method)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO
    )
    # Input include multiple methods
    class_with_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    t_infos = self.mod_finder.find_test_by_path(class_with_methods)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO
    )

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(test_finder_utils, 'find_host_unit_tests', return_value=[])
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=True
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch('subprocess.check_output', return_value=uc.FIND_ONE)
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch('os.path.isdir', return_value=True)
  # pylint: disable=unused-argument
  def test_find_test_by_class_name_is_parameterized(
      self,
      _isdir,
      _isfile,
      _fqcn,
      mock_checkoutput,
      mock_build,
      _vts,
      _has_method_in_file,
      _is_parameterized,
      _is_build_file,
      _mock_unit_tests,
      mods_to_test,
  ):
    """Test find_test_by_class_name and the class is parameterized java."""
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = False
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    self.mod_finder.module_info.has_test_config.return_value = True
    mods_to_test.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    # With method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    class_with_method = '%s#%s' % (uc.CLASS_NAME, uc.METHOD_NAME)
    t_infos = self.mod_finder.find_test_by_class_name(class_with_method)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.PARAMETERIZED_METHOD_INFO
    )
    # With multiple method
    mock_build.return_value = copy.deepcopy(uc.MODULE_BUILD_TARGETS)
    class_methods = '%s,%s' % (class_with_method, uc.METHOD2_NAME)
    t_infos = self.mod_finder.find_test_by_class_name(class_methods)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.PARAMETERIZED_FLAT_METHOD_INFO
    )

  # pylint: disable=unused-argument
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_build_targets',
      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
  )
  def test_find_test_by_config_name(self, _get_targ):
    """Test find_test_by_config_name."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True

    mod_info = {
        'installed': ['/path/to/install'],
        'path': [uc.MODULE_DIR],
        constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE, uc.EXTRA_CONFIG_FILE],
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    name_to_module_info = {uc.MODULE_NAME: mod_info}
    self.mod_finder.module_info.name_to_module_info = name_to_module_info
    t_infos = self.mod_finder.find_test_by_config_name(uc.MODULE_CONFIG_NAME)
    unittest_utils.assert_equal_testinfos(
        self, t_infos[0], uc.TEST_CONFIG_MODULE_INFO
    )

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch(
      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
  @mock.patch('os.path.exists')
  # pylint: disable=unused-argument
  def test_find_test_by_path_w_src_verify(
      self,
      mock_pathexists,
      mock_dir,
      _isfile,
      _real,
      _fqcn,
      _vts,
      mock_build,
      _has_cc_class,
      _has_method_in_file,
      _is_parameterized,
      mods_to_test,
  ):
    """Test find_test_by_path with src information."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    mods_to_test.return_value = [uc.MODULE_NAME]
    mock_build.return_value = uc.CLASS_BUILD_TARGETS

    # Happy path testing.
    mock_dir.return_value = uc.MODULE_DIR
    # Test path not in module's `srcs` but `path`.
    class_path = f'somewhere/to/module/{uc.CLASS_NAME}.java'
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_PATH: ['somewhere/to/module'],
        constants.MODULE_TEST_CONFIG: [uc.CONFIG_FILE],
        constants.MODULE_COMPATIBILITY_SUITES: [],
        constants.MODULE_SRCS: [],
    }
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])

    # Test input file is in module's `srcs`.
    class_path = '%s.java' % uc.CLASS_NAME
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
        constants.MODULE_SRCS: [class_path],
    }

    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, uc.CLASS_INFO, t_infos[0])

  @mock.patch.object(module_finder.ModuleFinder, '_determine_modules_to_test')
  @mock.patch.object(test_finder_utils, 'get_cc_class_info')
  @mock.patch.object(atest_utils, 'is_build_file', return_value=True)
  @mock.patch.object(
      test_filter_utils, 'is_parameterized_java_class', return_value=False
  )
  @mock.patch.object(test_finder_utils, 'has_method_in_file', return_value=True)
  @mock.patch.object(test_finder_utils, 'has_cc_class', return_value=True)
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch(
      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
  )
  @mock.patch('os.path.isfile', side_effect=unittest_utils.isfile_side_effect)
  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
  @mock.patch('os.path.exists')
  # pylint: disable=unused-argument
  def test_find_test_by_path_for_cc_file(
      self,
      mock_pathexists,
      mock_dir,
      _isfile,
      _real,
      _fqcn,
      _vts,
      mock_build,
      _has_cc_class,
      _has_method_in_file,
      _is_parameterized,
      _is_build_file,
      _mock_cc_class_info,
      mods_to_test,
  ):
    """Test find_test_by_path for handling correct CC filter."""
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.has_test_config.return_value = True
    mock_build.return_value = set()
    # Check that we don't return anything with invalid test references.
    mock_pathexists.return_value = False
    mock_pathexists.return_value = True
    mock_dir.return_value = None
    mods_to_test.return_value = [uc.MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    # Happy path testing.
    mock_dir.return_value = uc.MODULE_DIR
    # Cc path testing if get_cc_class_info found those information.
    mods_to_test.return_value = [uc.CC_MODULE_NAME]
    self.mod_finder.module_info.get_module_info.return_value = {
        constants.MODULE_INSTALLED: DEFAULT_INSTALL_PATH,
        constants.MODULE_NAME: uc.CC_MODULE_NAME,
        constants.MODULE_CLASS: [],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    mock_dir.return_value = uc.CC_MODULE_DIR
    class_path = '%s' % uc.CC_PATH
    mock_build.return_value = uc.CLASS_BUILD_TARGETS
    # Test without parameterized test
    founded_classed = 'class1'
    founded_methods = {'method1'}
    founded_prefixes = set()
    _mock_cc_class_info.return_value = {
        founded_classed: {
            'methods': founded_methods,
            'prefixes': founded_prefixes,
            'typed': False,
        }
    }
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    cc_path_data = {
        constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE,
        constants.TI_FILTER: frozenset(
            {test_info.TestFilter(class_name='class1.*', methods=frozenset())}
        ),
    }
    cc_path_info = test_info.TestInfo(
        uc.CC_MODULE_NAME,
        atf_tr.AtestTradefedTestRunner.NAME,
        uc.CLASS_BUILD_TARGETS,
        cc_path_data,
    )
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0])
    # Test with parameterize test defined in input path
    founded_prefixes = {'class1'}
    _mock_cc_class_info.return_value = {
        founded_classed: {
            'methods': founded_methods,
            'prefixes': founded_prefixes,
            'typed': False,
        }
    }
    cc_path_data = {
        constants.TI_REL_CONFIG: uc.CC_CONFIG_FILE,
        constants.TI_FILTER: frozenset(
            {test_info.TestFilter(class_name='*/class1.*', methods=frozenset())}
        ),
    }
    cc_path_info = test_info.TestInfo(
        uc.CC_MODULE_NAME,
        atf_tr.AtestTradefedTestRunner.NAME,
        uc.CLASS_BUILD_TARGETS,
        cc_path_data,
    )
    t_infos = self.mod_finder.find_test_by_path(class_path)
    unittest_utils.assert_equal_testinfos(self, cc_path_info, t_infos[0])

  # pylint: disable=unused-argument
  @mock.patch.object(
      module_finder.ModuleFinder, '_is_vts_module', return_value=False
  )
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_build_targets',
      return_value=copy.deepcopy(uc.MODULE_BUILD_TARGETS),
  )
  def test_process_test_info(self, _get_targ, _is_vts):
    """Test _process_test_info."""
    mod_info = {
        'installed': ['/path/to/install'],
        'path': [uc.MODULE_DIR],
        constants.MODULE_CLASS: [constants.MODULE_CLASS_JAVA_LIBRARIES],
        constants.MODULE_COMPATIBILITY_SUITES: [],
    }
    self.mod_finder.module_info.is_robolectric_test.return_value = False
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    self.mod_finder.module_info.get_instrumentation_target_apps.return_value = (
        {}
    )
    self.mod_finder.module_info.get_module_info.return_value = mod_info
    processed_info = self.mod_finder._process_test_info(
        copy.deepcopy(uc.MODULE_INFO)
    )
    unittest_utils.assert_equal_testinfos(
        self, processed_info, uc.MODULE_INFO_W_DALVIK
    )

  # pylint: disable=unused-argument
  @mock.patch.object(module_finder.ModuleFinder, '_get_build_targets')
  @mock.patch.object(module_info.ModuleInfo, 'get_instrumentation_target_apps')
  @mock.patch.object(module_info.ModuleInfo, 'get_robolectric_type')
  @mock.patch.object(module_info.ModuleInfo, 'is_testable_module')
  def test_process_test_info_with_instrumentation_target_apps(
      self, testable, robotype, tapps, btargets
  ):
    """Test _process_test_info."""
    testable.return_value = True
    robotype.return_value = 0
    target_module = 'AmSlam'
    test_module = 'AmSlamTests'
    artifact_path = '/out/somewhere/app/AmSlam.apk'
    tapps.return_value = {target_module: {artifact_path}}
    btargets.return_value = {target_module}
    self.mod_finder.module_info.is_auto_gen_test_config.return_value = True
    self.mod_finder.module_info.get_robolectric_type.return_value = 0
    test1 = module(
        name=target_module,
        classes=['APPS'],
        path=['foo/bar/AmSlam'],
        installed=[artifact_path],
    )
    test2 = module(
        name=test_module,
        classes=['APPS'],
        path=['foo/bar/AmSlam/test'],
        installed=['/out/somewhere/app/AmSlamTests.apk'],
    )
    info = test_info.TestInfo(
        test_module,
        atf_tr.AtestTradefedTestRunner.NAME,
        set(),
        {
            constants.TI_REL_CONFIG: uc.CONFIG_FILE,
            constants.TI_FILTER: frozenset(),
        },
    )

    self.mod_finder.module_info = create_module_info([test1, test2])
    t_infos = self.mod_finder._process_test_info(info)

    self.assertTrue(target_module in t_infos.build_targets)
    self.assertEqual([artifact_path], t_infos.artifacts)

  @mock.patch.object(test_finder_utils, 'get_annotated_methods')
  def test_is_srcs_match_method_annotation_include_anno(
      self, _mock_get_anno_methods
  ):
    """Test _is_srcs_match_method_annotation with include annotation."""
    annotation_dict = {constants.INCLUDE_ANNOTATION: 'includeAnnotation1'}
    input_method = 'my_input_method'
    input_srcs = ['src1']
    # Test if input method matched include annotation.
    _mock_get_anno_methods.return_value = {input_method, 'not_my_input_method'}

    is_matched = self.mod_finder._is_srcs_match_method_annotation(
        input_method, input_srcs, annotation_dict
    )

    self.assertTrue(is_matched)
    # Test if input method not matched include annotation.
    _mock_get_anno_methods.return_value = {'not_my_input_method'}

    is_matched = self.mod_finder._is_srcs_match_method_annotation(
        input_method, input_srcs, annotation_dict
    )

    self.assertFalse(is_matched)

  @mock.patch.object(test_finder_utils, 'get_annotated_methods')
  @mock.patch.object(test_finder_utils, 'get_java_methods')
  def test_is_srcs_match_method_exclude_anno(
      self, _mock_get_java_methods, _mock_get_exclude_anno_methods
  ):
    """Test _is_srcs_match_method_annotation with exclude annotation."""
    annotation_dict = {constants.EXCLUDE_ANNOTATION: 'excludeAnnotation1'}
    input_method = 'my_input_method'
    input_srcs = ['src1']
    _mock_get_java_methods.return_value = {input_method, 'method1', 'method2'}
    # Test if input method matched exclude annotation.
    _mock_get_exclude_anno_methods.return_value = {input_method, 'method1'}

    is_matched = self.mod_finder._is_srcs_match_method_annotation(
        input_method, input_srcs, annotation_dict
    )

    self.assertFalse(is_matched)

    # Test if input method not matched exclude annotation.
    _mock_get_exclude_anno_methods.return_value = {'method2'}

    is_matched = self.mod_finder._is_srcs_match_method_annotation(
        input_method, input_srcs, annotation_dict
    )

    self.assertTrue(is_matched)

  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
  def test_get_matched_test_infos_no_filter(
      self, _mock_get_conf_srcs, _mock_get_filters
  ):
    """Test _get_matched_test_infos without test filters."""
    test_info1 = 'test_info1'
    test_infos = [test_info1]
    test_config = 'test_config'
    test_srcs = ['src1', 'src2']
    _mock_get_conf_srcs.return_value = test_config, test_srcs
    filter_dict = {}
    _mock_get_filters.return_value = filter_dict

    self.assertEqual(
        self.mod_finder._get_matched_test_infos(test_infos, {'method'}),
        test_infos,
    )

  @mock.patch.object(
      module_finder.ModuleFinder, '_is_srcs_match_method_annotation'
  )
  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
  def test_get_matched_test_infos_get_filter_method_match(
      self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match
  ):
    """Test _get_matched_test_infos with test filters and method match."""
    test_infos = [KERNEL_MODULE_CLASS_INFO]
    test_config = 'test_config'
    test_srcs = ['src1', 'src2']
    _mock_get_conf_srcs.return_value = test_config, test_srcs
    filter_dict = {'include-annotation': 'annotate1'}
    _mock_get_filters.return_value = filter_dict
    _mock_method_match.return_value = True

    unittest_utils.assert_strict_equal(
        self,
        self.mod_finder._get_matched_test_infos(test_infos, {'method'}),
        test_infos,
    )

  @mock.patch.object(
      module_finder.ModuleFinder, '_is_srcs_match_method_annotation'
  )
  @mock.patch.object(atest_utils, 'get_android_junit_config_filters')
  @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs')
  def test_get_matched_test_infos_filter_method_not_match(
      self, _mock_get_conf_srcs, _mock_get_filters, _mock_method_match
  ):
    """Test _get_matched_test_infos but method not match."""
    test_infos = [KERNEL_MODULE_CLASS_INFO]
    test_config = 'test_config'
    test_srcs = ['src1', 'src2']
    _mock_get_conf_srcs.return_value = test_config, test_srcs
    filter_dict = {'include-annotation': 'annotate1'}
    _mock_get_filters.return_value = filter_dict
    _mock_method_match.return_value = False

    self.assertEqual(
        self.mod_finder._get_matched_test_infos(test_infos, {'method'}), []
    )

  @mock.patch.object(module_finder.ModuleFinder, '_get_matched_test_infos')
  @mock.patch.object(
      module_finder.ModuleFinder, '_get_test_infos', return_value=uc.MODULE_INFO
  )
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_test_info_filter',
      return_value=uc.CLASS_FILTER,
  )
  @mock.patch.object(
      test_finder_utils, 'find_class_file', return_value=['path1']
  )
  def test_find_test_by_class_name_not_matched_filters(
      self,
      _mock_class_path,
      _mock_test_filters,
      _mock_test_infos,
      _mock_matched_test_infos,
  ):
    """Test find_test_by_class_name which has not matched filters."""
    found_test_infos = [uc.MODULE_INFO, uc.MODULE_INFO2]
    _mock_test_infos.return_value = found_test_infos
    matched_test_infos = [uc.MODULE_INFO2]
    _mock_matched_test_infos.return_value = matched_test_infos

    # Test if class without method
    test_infos = self.mod_finder.find_test_by_class_name('my.test.class')
    self.assertEqual(len(test_infos), 2)
    unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO)
    unittest_utils.assert_equal_testinfos(self, test_infos[1], uc.MODULE_INFO2)

    # Test if class with method
    test_infos = self.mod_finder.find_test_by_class_name(
        'my.test.class#myMethod'
    )
    self.assertEqual(len(test_infos), 1)
    unittest_utils.assert_equal_testinfos(self, test_infos[0], uc.MODULE_INFO2)

  @mock.patch.object(
      module_finder.ModuleFinder, '_get_test_infos', return_value=None
  )
  @mock.patch.object(
      module_finder.ModuleFinder,
      '_get_test_info_filter',
      return_value=uc.CLASS_FILTER,
  )
  @mock.patch.object(
      test_finder_utils, 'find_class_file', return_value=['path1']
  )
  def test_find_test_by_class_name_get_test_infos_none(
      self, _mock_class_path, _mock_test_filters, _mock_test_infos
  ):
    """Test find_test_by_class_name which has not matched test infos."""
    self.assertEqual(
        self.mod_finder.find_test_by_class_name('my.test.class'), None
    )


def create_empty_module_info():
  with fake_filesystem_unittest.Patcher() as patcher:
    # pylint: disable=protected-access
    fake_temp_file_name = next(tempfile._get_candidate_names())
    patcher.fs.create_file(fake_temp_file_name, contents='{}')
    return module_info.load_from_file(module_file=fake_temp_file_name)


def create_module_info(modules=None):
  name_to_module_info = {}
  modules = modules or []

  for m in modules:
    name_to_module_info[m['module_name']] = m

  return module_info.load_from_dict(name_to_module_info)


# pylint: disable=too-many-arguments
def module(
    name=None,
    path=None,
    installed=None,
    classes=None,
    auto_test_config=None,
    shared_libs=None,
    dependencies=None,
    runtime_dependencies=None,
    data=None,
    data_dependencies=None,
    compatibility_suites=None,
    host_dependencies=None,
    srcs=None,
):
  name = name or 'libhello'

  m = {}

  m['module_name'] = name
  m['class'] = classes
  m['path'] = path or ['']
  m['installed'] = installed or []
  m['is_unit_test'] = 'false'
  m['auto_test_config'] = auto_test_config or []
  m['shared_libs'] = shared_libs or []
  m['runtime_dependencies'] = runtime_dependencies or []
  m['dependencies'] = dependencies or []
  m['data'] = data or []
  m['data_dependencies'] = data_dependencies or []
  m['compatibility_suites'] = compatibility_suites or []
  m['host_dependencies'] = host_dependencies or []
  m['srcs'] = srcs or []
  return m


# pylint: disable=too-many-locals
def create_test_info(**kwargs):
  test_name = kwargs.pop('test_name')
  test_runner = kwargs.pop('test_runner')
  build_targets = kwargs.pop('build_targets')
  data = kwargs.pop('data', None)
  suite = kwargs.pop('suite', None)
  module_class = kwargs.pop('module_class', None)
  install_locations = kwargs.pop('install_locations', None)
  test_finder = kwargs.pop('test_finder', '')
  compatibility_suites = kwargs.pop('compatibility_suites', None)

  t_info = test_info.TestInfo(
      test_name=test_name,
      test_runner=test_runner,
      build_targets=build_targets,
      data=data,
      suite=suite,
      module_class=module_class,
      install_locations=install_locations,
      test_finder=test_finder,
      compatibility_suites=compatibility_suites,
  )
  raw_test_name = kwargs.pop('raw_test_name', None)
  if raw_test_name:
    t_info.raw_test_name = raw_test_name
  artifacts = kwargs.pop('artifacts', set())
  if artifacts:
    t_info.artifacts = artifacts
  robo_type = kwargs.pop('robo_type', None)
  if robo_type:
    t_info.robo_type = robo_type
  mainline_modules = kwargs.pop('mainline_modules', set())
  if mainline_modules:
    t_info._mainline_modules = mainline_modules
  for keyword in ['from_test_mapping', 'host', 'aggregate_metrics_result']:
    value = kwargs.pop(keyword, 'None')
    if isinstance(value, bool):
      setattr(t_info, keyword, value)
  if kwargs:
    assert f'Unknown keyword(s) for test_info: {kwargs.keys()}'
  return t_info


if __name__ == '__main__':
  unittest.main()
