# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import os
import unittest

import mock
import version


def _ReplaceArgs(args, *replacements):
  new_args = args[:]
  for flag, val in replacements:
    flag_index = args.index(flag)
    new_args[flag_index + 1] = val
  return new_args


class _VersionTest(unittest.TestCase):
  """Unittests for the version module.
  """

  _CHROME_VERSION_FILE = os.path.join(
      os.path.dirname(__file__), os.pardir, os.pardir, 'chrome', 'VERSION')

  _SCRIPT = os.path.join(os.path.dirname(__file__), 'version.py')

  _EXAMPLE_VERSION = {
      'MAJOR': '74',
      'MINOR': '0',
      'BUILD': '3720',
      'PATCH': '0',
  }

  _EXAMPLE_TEMPLATE = (
      'full = "@MAJOR@.@MINOR@.@BUILD@.@PATCH@" '
      'major = "@MAJOR@" minor = "@MINOR@" '
      'build = "@BUILD@" patch = "@PATCH@" version_id = @VERSION_ID@ ')

  _ANDROID_CHROME_VARS = [
      'chrome_version_code',
      'chrome_modern_version_code',
      'monochrome_version_code',
      'trichrome_version_code',
      'webview_stable_version_code',
      'webview_beta_version_code',
      'webview_dev_version_code',
  ]

  _EXAMPLE_ANDROID_TEMPLATE = (
      _EXAMPLE_TEMPLATE + ''.join(
          ['%s = "@%s@" ' % (el, el.upper()) for el in _ANDROID_CHROME_VARS]))

  _EXAMPLE_ARGS = [
      '-f',
      _CHROME_VERSION_FILE,
      '-t',
      _EXAMPLE_TEMPLATE,
  ]

  _EXAMPLE_ANDROID_ARGS = _ReplaceArgs(_EXAMPLE_ARGS,
                                       ['-t', _EXAMPLE_ANDROID_TEMPLATE]) + [
                                           '-a',
                                           'arm',
                                           '--os',
                                           'android',
                                       ]

  @staticmethod
  def _RunBuildOutput(new_version_values={},
                      get_new_args=lambda old_args: old_args):
    """Parameterized helper method for running the main testable method in
    version.py.

    Keyword arguments:
    new_version_values -- dict used to update _EXAMPLE_VERSION
    get_new_args -- lambda for updating _EXAMPLE_ANDROID_ARGS
    """

    with mock.patch('version.FetchValuesFromFile') as \
        fetch_values_from_file_mock:

      fetch_values_from_file_mock.side_effect = (lambda values, file :
          values.update(
              dict(_VersionTest._EXAMPLE_VERSION, **new_version_values)))

      new_args = get_new_args(_VersionTest._EXAMPLE_ARGS)
      return version.BuildOutput(new_args)

  def testFetchValuesFromFile(self):
    """It returns a dict in correct format - { <str>: <str> }, to verify
    assumption of other tests that mock this function
    """
    result = {}
    version.FetchValuesFromFile(result, self._CHROME_VERSION_FILE)

    for key, val in result.items():
      self.assertIsInstance(key, str)
      self.assertIsInstance(val, str)

  def testBuildOutputAndroid(self):
    """Assert it gives includes assignments of expected variables"""
    output = self._RunBuildOutput(
        get_new_args=lambda args: self._EXAMPLE_ANDROID_ARGS)
    contents = output['contents']

    self.assertRegexpMatches(contents, r'\bchrome_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\bchrome_modern_version_code = "\d+"\s')
    self.assertRegexpMatches(contents, r'\bmonochrome_version_code = "\d+"\s')
    self.assertRegexpMatches(contents, r'\btrichrome_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\bwebview_stable_version_code = "\d+"\s')
    self.assertRegexpMatches(contents, r'\bwebview_beta_version_code = "\d+"\s')
    self.assertRegexpMatches(contents, r'\bwebview_dev_version_code = "\d+"\s')

  def testBuildOutputAndroidArchVariantsArm64(self):
    """Assert 64-bit-specific version codes"""
    new_template = (
        self._EXAMPLE_ANDROID_TEMPLATE +
        "monochrome_64_32_version_code = \"@MONOCHROME_64_32_VERSION_CODE@\" "
        "monochrome_64_version_code = \"@MONOCHROME_64_VERSION_CODE@\" "
        "trichrome_64_32_version_code = \"@TRICHROME_64_32_VERSION_CODE@\" "
        "trichrome_64_version_code = \"@TRICHROME_64_VERSION_CODE@\" ")
    args_with_template = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS,
                                      ['-t', new_template])
    new_args = _ReplaceArgs(args_with_template, ['-a', 'arm64'])
    output = self._RunBuildOutput(get_new_args=lambda args: new_args)
    contents = output['contents']

    self.assertRegexpMatches(contents,
                             r'\bmonochrome_64_32_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\bmonochrome_64_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\btrichrome_64_32_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\btrichrome_64_version_code = "\d+"\s')

  def testBuildOutputAndroidArchVariantsX64(self):
    """Assert 64-bit-specific version codes"""
    new_template = (
        self._EXAMPLE_ANDROID_TEMPLATE +
        "monochrome_64_32_version_code = \"@MONOCHROME_64_32_VERSION_CODE@\" "
        "monochrome_64_version_code = \"@MONOCHROME_64_VERSION_CODE@\" "
        "trichrome_64_32_version_code = \"@TRICHROME_64_32_VERSION_CODE@\" "
        "trichrome_64_version_code = \"@TRICHROME_64_VERSION_CODE@\" ")
    args_with_template = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS,
                                      ['-t', new_template])
    new_args = _ReplaceArgs(args_with_template, ['-a', 'x64'])
    output = self._RunBuildOutput(get_new_args=lambda args: new_args)
    contents = output['contents']

    self.assertRegexpMatches(contents,
                             r'\bmonochrome_64_32_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\bmonochrome_64_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\btrichrome_64_32_version_code = "\d+"\s')
    self.assertRegexpMatches(contents,
                             r'\btrichrome_64_version_code = "\d+"\s')

  def testBuildOutputAndroidChromeArchInput(self):
    """Assert it raises an exception when using an invalid architecture input"""
    new_args = _ReplaceArgs(self._EXAMPLE_ANDROID_ARGS, ['-a', 'foobar'])
    with self.assertRaises(SystemExit) as cm:
      self._RunBuildOutput(get_new_args=lambda args: new_args)

    self.assertEqual(cm.exception.code, 2)


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