From 4a8c154a533cb26e78fcde73c4dc28dadd2df66b Mon Sep 17 00:00:00 2001 From: Layla Manley Date: Sun, 2 Jul 2023 18:29:32 -0400 Subject: [PATCH] Implement unittests --- .gitignore | 1 - semver/scm/__init__.py | 24 ++-- semver/scm/git.py | 18 ++- semver/scm/mock.py | 20 +++ semver/scm/tests/__init__.py | 0 semver/scm/tests/test_git.py | 100 ++++++++++++++ semver/scm/tests/test_mock.py | 34 +++++ semver/scm/tests/test_scm.py | 72 ++++++++++ semver/semver.py | 5 +- semver/tests.py | 246 ---------------------------------- semver/tests/__init__.py | 0 semver/tests/test_semver.py | 144 ++++++++++++++++++++ 12 files changed, 393 insertions(+), 271 deletions(-) create mode 100644 semver/scm/mock.py create mode 100644 semver/scm/tests/__init__.py create mode 100644 semver/scm/tests/test_git.py create mode 100644 semver/scm/tests/test_mock.py create mode 100644 semver/scm/tests/test_scm.py delete mode 100644 semver/tests.py create mode 100644 semver/tests/__init__.py create mode 100644 semver/tests/test_semver.py diff --git a/.gitignore b/.gitignore index ab3efa6..2b98876 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ dist/ *.zip env # Byte-compiled / optimized / DLL files -tests/ __pycache__/ *.py[cod] *$py.class diff --git a/semver/scm/__init__.py b/semver/scm/__init__.py index be19322..7d01403 100644 --- a/semver/scm/__init__.py +++ b/semver/scm/__init__.py @@ -8,42 +8,34 @@ from semver.logger import logger class SCM(ABC): @abstractmethod def get_tag_version(self) -> str: - raise NotImplementedError + raise NotImplementedError() @abstractmethod def get_branch(self) -> str: - raise NotImplementedError + raise NotImplementedError() @abstractmethod def get_merge_branch(self) -> Union[str, None]: - raise NotImplementedError + raise NotImplementedError() @abstractmethod def commit_and_push(self, branch: str) -> None: - raise NotImplementedError + raise NotImplementedError() @abstractmethod def tag_version(self, version: str) -> None: - raise NotImplementedError + raise NotImplementedError() def get_file_version(self, config: dict) -> str: """ :param config: The bumpversion config as a dict :return: The current version from the config file """ - bumpversion: Union[str, None] = config.get("bumpversion", None) - version: Union[str, None] = ( - bumpversion.get("current_version", None) if bumpversion else None + bump_version: Union[str, None] = config.get("bumpversion", None) + version: str = ( + bump_version.get("current_version", "0.0.0") if bump_version else "0.0.0" ) - if not bumpversion: - config["bumpversion"] = {} - version = "0.0.0" - - if not version: - config["bumpversion"]["current_version"] = "0.0.0" - version = "0.0.0" - return version def get_version_type( diff --git a/semver/scm/git.py b/semver/scm/git.py index bd6d26e..4cee797 100644 --- a/semver/scm/git.py +++ b/semver/scm/git.py @@ -26,12 +26,14 @@ class Git(SCM): super().__init__() - def _run_command(self, *args: str) -> subprocess.CompletedProcess[str]: + def _run_command( + self, *args: str, throwExceptions: bool = True + ) -> subprocess.CompletedProcess[str]: return subprocess.run( args, capture_output=True, text=True, - check=True, + check=throwExceptions, ) def _setup_git_user(self) -> None: @@ -75,7 +77,7 @@ class Git(SCM): ) tagged_versions = proc.stdout.rstrip().split("\n") except subprocess.CalledProcessError as e: - raise RuntimeError( + raise SemverException( f"Error getting latest tagged git version: {str(e.stderr).rstrip()}" ) @@ -122,16 +124,20 @@ class Git(SCM): Commit and push the versioning changes :param branch: The branch to push """ - proc = self._run_command(self.git_bin, "push", "origin", branch) + proc = self._run_command( + self.git_bin, "push", "origin", branch, throwExceptions=False + ) if proc.returncode != 0: raise SemverException( f"Error pushing versioning changes to {branch}: {proc.stderr}" ) - proc = self._run_command(self.git_bin, "push", "origin", "--tags") + proc = self._run_command( + self.git_bin, "push", "origin", "--tags", throwExceptions=False + ) if proc.returncode != 0: raise SemverException( f"Error pushing versioning changes to {branch}: {proc.stderr}" ) def tag_version(self, version: str) -> None: - self._run_command(self.git_bin, "tag", version) \ No newline at end of file + self._run_command(self.git_bin, "tag", version) diff --git a/semver/scm/mock.py b/semver/scm/mock.py new file mode 100644 index 0000000..ec26713 --- /dev/null +++ b/semver/scm/mock.py @@ -0,0 +1,20 @@ +from typing import Union + +from semver.scm import SCM + + +class MockSCM(SCM): + def get_tag_version(self) -> str: + return "1.0.0" + + def get_branch(self) -> str: + return "main" + + def get_merge_branch(self) -> Union[str, None]: + return "main" + + def commit_and_push(self, branch: str) -> None: + pass + + def tag_version(self, version: str) -> None: + pass diff --git a/semver/scm/tests/__init__.py b/semver/scm/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/semver/scm/tests/test_git.py b/semver/scm/tests/test_git.py new file mode 100644 index 0000000..2547358 --- /dev/null +++ b/semver/scm/tests/test_git.py @@ -0,0 +1,100 @@ +import unittest +from unittest import mock +import subprocess + +from semver.version_type import VersionType +from semver.exceptions import SemverException +from semver.scm import SCM +from semver.scm.git import Git + + +class TestMockSCM(unittest.TestCase): + @mock.patch("subprocess.run") + def setUp(self, mock_subprocess_run: mock.Mock): + # Mock the subprocess.run function to avoid + # running actual git commands + mock_subprocess_run.return_value.returncode = 0 + mock_subprocess_run.return_value.stdout = "" + + self.scm = Git() + + def test_run_command(self): + proc: subprocess.CompletedProcess[str] = self.scm._run_command("echo", "hello") + self.assertEqual(proc.stdout, "hello\n") + + @mock.patch("toml.load") + @mock.patch("subprocess.run") + def test_get_tag_version( + self, mock_subprocess_run: mock.Mock, mock_toml_load: mock.Mock + ): + mock_toml_load.return_value = {"bumpversion": {"tag_name": "v{new_version}"}} + mock_subprocess_run.return_value.stdout = "v1.0.0\n" + + expected_version = "v1.0.0" + version = self.scm.get_tag_version() + self.assertEqual(version, expected_version) + + @mock.patch("toml.load") + @mock.patch("subprocess.run") + def test_get_tag_version_git_fail( + self, mock_subprocess_run: mock.Mock, mock_toml_load: mock.Mock + ): + mock_toml_load.return_value = {"bumpversion": {"tag_name": "v{new_version}"}} + mock_subprocess_run.return_value.returncode = 1 + mock_subprocess_run.side_effect = subprocess.CalledProcessError( + 1, "git", "git error" + ) + + with self.assertRaises(SemverException): + self.scm.get_tag_version() + + @mock.patch("subprocess.run") + def test_get_branch(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.return_value.stdout = "main\n" + + expected_branch = "main" + branch = self.scm.get_branch() + self.assertEqual(branch, expected_branch) + + @mock.patch("subprocess.run") + def test_get_merge_branch(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.return_value.stdout = ( + "Merge pull request #1 from RightBrain-Networks/feature/example\n" + ) + + expected_merge_branch = "feature/example" + merge_branch = self.scm.get_merge_branch() + self.assertEqual(merge_branch, expected_merge_branch) + + @mock.patch("subprocess.run") + def test_commit_and_push(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.return_value.returncode = 0 + + branch = "main" + self.scm.commit_and_push(branch) + + @mock.patch("subprocess.run") + def test_commit_and_push_git_fail(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.return_value.returncode = 1 + + branch = "main" + with self.assertRaises(SemverException): + self.scm.commit_and_push(branch) + + @mock.patch("subprocess.run") + def test_commit_and_push_git_fail_tags(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.side_effect = [ + mock.Mock(returncode=0), + mock.Mock(returncode=1), + ] + + branch = "main" + with self.assertRaises(SemverException): + self.scm.commit_and_push(branch) + + @mock.patch("subprocess.run") + def test_tag_version(self, mock_subprocess_run: mock.Mock): + mock_subprocess_run.return_value.returncode = 0 + + version = "1.0.0" + self.scm.tag_version(version) diff --git a/semver/scm/tests/test_mock.py b/semver/scm/tests/test_mock.py new file mode 100644 index 0000000..a934be0 --- /dev/null +++ b/semver/scm/tests/test_mock.py @@ -0,0 +1,34 @@ +import unittest + + +from semver.version_type import VersionType +from semver.scm import SCM +from semver.scm.mock import MockSCM + + +class TestMockSCM(unittest.TestCase): + def setUp(self): + self.scm: SCM = MockSCM() + + def test_get_tag_version(self): + expected_version = "1.0.0" + version = self.scm.get_tag_version() + self.assertEqual(version, expected_version) + + def test_get_branch(self): + expected_branch = "main" + branch = self.scm.get_branch() + self.assertEqual(branch, expected_branch) + + def test_get_merge_branch(self): + expected_merge_branch = "main" + merge_branch = self.scm.get_merge_branch() + self.assertEqual(merge_branch, expected_merge_branch) + + def test_commit_and_push(self): + branch = "main" + self.scm.commit_and_push(branch) + + def test_tag_version(self): + version = "1.0.0" + self.scm.tag_version(version) diff --git a/semver/scm/tests/test_scm.py b/semver/scm/tests/test_scm.py new file mode 100644 index 0000000..3743fb9 --- /dev/null +++ b/semver/scm/tests/test_scm.py @@ -0,0 +1,72 @@ +import unittest + +from semver.version_type import VersionType +from semver.scm import SCM +from semver.scm.mock import MockSCM + + +class TestSCM(unittest.TestCase): + def setUp(self): + self.scm: SCM = MockSCM() + + def test_get_file_version_existing_config(self): + config = {"bumpversion": {"current_version": "1.2.3"}} + expected_version = "1.2.3" + version = self.scm.get_file_version(config) + self.assertEqual(version, expected_version) + + def test_get_file_version_no_config(self): + config = {} + expected_version = "0.0.0" + version = self.scm.get_file_version(config) + self.assertEqual(version, expected_version) + + def test_get_file_version_no_version(self): + config = {"bumpversion": {}} + expected_version = "0.0.0" + version = self.scm.get_file_version(config) + self.assertEqual(version, expected_version) + + def test_get_version_type_major(self): + merged_branch = "main" + major_branches = ["main"] + minor_branches = ["develop"] + patch_branches = ["hotfix"] + expected_version_type = VersionType.MAJOR + version_type = self.scm.get_version_type( + merged_branch, major_branches, minor_branches, patch_branches + ) + self.assertEqual(version_type, expected_version_type) + + def test_get_version_type_minor(self): + merged_branch = "develop" + major_branches = ["main"] + minor_branches = ["develop"] + patch_branches = ["hotfix"] + expected_version_type = VersionType.MINOR + version_type = self.scm.get_version_type( + merged_branch, major_branches, minor_branches, patch_branches + ) + self.assertEqual(version_type, expected_version_type) + + def test_get_version_type_patch(self): + merged_branch = "hotfix" + major_branches = ["main"] + minor_branches = ["develop"] + patch_branches = ["hotfix"] + expected_version_type = VersionType.PATCH + version_type = self.scm.get_version_type( + merged_branch, major_branches, minor_branches, patch_branches + ) + self.assertEqual(version_type, expected_version_type) + + def test_get_version_type_none(self): + merged_branch = "feature" + major_branches = ["main"] + minor_branches = ["develop"] + patch_branches = ["hotfix"] + expected_version_type = None + version_type = self.scm.get_version_type( + merged_branch, major_branches, minor_branches, patch_branches + ) + self.assertEqual(version_type, expected_version_type) diff --git a/semver/semver.py b/semver/semver.py index 657fd55..2dade33 100644 --- a/semver/semver.py +++ b/semver/semver.py @@ -44,16 +44,17 @@ class SemVer: self._scm: SCM = scm - def _version_repo(self) -> None: + def _version_repo(self) -> str: """ Use bump_version to update the repo version + :return: The new version """ version = self._scm.get_tag_version() if not self._version_type: raise NoMergeFoundException() logger.debug(f"Running bumpversion of type: {self._version_type.name}") - self._bump_version(version, self._version_type) + return self._bump_version(version, self._version_type) def _process_config_string(self, cfg_string, new_version, version): return cfg_string.replace("{new_version}", new_version).replace( diff --git a/semver/tests.py b/semver/tests.py deleted file mode 100644 index 63025fa..0000000 --- a/semver/tests.py +++ /dev/null @@ -1,246 +0,0 @@ -import unittest, os, subprocess, re, semver -from semver.logger import logging, logger, console_logger - -from semver import bump, get_version, utils, NO_MERGE_FOUND, GET_COMMIT_MESSAGE - -config_data = """ -[bumpversion] -current_version = 0.0.0 -commit = False -tag = True -tag_name = {new_version} - -[bumpversion:file:file.txt] -search = 0.0.0 -replace = {new_version} - -[semver] -main_branches = master -major_branches = major -minor_branches = minor -patch_branches = patch -""" - -test_directory = "test" - - -class TestSemverObject(unittest.TestCase): - def test_get_version_type_major_merge(self): - semver_object = semver.SemVer() - semver_object.merged_branch = "major/unittest" - semver_object.get_version_type() - self.assertEqual(semver_object.version_type, semver.VersionType.MAJOR) - def test_get_version_type_minor_merge(self): - semver_object = semver.SemVer() - semver_object.merged_branch = "minor/unittest" - semver_object.get_version_type() - self.assertEqual(semver_object.version_type, semver.VersionType.MINOR) - def test_get_version_type_patch_merge(self): - semver_object = semver.SemVer() - semver_object.merged_branch = "patch/unittest" - semver_object.get_version_type() - self.assertEqual(semver_object.version_type, semver.VersionType.PATCH) - def test_run_no_merge(self): - semver_object = semver.SemVer() - try: - result = semver_object.run(False) - except Exception as e: - if e == NO_MERGE_FOUND: - self.assertTrue(True) - else: - self.assertTrue(False) - -class TestGetVersion(unittest.TestCase): - def test_get_branch_version(self): - create_git_environment() - branch = get_version.get_version() - self.assertEqual(branch, "master") - def test_branch_dotting(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'test/branch']) - branch = get_version.get_version(dot=True) - self.assertEqual(branch, "test.branch") - def test_branch_dotting_false(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'test/branch']) - branch = get_version.get_version(dot=False) - self.assertEqual(branch, "test/branch") - def test_branch_npm_pre_release(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'patch/branch']) - branch = get_version.get_version(version_format='npm') - self.assertEqual(branch, "0.0.1-patch-branch.0") - def test_branch_docker_pre_release(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'patch/branch']) - branch = get_version.get_version(build=2,version_format='docker') - self.assertEqual(branch, "0.0.1-patch-branch.2") - def test_branch_maven_pre_release(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'minor/branch']) - branch = get_version.get_version(version_format='maven') - self.assertEqual(branch, "0.1.0-minor-branch-SNAPSHOT") - def test_branch_maven_bad_branch(self): - create_git_environment() - subprocess.call(['git', 'checkout', '-b', 'test/branch']) - branch = get_version.get_version(version_format='maven') - self.assertEqual(branch, "test/branch") - def test_get_version_run(self): - create_git_environment() - val = subprocess.Popen(['python', '../get_version.py', '-d'], stdout=subprocess.PIPE, - stderr=open(os.devnull, 'wb'), cwd='.').stdout.read().decode('utf-8').rstrip() - self.assertEqual(val, "master") - - -class TestGetTagVersion(unittest.TestCase): - def test_get_version_tag(self): - create_git_environment() - subprocess.call(['git', 'tag', '1.0.0']) - tag = utils.get_tag_version() - self.assertEqual(tag, "1.0.0") - def test_get_version_multiple(self): - create_git_environment() - subprocess.call(['git', 'tag', '0.1.0']) - subprocess.call(['git', 'tag', '0.1.1']) - subprocess.call(['git', 'tag', '0.1.2']) - subprocess.call(['git', 'tag', '0.1.3']) - subprocess.call(['git', 'tag', '0.2.0']) - subprocess.call(['git', 'tag', '0.3.0']) - subprocess.call(['git', 'tag', '0.3.1']) - subprocess.call(['git', 'tag', '1.0.0']) - subprocess.call(['git', 'tag', '1.1.0']) - subprocess.call(['git', 'tag', '1.2.0']) - subprocess.call(['git', 'tag', '1.2.1']) - tag = utils.get_tag_version() - self.assertEqual(tag, "1.2.1") - def test_get_version_out_of_order(self): - subprocess.call(['git', 'tag', '0.1.0']) - subprocess.call(['git', 'tag', '0.1.1']) - subprocess.call(['git', 'tag', '0.5.2']) - subprocess.call(['git', 'tag', '0.1.3']) - subprocess.call(['git', 'tag', '8.1.0']) - subprocess.call(['git', 'tag', '0.3.8']) - subprocess.call(['git', 'tag', '3.3.1']) - subprocess.call(['git', 'tag', '1.4.0']) - subprocess.call(['git', 'tag', '1.1.7']) - subprocess.call(['git', 'tag', '1.2.0']) - subprocess.call(['git', 'tag', '0.2.1']) - tag = utils.get_tag_version() - self.assertEqual(tag, "8.1.0") - def test_default_get_version_tag(self): - create_git_environment() - tag = utils.get_tag_version() - self.assertEqual(tag, "0.0.0") - -class TestGetCommitMessageRegex(unittest.TestCase): - def test_github_message(self): - matches = GET_COMMIT_MESSAGE.search("Merge pull request #1 from user/branch") - if matches: - self.assertEqual(matches.group(4), None) - self.assertEqual(matches.group(5), "branch") - else: - self.assertTrue(False) - pass - def test_gitlab_message(self): - matches = GET_COMMIT_MESSAGE.search("Merge branch 'branch' into 'master'") - if matches: - self.assertEqual(matches.group(4), "master") - self.assertEqual(matches.group(2), "branch") - else: - self.assertTrue(False) - def test_branch_in_message(self): - matches = GET_COMMIT_MESSAGE.search(str(b'commit examplehash\nMerge: example\nAuthor: Test \nDate: Mon Jun 15 18:15:22 2020 -0400\n\n Merge pull request #45 from user/branch\n \n user/branch\n')) - if matches: - self.assertEqual(matches.group(4), None) - self.assertEqual(matches.group(5), "branch") - else: - self.assertTrue(False) - def test_non_merge_message(self): - matches = GET_COMMIT_MESSAGE.search("Example unrelated commit message that should get 0 matches") - self.assertEqual(matches, None) - def test_gitlab_merge_with_double_quotes(self): - matches = GET_COMMIT_MESSAGE.search("Merge branch 'branch' into 'master'\n\n\"Message in quotes!\"") - if matches: - self.assertEqual(matches.group(4), "master") - self.assertEqual(matches.group(2), "branch") - else: - self.assertTrue(False) - -class TestVersionBumping(unittest.TestCase): - def test_patch_bump(self): - self.assertEqual("0.0.1", bump.bump_version("0.0.0", semver.VersionType.PATCH, False)) - self.assertEqual("0.0.2", bump.bump_version("0.0.1", semver.VersionType.PATCH, False)) - self.assertEqual("0.1.1", bump.bump_version("0.1.0", semver.VersionType.PATCH, False)) - self.assertEqual("1.0.1", bump.bump_version("1.0.0", semver.VersionType.PATCH, False)) - self.assertEqual("1.2.4", bump.bump_version("1.2.3", semver.VersionType.PATCH, False)) - self.assertEqual("0.0.11", bump.bump_version("0.0.10", semver.VersionType.PATCH, False)) - self.assertEqual("0.10.1", bump.bump_version("0.10.0", semver.VersionType.PATCH, False)) - self.assertEqual("10.0.1", bump.bump_version("10.0.0", semver.VersionType.PATCH, False)) - def test_minor_bump(self): - self.assertEqual("0.1.0", bump.bump_version("0.0.0", semver.VersionType.MINOR, False)) - self.assertEqual("0.1.0", bump.bump_version("0.0.1", semver.VersionType.MINOR, False)) - self.assertEqual("0.2.0", bump.bump_version("0.1.0", semver.VersionType.MINOR, False)) - self.assertEqual("1.1.0", bump.bump_version("1.0.0", semver.VersionType.MINOR, False)) - self.assertEqual("1.3.0", bump.bump_version("1.2.3", semver.VersionType.MINOR, False)) - self.assertEqual("0.1.0", bump.bump_version("0.0.10", semver.VersionType.MINOR, False)) - self.assertEqual("0.11.0", bump.bump_version("0.10.0", semver.VersionType.MINOR, False)) - self.assertEqual("10.1.0", bump.bump_version("10.0.0", semver.VersionType.MINOR, False)) - def test_major_bump(self): - self.assertEqual("1.0.0", bump.bump_version("0.0.0", semver.VersionType.MAJOR, False)) - self.assertEqual("1.0.0", bump.bump_version("0.0.1", semver.VersionType.MAJOR, False)) - self.assertEqual("1.0.0", bump.bump_version("0.1.0", semver.VersionType.MAJOR, False)) - self.assertEqual("2.0.0", bump.bump_version("1.0.0", semver.VersionType.MAJOR, False)) - self.assertEqual("2.0.0", bump.bump_version("1.2.3", semver.VersionType.MAJOR, False)) - self.assertEqual("1.0.0", bump.bump_version("0.0.10", semver.VersionType.MAJOR, False)) - self.assertEqual("1.0.0", bump.bump_version("0.10.0", semver.VersionType.MAJOR, False)) - self.assertEqual("11.0.0", bump.bump_version("10.0.0", semver.VersionType.MAJOR, False)) -class TestFileVersioning(unittest.TestCase): - def test_file_bump(self): - with open('file.txt', 'w') as f: - f.write("0.0.0") - bump.update_file_version("12.34.56") - - file_data = "" - with open('file.txt', 'r') as f: - file_data = f.read() - - self.assertEqual("12.34.56", file_data) - def test_file_bump_with_text(self): - with open('file.txt', 'w') as f: - f.write("version = 0.0.0") - bump.update_file_version("12.34.56") - - file_data = "" - with open('file.txt', 'r') as f: - file_data = f.read() - - self.assertEqual("version = 12.34.56", file_data) - def test_file_bump_with_multiline(self): - with open('file.txt', 'w') as f: - f.write("version = 0.0.0\n#An example second line\nThird line!") - bump.update_file_version("12.34.56") - - file_data = "" - with open('file.txt', 'r') as f: - file_data = f.read() - - self.assertEqual("version = 12.34.56", file_data.split('\n')[0]) - -def create_git_environment(): - subprocess.call(['rm', '-rf', './.git']) - subprocess.call(['git', 'init']) - subprocess.call(['touch', 'file.txt']) - subprocess.call(['git', 'add', 'file.txt']) - subprocess.call(['git', 'commit', '-m', 'file.txt']) - subprocess.call(['git', 'remote', 'add', 'origin', os.getcwd()+'/.git']) - -if __name__ == "__main__": - console_logger.setLevel(logging.DEBUG) - - subprocess.call(['rm', '-rf', test_directory]) - subprocess.call(['mkdir', test_directory]) - os.chdir(test_directory) - with open('.bumpversion.cfg', "w") as config: - config.write(config_data) - unittest.main() - os.chdir("..") \ No newline at end of file diff --git a/semver/tests/__init__.py b/semver/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/semver/tests/test_semver.py b/semver/tests/test_semver.py new file mode 100644 index 0000000..5b857ab --- /dev/null +++ b/semver/tests/test_semver.py @@ -0,0 +1,144 @@ +import unittest +from unittest import mock + +from semver.version_type import VersionType +from semver.scm import SCM +from semver.scm.mock import MockSCM +from semver.semver import SemVer +from semver.exceptions import ( + NoMergeFoundException, + NoGitFlowException, + NotMainBranchException, +) + + +class TestSCM(unittest.TestCase): + def setUp(self): + scm = mock.MagicMock(MockSCM()) + self.semver: SemVer = SemVer(scm=scm) + + @mock.patch("semver.semver.SemVer._bump_version") + def test_version_repo(self, mock_bump_version: mock.Mock): + self.semver._scm.get_tag_version.return_value = "1.0.0" + self.semver._version_type = VersionType.PATCH + + expected_version = "1.0.1" + mock_bump_version.return_value = expected_version + version = self.semver._version_repo() + self.assertEqual(version, expected_version) + + @mock.patch("semver.semver.SemVer._bump_version") + def test_version_repo_no_tag(self, mock_bump_version: mock.Mock): + self.semver._scm.get_tag_version.return_value = "1.0.0" + self.semver._version_type = None + + with self.assertRaises(NoMergeFoundException): + self.semver._version_repo() + + def test_process_config_string(self): + expected_version = "v1.0.0" + version = self.semver._process_config_string("v{new_version}", "1.0.0", "1.0.1") + self.assertEqual(version, expected_version) + + expected_version = "v1.0.1" + version = self.semver._process_config_string( + "v{current_version}", "1.0.0", "1.0.1" + ) + self.assertEqual(version, expected_version) + + @mock.patch("semver.semver.SemVer._update_file_version") + def test_bump_version_major(self, mock_update_file_version: mock.Mock): + expected_version = "2.0.0" + version = self.semver._bump_version("1.0.0", VersionType.MAJOR) + self.assertEqual(version, expected_version) + + @mock.patch("semver.semver.SemVer._update_file_version") + def test_bump_version_minor(self, mock_update_file_version: mock.Mock): + expected_version = "1.1.0" + version = self.semver._bump_version("1.0.0", VersionType.MINOR) + self.assertEqual(version, expected_version) + + @mock.patch("semver.semver.SemVer._update_file_version") + def test_bump_version_patch(self, mock_update_file_version: mock.Mock): + expected_version = "1.0.1" + version = self.semver._bump_version("1.0.0", VersionType.PATCH) + self.assertEqual(version, expected_version) + + @mock.patch("toml.load") + @mock.patch("pathlib.Path.is_file") + @mock.patch("builtins.open", mock.mock_open()) + @mock.patch("semver.logger.warning") + def test_update_file_version( + self, + mock_logger: mock.Mock, + mock_path_is_file: mock.Mock, + mock_toml_load: mock.Mock, + ): + mock_toml_load.return_value = { + "bumpversion": {"current_version": "1.0.0"}, + "bumpversion:file:VERSION": { + "search": "0.0.0", + "replace": "{new_version}", + }, + } + mock_path_is_file.return_value = True + self.semver._update_file_version("1.0.1", "1.0.0") + mock_logger.assert_not_called() + + mock_path_is_file.return_value = False + self.semver._update_file_version("1.0.1", "1.0.0") + mock_logger.assert_called_once() + + @mock.patch("semver.semver.SemVer._version_repo", mock.MagicMock()) + def test_run_ok(self): + self.semver._version_repo = mock.MagicMock() + self.semver._version_repo.return_value = "1.0.1" + self.semver._scm.get_branch.return_value = "main" + self.semver._scm.get_merge_branch.return_value = "main" + self.semver._scm.get_version_type.return_value = VersionType.MINOR + self.semver._scm.commit_and_push.return_value = None + + self.semver._main_branches = ["main"] + self.semver.run() + + @mock.patch("semver.semver.SemVer._version_repo", mock.MagicMock()) + def test_run_not_merge(self): + self.semver._version_repo = mock.MagicMock() + self.semver._version_repo.return_value = "1.0.1" + self.semver._scm.get_branch.return_value = "main" + self.semver._scm.get_merge_branch.return_value = None + self.semver._scm.get_version_type.return_value = VersionType.MINOR + self.semver._scm.commit_and_push.return_value = None + + self.semver._main_branches = ["main"] + + with self.assertRaises(NoMergeFoundException): + self.semver.run() + + @mock.patch("semver.semver.SemVer._version_repo", mock.MagicMock()) + def test_run_not_version_type(self): + self.semver._version_repo = mock.MagicMock() + self.semver._version_repo.return_value = "1.0.1" + self.semver._scm.get_branch.return_value = "feature/example" + self.semver._scm.get_merge_branch.return_value = "main" + self.semver._scm.get_version_type.return_value = VersionType.MINOR + self.semver._scm.commit_and_push.return_value = None + + self.semver._main_branches = ["main"] + + with self.assertRaises(NotMainBranchException): + self.semver.run() + + @mock.patch("semver.semver.SemVer._version_repo", mock.MagicMock()) + def test_run_not_main_branch(self): + self.semver._version_repo = mock.MagicMock() + self.semver._version_repo.return_value = "1.0.1" + self.semver._scm.get_branch.return_value = "main" + self.semver._scm.get_merge_branch.return_value = "main" + self.semver._scm.get_version_type.return_value = None + self.semver._scm.commit_and_push.return_value = None + + self.semver._main_branches = ["main"] + + with self.assertRaises(NoGitFlowException): + self.semver.run()