text: # -*- coding: utf-8 -*-
  """
      tests.unit.version_test
      ~~~~~~~~~~~~~~~~~~~~~~~
  
      These tests are copied from python's source `Lib/distutils/tests/test_version.py`
      Some new examples were added and some adjustments were made to run tests in python 2 and 3
  """
  # pylint: disable=string-substitution-usage-error
  
  from __future__ import absolute_import, print_function, unicode_literals
  
  import datetime
  import os
  import sys
  import warnings
  
  import salt.modules.cmdmod
  import salt.utils.platform
  import salt.utils.versions
  import salt.version
  from salt.ext import six
  from salt.utils.versions import LooseVersion, StrictVersion
  from tests.support.helpers import slowTest
  from tests.support.mock import patch
  from tests.support.paths import CODE_DIR
  from tests.support.unit import TestCase, skipIf
  
  if six.PY2:
      cmp_method = "__cmp__"
  else:
      cmp_method = "_cmp"
  
  
  class VersionTestCase(TestCase):
      def test_prerelease(self):
          version = StrictVersion("1.2.3a1")
          self.assertEqual(version.version, (1, 2, 3))
          self.assertEqual(version.prerelease, ("a", 1))
          self.assertEqual(six.text_type(version), "1.2.3a1")
  
          version = StrictVersion("1.2.0")
          self.assertEqual(six.text_type(version), "1.2")
  
      def test_cmp_strict(self):
          versions = (
              ("1.5.1", "1.5.2b2", -1),
              ("161", "3.10a", ValueError),
              ("8.02", "8.02", 0),
              ("3.4j", "1996.07.12", ValueError),
              ("3.2.pl0", "3.1.1.6", ValueError),
              ("2g6", "11g", ValueError),
              ("0.9", "2.2", -1),
              ("1.2.1", "1.2", 1),
              ("1.1", "1.2.2", -1),
              ("1.2", "1.1", 1),
              ("1.2.1", "1.2.2", -1),
              ("1.2.2", "1.2", 1),
              ("1.2", "1.2.2", -1),
              ("0.4.0", "0.4", 0),
              ("1.13++", "5.5.kw", ValueError),
              # Added by us
              ("1.1.1a1", "1.1.1", -1),
          )
  
          for v1, v2, wanted in versions:
              try:
                  res = getattr(StrictVersion(v1), cmp_method)(StrictVersion(v2))
              except ValueError:
                  if wanted is ValueError:
                      continue
                  else:
                      raise AssertionError(
                          ("cmp(%s, %s) " "shouldn't raise ValueError") % (v1, v2)
                      )
              self.assertEqual(
                  res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)
              )
  
      def test_cmp(self):
          versions = (
              ("1.5.1", "1.5.2b2", -1),
              ("161", "3.10a", 1),
              ("8.02", "8.02", 0),
              ("3.4j", "1996.07.12", -1),
              ("3.2.pl0", "3.1.1.6", 1),
              ("2g6", "11g", -1),
              ("0.960923", "2.2beta29", -1),
              ("1.13++", "5.5.kw", -1),
              # Added by us
              ("3.10.0-514.el7", "3.10.0-514.6.1.el7", 1),
              ("2.2.2", "2.12.1", -1),
          )
  
          for v1, v2, wanted in versions:
              res = getattr(LooseVersion(v1), cmp_method)(LooseVersion(v2))
              self.assertEqual(
                  res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)
              )
  
      @skipIf(not salt.utils.platform.is_linux(), "only need to run on linux")
      @slowTest
      def test_spelling_version_name(self):
          """
          check the spelling of the version name for the release
          names in the salt.utils.versions.warn_until call
          """
          query = "salt.utils.versions.warn_until("
          names = salt.version.SaltStackVersion.NAMES
  
          cmd = "grep -lr {} -A 1 {}".format(query, os.path.join(CODE_DIR, "salt"))
  
          grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd).split(os.linesep)
  
          for line in grep_call:
              num_cmd = salt.modules.cmdmod.run_stdout(
                  "grep -c {0} {1}".format(query, line)
              )
              ver_cmd = salt.modules.cmdmod.run_stdout(
                  "grep {0} {1} -A 1".format(query, line)
              )
              if "pyc" in line:
                  break
  
              match = 0
              for key in names:
                  if key in ver_cmd:
                      match = match + (ver_cmd.count(key))
              if "utils/__init__.py" in line:
                  # work around for utils/__init__.py because
                  # it includes the warn_utils function
                  match = match + 1
              self.assertEqual(
                  match,
                  int(num_cmd),
                  msg="The file: {0} has an "
                  "incorrect spelling for the release name in the warn_utils "
                  "call: {1}. Expecting one of these release names: "
                  "{2}".format(line, ver_cmd, names),
              )
  
  
  class VersionFuncsTestCase(TestCase):
      def test_compare(self):
          ret = salt.utils.versions.compare("1.0", "==", "1.0")
          self.assertTrue(ret)
  
          ret = salt.utils.versions.compare("1.0", "!=", "1.0")
          self.assertFalse(ret)
  
          with patch.object(salt.utils.versions, "log") as log_mock:
              ret = salt.utils.versions.compare(
                  "1.0", "HAH I AM NOT A COMP OPERATOR! I AM YOUR FATHER!", "1.0"
              )
              self.assertTrue(log_mock.error.called)
  
      def test_kwargs_warn_until(self):
          # Test invalid version arg
          self.assertRaises(RuntimeError, salt.utils.versions.kwargs_warn_until, {}, [])
  
      def test_warn_until_warning_raised(self):
          # We *always* want *all* warnings thrown on this module
          warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  
          def raise_warning(_version_info_=(0, 16, 0)):
              salt.utils.versions.warn_until(
                  (0, 17), "Deprecation Message!", _version_info_=_version_info_
              )
  
          def raise_named_version_warning(_version_info_=(0, 16, 0)):
              salt.utils.versions.warn_until(
                  "Hydrogen", "Deprecation Message!", _version_info_=_version_info_
              )
  
          # raise_warning should show warning until version info is >= (0, 17)
          with warnings.catch_warnings(record=True) as recorded_warnings:
              raise_warning()
              self.assertEqual(
                  "Deprecation Message!", six.text_type(recorded_warnings[0].message)
              )
  
          # raise_warning should show warning until version info is >= (0, 17)
          with warnings.catch_warnings(record=True) as recorded_warnings:
              raise_named_version_warning()
              self.assertEqual(
                  "Deprecation Message!", six.text_type(recorded_warnings[0].message)
              )
  
          # the deprecation warning is not issued because we passed
          # _dont_call_warning
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.warn_until(
                  (0, 17), "Foo", _dont_call_warnings=True, _version_info_=(0, 16)
              )
              self.assertEqual(0, len(recorded_warnings))
  
          # Let's set version info to (0, 17), a RuntimeError should be raised
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"0.17.0 is released. Current version is now 0.17.0. "
              r"Please remove the warning.",
          ):
              raise_warning(_version_info_=(0, 17, 0))
  
          # Let's set version info to (0, 17), a RuntimeError should be raised
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"(.*) is released. Current version is now "
              r"([\d.]+). Please remove the warning.",
          ):
              raise_named_version_warning(
                  _version_info_=(
                      getattr(sys, "maxint", None) or getattr(sys, "maxsize"),
                      16,
                      0,
                  )
              )
  
          # Even though we're calling warn_until, we pass _dont_call_warnings
          # because we're only after the RuntimeError
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"0.17.0 is released. Current version is now "
              r"(.*). Please remove the warning.",
          ):
              salt.utils.versions.warn_until((0, 17), "Foo", _dont_call_warnings=True)
  
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"(.*) is released. Current version is now "
              r"(.*). Please remove the warning.",
          ):
              salt.utils.versions.warn_until(
                  "Hydrogen",
                  "Foo",
                  _dont_call_warnings=True,
                  _version_info_=(
                      getattr(sys, "maxint", None) or getattr(sys, "maxsize"),
                      16,
                      0,
                  ),
              )
  
          # version on the deprecation message gets properly formatted
          with warnings.catch_warnings(record=True) as recorded_warnings:
              vrs = salt.version.SaltStackVersion.from_name("Helium")
              salt.utils.versions.warn_until(
                  "Helium",
                  "Deprecation Message until {version}!",
                  _version_info_=(vrs.major - 1, 0),
              )
              self.assertEqual(
                  "Deprecation Message until {0}!".format(vrs.formatted_version),
                  six.text_type(recorded_warnings[0].message),
              )
  
      def test_kwargs_warn_until_warning_raised(self):
          # We *always* want *all* warnings thrown on this module
          warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  
          def raise_warning(**kwargs):
              _version_info_ = kwargs.pop("_version_info_", (0, 16, 0))
              salt.utils.versions.kwargs_warn_until(
                  kwargs, (0, 17), _version_info_=_version_info_
              )
  
          # raise_warning({...}) should show warning until version info is >= (0, 17)
          with warnings.catch_warnings(record=True) as recorded_warnings:
              raise_warning(foo=42)  # with a kwarg
              self.assertEqual(
                  "The following parameter(s) have been deprecated and "
                  "will be removed in '0.17.0': 'foo'.",
                  six.text_type(recorded_warnings[0].message),
              )
          # With no **kwargs, should not show warning until version info is >= (0, 17)
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.kwargs_warn_until(
                  {}, (0, 17), _version_info_=(0, 16, 0)  # no kwargs
              )
              self.assertEqual(0, len(recorded_warnings))
  
          # Let's set version info to (0, 17), a RuntimeError should be raised
          # regardless of whether or not we pass any **kwargs.
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"0.17.0 is released. Current version is now 0.17.0. "
              r"Please remove the warning.",
          ):
              raise_warning(_version_info_=(0, 17))  # no kwargs
  
          with self.assertRaisesRegex(
              RuntimeError,
              r"The warning triggered on filename \'(.*)test_versions.py\', "
              r"line number ([\d]+), is supposed to be shown until version "
              r"0.17.0 is released. Current version is now 0.17.0. "
              r"Please remove the warning.",
          ):
              raise_warning(bar="baz", qux="quux", _version_info_=(0, 17))  # some kwargs
  
      def test_warn_until_date_warning_raised(self):
          # We *always* want *all* warnings thrown on this module
          warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  
          _current_date = datetime.date(2000, 1, 1)
  
          # Test warning with datetime.date instance
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.warn_until_date(
                  datetime.date(2000, 1, 2),
                  "Deprecation Message!",
                  _current_date=_current_date,
              )
              self.assertEqual(
                  "Deprecation Message!", six.text_type(recorded_warnings[0].message)
              )
  
          # Test warning with datetime.datetime instance
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.warn_until_date(
                  datetime.datetime(2000, 1, 2),
                  "Deprecation Message!",
                  _current_date=_current_date,
              )
              self.assertEqual(
                  "Deprecation Message!", six.text_type(recorded_warnings[0].message)
              )
  
          # Test warning with date as a string
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.warn_until_date(
                  "20000102", "Deprecation Message!", _current_date=_current_date
              )
              self.assertEqual(
                  "Deprecation Message!", six.text_type(recorded_warnings[0].message)
              )
  
          # the deprecation warning is not issued because we passed
          # _dont_call_warning
          with warnings.catch_warnings(record=True) as recorded_warnings:
              salt.utils.versions.warn_until_date(
                  "20000102",
                  "Deprecation Message!",
                  _dont_call_warnings=True,
                  _current_date=_current_date,
              )
              self.assertEqual(0, len(recorded_warnings))
  
          # Let's test for RuntimeError raise
          with self.assertRaisesRegex(
              RuntimeError,
              r"Deprecation Message! This warning\(now exception\) triggered on "
              r"filename \'(.*)test_versions.py\', line number ([\d]+), is "
              r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
              r"Please remove the warning.",
          ):
              salt.utils.versions.warn_until_date("20000101", "Deprecation Message!")
  
          # Even though we're calling warn_until_date, we pass _dont_call_warnings
          # because we're only after the RuntimeError
          with self.assertRaisesRegex(
              RuntimeError,
              r"Deprecation Message! This warning\(now exception\) triggered on "
              r"filename \'(.*)test_versions.py\', line number ([\d]+), is "
              r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
              r"Please remove the warning.",
          ):
              salt.utils.versions.warn_until_date(
                  "20000101",
                  "Deprecation Message!",
                  _dont_call_warnings=True,
                  _current_date=_current_date,
              )
  
      def test_warn_until_date_bad_strptime_format(self):
          # We *always* want *all* warnings thrown on this module
          warnings.filterwarnings("always", "", DeprecationWarning, __name__)
  
          # Let's test for RuntimeError raise
          with self.assertRaisesRegex(
              ValueError, "time data '0022' does not match format '%Y%m%d'"
          ):
              salt.utils.versions.warn_until_date("0022", "Deprecation Message!")
  