#!/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 tf_integration_finder."""

import os
import unittest
from unittest import mock

from atest import constants
from atest import unittest_constants as uc
from atest import unittest_utils
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_finders import tf_integration_finder
from atest.test_runners import atest_tf_test_runner as atf_tr


INT_NAME_CLASS = uc.INT_NAME + ':' + uc.FULL_CLASS_NAME
INT_NAME_METHOD = INT_NAME_CLASS + '#' + uc.METHOD_NAME
GTF_INT_CONFIG = os.path.join(uc.GTF_INT_DIR, uc.GTF_INT_NAME + '.xml')
INT_CLASS_INFO = test_info.TestInfo(
    uc.INT_NAME,
    atf_tr.AtestTradefedTestRunner.NAME,
    set(),
    data={
        constants.TI_FILTER: frozenset([uc.CLASS_FILTER]),
        constants.TI_REL_CONFIG: uc.INT_CONFIG,
    },
)
INT_METHOD_INFO = test_info.TestInfo(
    uc.INT_NAME,
    atf_tr.AtestTradefedTestRunner.NAME,
    set(),
    data={
        constants.TI_FILTER: frozenset([uc.METHOD_FILTER]),
        constants.TI_REL_CONFIG: uc.INT_CONFIG,
    },
)


class TFIntegrationFinderUnittests(unittest.TestCase):
  """Unit tests for tf_integration_finder.py"""

  def setUp(self):
    """Set up for testing."""
    self.tf_finder = tf_integration_finder.TFIntegrationFinder()
    self.tf_finder.integration_dirs = [
        os.path.join(uc.ROOT, uc.INT_DIR),
        os.path.join(uc.ROOT, uc.GTF_INT_DIR),
    ]
    self.tf_finder.root_dir = uc.ROOT

  @mock.patch.object(
      tf_integration_finder.TFIntegrationFinder,
      '_get_build_targets',
      return_value=set(),
  )
  @mock.patch.object(
      test_filter_utils,
      'get_fully_qualified_class_name',
      return_value=uc.FULL_CLASS_NAME,
  )
  @mock.patch('subprocess.check_output')
  @mock.patch('os.path.exists', return_value=True)
  @mock.patch('os.path.isfile', return_value=False)
  @mock.patch('os.path.isdir', return_value=False)
  # pylint: disable=unused-argument
  def test_find_test_by_integration_name(
      self, _isdir, _isfile, _path, mock_find, _fcqn, _build
  ):
    """Test find_test_by_integration_name.

    Note that _isfile is always False since we don't index integration tests.
    """
    mock_find.return_value = os.path.join(
        uc.ROOT, uc.INT_DIR, uc.INT_NAME + '.xml'
    )
    t_infos = self.tf_finder.find_test_by_integration_name(uc.INT_NAME)
    self.assertEqual(len(t_infos), 0)
    _isdir.return_value = True
    t_infos = self.tf_finder.find_test_by_integration_name(uc.INT_NAME)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.INT_INFO)
    t_infos = self.tf_finder.find_test_by_integration_name(INT_NAME_CLASS)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], INT_CLASS_INFO)
    t_infos = self.tf_finder.find_test_by_integration_name(INT_NAME_METHOD)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], INT_METHOD_INFO)
    not_fully_qual = uc.INT_NAME + ':' + 'someClass'
    t_infos = self.tf_finder.find_test_by_integration_name(not_fully_qual)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], INT_CLASS_INFO)
    mock_find.return_value = os.path.join(
        uc.ROOT, uc.GTF_INT_DIR, uc.GTF_INT_NAME + '.xml'
    )
    t_infos = self.tf_finder.find_test_by_integration_name(uc.GTF_INT_NAME)
    unittest_utils.assert_equal_testinfos(self, t_infos[0], uc.GTF_INT_INFO)
    mock_find.return_value = ''
    self.assertEqual(
        self.tf_finder.find_test_by_integration_name('NotIntName'), []
    )

  @mock.patch.object(
      tf_integration_finder.TFIntegrationFinder,
      '_get_build_targets',
      return_value=set(),
  )
  @mock.patch(
      'os.path.realpath', side_effect=unittest_utils.realpath_side_effect
  )
  @mock.patch('os.path.isdir', return_value=True)
  @mock.patch('os.path.isfile', return_value=True)
  @mock.patch.object(test_finder_utils, 'find_parent_module_dir')
  @mock.patch('os.path.exists', return_value=True)
  def test_find_int_test_by_path(
      self, _exists, _find, _isfile, _isdir, _real, _build
  ):
    """Test find_int_test_by_path."""
    path = os.path.join(uc.INT_DIR, uc.INT_NAME + '.xml')
    t_infos = self.tf_finder.find_int_test_by_path(path)
    unittest_utils.assert_equal_testinfos(self, uc.INT_INFO, t_infos[0])
    path = os.path.join(uc.GTF_INT_DIR, uc.GTF_INT_NAME + '.xml')
    t_infos = self.tf_finder.find_int_test_by_path(path)
    unittest_utils.assert_equal_testinfos(self, uc.GTF_INT_INFO, t_infos[0])

  # pylint: disable=protected-access
  @mock.patch.object(
      tf_integration_finder.TFIntegrationFinder, '_search_integration_dirs'
  )
  def test_load_xml_file(self, search):
    """Test _load_xml_file and _load_include_tags methods."""
    search.return_value = [
        os.path.join(uc.TEST_DATA_DIR, 'CtsUiDeviceTestCases.xml.data')
    ]
    xml_file = os.path.join(uc.TEST_DATA_DIR, constants.MODULE_CONFIG + '.data')
    xml_root = self.tf_finder._load_xml_file(xml_file)
    include_tags = xml_root.findall('.//include')
    self.assertEqual(0, len(include_tags))
    option_tags = xml_root.findall('.//option')
    included = False
    for tag in option_tags:
      if tag.attrib['value'].strip() == 'CtsUiDeviceTestCases.apk':
        included = True
    self.assertTrue(included)

  @mock.patch.object(
      tf_integration_finder.TFIntegrationFinder, '_get_prebuilt_jars'
  )
  def test_search_prebuilt_jars(self, prebuilt_jars):
    """Test _search_prebuilt_jars method."""
    test_plan = 'performance/inodeop-benchmark'
    prebuilt_jars.return_value = [
        os.path.join(
            uc.TEST_DATA_DIR,
            'tradefed_prebuilt/prebuilts/filegroups/tradefed/tradefed-contrib.jar',
        )
    ]
    expect_path = [
        os.path.join(
            self.tf_finder.temp_dir.name,
            'tradefed-contrib.jar',
            'config',
            test_plan + '.xml',
        )
    ]
    self.assertEqual(
        self.tf_finder._search_prebuilt_jars(test_plan), expect_path
    )

  def test_get_prebuilt_jars(self):
    """Test _get_prebuilt_jars method."""
    tf_int_finder = tf_integration_finder.TFIntegrationFinder()
    tf_int_finder.tf_dirs = ['tradefed_prebuilt/prebuilts/test_harness']
    tf_int_finder.root_dir = uc.TEST_DATA_DIR
    expect_prebuilt_jars = [
        os.path.join(
            uc.TEST_DATA_DIR,
            'tradefed_prebuilt/prebuilts/test_harness/..',
            'filegroups/tradefed/tradefed-contrib.jar',
        )
    ]
    self.assertEqual(tf_int_finder._get_prebuilt_jars(), expect_prebuilt_jars)


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