Skip to content

Commit

Permalink
Add missing tests - vol. 11
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelLipski committed Jun 24, 2023
1 parent 532ae1e commit 6d836b9
Show file tree
Hide file tree
Showing 24 changed files with 666 additions and 224 deletions.
1 change: 1 addition & 0 deletions ci/checks/enforce-mocking-only-whitelisted-methods.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ whitelisted_methods='
builtins.input
builtins.open
git_machete.client.MacheteClient.is_stdout_a_tty
git_machete.git_operations.GitContext.fetch_remote
git_machete.github.GitHubClient.MAX_PULLS_PER_PAGE_COUNT
git_machete.github.GitHubToken.for_domain
git_machete.github.RemoteAndOrganizationAndRepository.from_url
Expand Down
4 changes: 2 additions & 2 deletions git_machete/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ def launch(orig_args: List[str]) -> None:
fork_point = machete_client.fork_point(branch=branch, use_overrides=False)
machete_client.set_fork_point_override(branch, fork_point)
elif cli_opts.opt_override_to_parent:
upstream = machete_client.up_branch.get(branch)
upstream = machete_client.up_branch_for(branch)
if upstream:
machete_client.set_fork_point_override(branch, upstream)
else:
Expand Down Expand Up @@ -645,7 +645,7 @@ def launch(orig_args: List[str]) -> None:
all_opened_prs=parsed_cli.all if 'all' in parsed_cli else False,
my_opened_prs=parsed_cli.mine if 'mine' in parsed_cli else False,
opened_by=parsed_cli.by if 'by' in parsed_cli else None,
fail_on_missing_current_user_for_my_opened_prs=False)
fail_on_missing_current_user_for_my_opened_prs=True)
elif github_subcommand == "create-pr":
current_branch = git.get_current_branch()
machete_client.create_github_pr(
Expand Down
212 changes: 81 additions & 131 deletions git_machete/client.py

Large diffs are not rendered by default.

25 changes: 15 additions & 10 deletions git_machete/git_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class LocalBranchShortName(AnyBranchName):
def of(value: str) -> "LocalBranchShortName":
if value.startswith('refs/heads/') or value.startswith('refs/remotes/'):
raise TypeError( # pragma: no cover
f'LocalBranchShortName cannot accept `refs/heads` or `refs/remotes`. Given value: {value}.\n' + GITHUB_NEW_ISSUE_MESSAGE)
f'LocalBranchShortName cannot accept `refs/heads` or `refs/remotes`. '
f'Provided value: {value}.\n{GITHUB_NEW_ISSUE_MESSAGE}')
else:
return LocalBranchShortName(value)

Expand All @@ -60,8 +61,8 @@ def of(value: str) -> "LocalBranchFullName":
return LocalBranchFullName(value)
else:
raise TypeError( # pragma: no cover
f'LocalBranchFullName needs to have `refs/heads` prefix before branch name. Given value: {value}.\n' +
GITHUB_NEW_ISSUE_MESSAGE)
f'LocalBranchFullName needs to have `refs/heads` prefix before branch name. '
f'Provided value: {value}.\n{GITHUB_NEW_ISSUE_MESSAGE}')

@staticmethod
def from_short_name(value: LocalBranchShortName) -> "LocalBranchFullName":
Expand All @@ -79,7 +80,8 @@ class RemoteBranchShortName(AnyBranchName):
def of(value: str) -> "RemoteBranchShortName":
if value and value.startswith('refs/heads/') or value.startswith('refs/remotes/'):
raise TypeError( # pragma: no cover
f'RemoteBranchShortName cannot accept `refs/heads` or `refs/remotes`. Given value: {value}.\n' + GITHUB_NEW_ISSUE_MESSAGE)
f'RemoteBranchShortName cannot accept `refs/heads` or `refs/remotes`. '
f'Provided value: {value}.\n{GITHUB_NEW_ISSUE_MESSAGE}')
else:
return RemoteBranchShortName(value)

Expand All @@ -94,8 +96,8 @@ def of(value: str) -> "RemoteBranchFullName":
return RemoteBranchFullName(value)
else:
raise TypeError( # pragma: no cover
f'RemoteBranchFullName needs to have `refs/remotes` prefix before branch name. Given value: {value}.\n' +
GITHUB_NEW_ISSUE_MESSAGE)
f'RemoteBranchFullName needs to have `refs/remotes` prefix before branch name. '
f'Provided value: {value}.\n{GITHUB_NEW_ISSUE_MESSAGE}')

@staticmethod
def is_valid(value: str) -> bool:
Expand All @@ -119,7 +121,8 @@ def of(value: str) -> "FullCommitHash":
return FullCommitHash(value)
else:
raise TypeError( # pragma: no cover
f'FullCommitHash requires length of 40. Given value: "{value}".\n' + GITHUB_NEW_ISSUE_MESSAGE)
f'FullCommitHash requires length of 40. '
f'Provided value: "{value}".\n{GITHUB_NEW_ISSUE_MESSAGE}')

@staticmethod
def is_valid(value: str) -> bool:
Expand All @@ -136,8 +139,8 @@ def of(value: str) -> "ShortCommitHash":
return ShortCommitHash(value)
else:
raise TypeError( # pragma: no cover
f'ShortCommitHash requires length greater or equal to 7. Given value: "{value}".\n' +
GITHUB_NEW_ISSUE_MESSAGE)
f'ShortCommitHash requires length greater or equal to 7. '
f'Provided value: "{value}".\n{GITHUB_NEW_ISSUE_MESSAGE}')

def full_name(self) -> "ShortCommitHash":
return self
Expand All @@ -148,7 +151,7 @@ class FullTreeHash(str):
def of(value: str) -> Optional["FullTreeHash"]:
if not value:
raise TypeError( # pragma: no cover
f'FullTreeHash.of should not accept {value} as a param.\n' + GITHUB_NEW_ISSUE_MESSAGE)
f'FullTreeHash.of should not accept {value} as a param.\n{GITHUB_NEW_ISSUE_MESSAGE}')
return FullTreeHash(value)


Expand Down Expand Up @@ -180,10 +183,12 @@ class GitContext:

def __init__(self) -> None:
self.owner: Optional[Any] = None

self.__git_version: Optional[Tuple[int, int, int]] = None
self.__root_dir: Optional[str] = None
self.__main_git_dir: Optional[str] = None
self.__worktree_git_dir: Optional[str] = None

self.__commit_hash_by_revision_cached: Optional[Dict[AnyRevision, Optional[FullCommitHash]]] = None
self.__committer_unix_timestamp_by_revision_cached: Optional[Dict[AnyRevision, int]] = None
self.__config_cached: Optional[Dict[str, str]] = None
Expand Down
10 changes: 5 additions & 5 deletions git_machete/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,17 @@ def __get_token_from_hub(cls, domain: str) -> Optional["GitHubToken"]:
if line.rstrip() == domain + ":":
found_host = True
elif found_host and line.lstrip().startswith("oauth_token:"):
result = re.sub(' *oauth_token: *', '', line).rstrip().replace('"', '')
result = re.sub(' *oauth_token: +', '', line).rstrip().replace('"', '')
return cls(value=result,
provider=f'auth token for {domain} from `hub` GitHub CLI')
return None

@classmethod
def get_possible_providers(cls) -> str:
return (f'\n\t1. `{GITHUB_TOKEN_ENV_VAR}` environment variable.\n'
'\t2. Content of the `~/.github-token` file.\n'
'\t3. Current auth token from the `gh` GitHub CLI.\n'
'\t4. Current auth token from the `hub` GitHub CLI.\n')
return (f'\n\t1. `{GITHUB_TOKEN_ENV_VAR}` environment variable\n'
'\t2. Content of the `~/.github-token` file\n'
'\t3. Current auth token from the `gh` GitHub CLI\n'
'\t4. Current auth token from the `hub` GitHub CLI\n')


class GitHubClient:
Expand Down
4 changes: 2 additions & 2 deletions git_machete/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ def find_executable(executable: str) -> Optional[str]:
base, ext = os.path.splitext(executable)

if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'):
executable = f"{executable}.exe" # pragma: no cover
executable += ".exe" # pragma: no cover

if os.path.isfile(executable):
if os.path.isfile(executable) and is_executable(executable):
return executable

path = os.environ.get('PATH', os.defpath)
Expand Down
4 changes: 3 additions & 1 deletion tests/mockers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import io
import os
import re
import subprocess
import sys
import textwrap
Expand Down Expand Up @@ -54,7 +55,7 @@ def assert_success(cmds: Iterable[str], expected_result: str) -> None:
# removeprefix is only available since Python 3.9
expected_result = expected_result[1:]
expected_result = textwrap.dedent(expected_result)
actual_result = textwrap.dedent(launch_command(*cmds))
actual_result = re.sub(" +$", "", textwrap.dedent(launch_command(*cmds)), flags=re.MULTILINE)
assert actual_result == expected_result


Expand All @@ -67,6 +68,7 @@ def assert_failure(cmds: Iterable[str], expected_result: str, expected_exception
with pytest.raises(expected_exception) as e:
launch_command(*cmds)
error_message = e.value.msg # type: ignore[attr-defined]
error_message = re.sub(" +$", "", error_message, flags=re.MULTILINE)
if sys.platform == 'win32':
error_message = error_message.replace('.git\\machete', '.git/machete')
assert error_message == expected_result
Expand Down
2 changes: 1 addition & 1 deletion tests/mockers_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def get_open_pulls(self) -> List[Dict[str, Any]]:

def add_pull(self, pull: Dict[str, Any]) -> None:
pull_numbers = [int(item['number']) for item in self.__pulls]
pull['number'] = str(max(pull_numbers) + 1)
pull['number'] = str(max(pull_numbers or [0]) + 1)
self.__pulls.append(pull)


Expand Down
8 changes: 4 additions & 4 deletions tests/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_add(self, mocker: MockerFixture) -> None:
self.patch_symbol(mocker, "builtins.input", mock_input_returning("n"))
assert_success(
['add'],
'Add bugfix/feature_fail onto the inferred upstream (parent) branch develop? (y, N) \n'
'Add bugfix/feature_fail onto the inferred upstream (parent) branch develop? (y, N)\n'
)
assert_success(
['add', '-y'],
Expand Down Expand Up @@ -81,7 +81,7 @@ def test_add_check_out_remote_branch(self, mocker: MockerFixture) -> None:
self.patch_symbol(mocker, "builtins.input", mock_input_returning("n"))
assert_success(
['add', 'foo'],
'A local branch foo does not exist. Create out of the current HEAD? (y, N) \n'
'A local branch foo does not exist. Create out of the current HEAD? (y, N)\n'
)

assert_success(
Expand All @@ -94,7 +94,7 @@ def test_add_check_out_remote_branch(self, mocker: MockerFixture) -> None:
assert_success(
['add', '--as-root', 'feature/foo'],
'A local branch feature/foo does not exist, but a remote branch origin/feature/foo exists.\n'
'Check out feature/foo locally? (y, N) \n'
'Check out feature/foo locally? (y, N)\n'
)

assert_success(
Expand All @@ -115,7 +115,7 @@ def test_add_new_branch_onto_managed_current_branch(self, mocker: MockerFixture)
self.patch_symbol(mocker, "builtins.input", mock_input_returning_y)
assert_success(
['add', 'foo'],
"A local branch foo does not exist. Create out of the current HEAD? (y, N) \n"
"A local branch foo does not exist. Create out of the current HEAD? (y, N)\n"
"Added branch foo onto master\n"
)

Expand Down
8 changes: 4 additions & 4 deletions tests/test_advance.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_advance_with_immediate_cancel(self, mocker: MockerFixture) -> None:
rewrite_definition_file("master\n develop")

self.patch_symbol(mocker, "builtins.input", mock_input_returning("n"))
assert_success(["advance"], "Fast-forward master to match develop? (y, N) \n")
assert_success(["advance"], "Fast-forward master to match develop? (y, N)\n")

def test_advance_with_push_for_one_downstream_branch(self) -> None:
"""
Expand Down Expand Up @@ -191,11 +191,11 @@ def test_advance_for_a_few_possible_downstream_branches_and_yes_option(self, moc
"""
[1] level-1a-branch
[2] level-1b-branch
Specify downstream branch towards which root is to be fast-forwarded or hit <return> to skip:
Specify downstream branch towards which root is to be fast-forwarded or hit <return> to skip:
Branch root is now fast-forwarded to match level-1a-branch. Push root to origin? (y, N)
Branch root is now fast-forwarded to match level-1a-branch. Push root to origin? (y, N)
Branch root is now fast-forwarded to match level-1a-branch. Slide level-1a-branch out of the tree of branch dependencies? (y, N)
Branch root is now fast-forwarded to match level-1a-branch. Slide level-1a-branch out of the tree of branch dependencies? (y, N)
"""
)

Expand Down
22 changes: 21 additions & 1 deletion tests/test_clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .base_test import BaseTest
from .mockers import (assert_success, launch_command, mock_input_returning_y,
rewrite_definition_file)
from .mockers_github import mock_github_token_for_domain_none


class TestClean(BaseTest):
Expand Down Expand Up @@ -43,7 +44,7 @@ def test_clean(self, mocker: MockerFixture) -> None:
foo2
moo
moo2
mars
mars
"""
rewrite_definition_file(body)

Expand All @@ -66,3 +67,22 @@ def test_clean(self, mocker: MockerFixture) -> None:
branches = self.repo_sandbox.get_local_branches()
assert 'foo' in branches
assert 'mars' not in branches

def test_clean_with_checkout_my_github_prs(self, mocker: MockerFixture) -> None:
self.patch_symbol(mocker, 'git_machete.github.GitHubToken.for_domain', mock_github_token_for_domain_none)
self.repo_sandbox.remove_remote("origin").add_remote("new_origin", "https://github.com/user/repo.git")
assert_success(
["clean", "--checkout-my-github-prs"],
"""
Checking for open GitHub PRs... Warn: Could not determine current user name, please check that the GitHub API token provided by one of the:
\t1. GITHUB_TOKEN environment variable
\t2. Content of the ~/.github-token file
\t3. Current auth token from the gh GitHub CLI
\t4. Current auth token from the hub GitHub CLI
is valid.
Checking for unmanaged branches...
No branches to delete
Checking for untracked managed branches with no downstream...
No branches to delete
""" # noqa: E501
)
2 changes: 1 addition & 1 deletion tests/test_delete_unmanaged.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def test_delete_unmanaged(self, mocker: MockerFixture) -> None:
"""
Checking for unmanaged branches...
Skipping current branch feature
Delete branch develop (merged to HEAD)? (y, N, q)
Delete branch develop (merged to HEAD)? (y, N, q)
Deleted branch develop (was 03e727b).
"""
)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_discover.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def test_discover_main_branch_and_edit(self, mocker: MockerFixture) -> None:
feature1
Save the above tree to .git/machete? (y, e[dit], N)
Save the above tree to .git/machete? (y, e[dit], N)
"""
)

Expand Down Expand Up @@ -209,7 +209,7 @@ def test_discover_with_merged_branches(self, mocker: MockerFixture) -> None:
x-feature2
Save the above tree to .git/machete?
The existing definition file will be backed up as .git/machete~ (y, e[dit], N)
The existing definition file will be backed up as .git/machete~ (y, e[dit], N)
"""
)

Expand Down
8 changes: 8 additions & 0 deletions tests/test_edit.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import sys

import pytest
from pytest_mock import MockerFixture

from .base_test import BaseTest
Expand All @@ -15,6 +17,12 @@ def test_edit_git_machete_editor(self) -> None:
launch_command("edit")
assert self.repo_sandbox.read_file(".git/machete").strip() == "foo"

@pytest.mark.skipif(sys.platform == "win32", reason="There isn't a /bin/ folder under Windows")
def test_edit_git_machete_editor_full_path(self) -> None:
with overridden_environment(GIT_MACHETE_EDITOR="/bin/" + dummy_editor):
launch_command("edit")
assert self.repo_sandbox.read_file(".git/machete").strip() == "foo"

def test_edit_git_machete_editor_not_valid_executable(self) -> None:
with overridden_environment(GIT_MACHETE_EDITOR="lolxd-this-doesnt-exist"):
assert_failure(["edit"], "'$GIT_MACHETE_EDITOR' (lolxd-this-doesnt-exist) is not available")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def test_file(self) -> None:

def test_file_outside_git_repo(self) -> None:
os.chdir(mkdtemp())
assert_failure(["file"], "Not a git repository", expected_exception=UnderlyingGitException)
assert_failure(["file", "--debug"], "Not a git repository", expected_exception=UnderlyingGitException)

def test_file_when_git_machete_is_a_directory(self) -> None:
self.repo_sandbox.execute(f"mkdir .git{os.path.sep}machete")
Expand Down
32 changes: 30 additions & 2 deletions tests/test_github_anno_prs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pytest_mock import MockerFixture

from tests.base_test import BaseTest
from tests.mockers import (assert_success, launch_command,
from tests.mockers import (assert_failure, assert_success, launch_command,
rewrite_definition_file)
from tests.mockers_github import (MockGitHubAPIState,
mock_github_token_for_domain_fake,
Expand Down Expand Up @@ -87,7 +87,7 @@ def test_github_anno_prs(self, mocker: MockerFixture) -> None:
# is different than the current user, overwrite annotation text but doesn't overwrite existing qualifiers
launch_command('anno', '-b=allow-ownership-link', 'rebase=no')
launch_command('anno', '-b=build-chain', 'rebase=no push=no')
launch_command('github', 'anno-prs')
launch_command('github', 'anno-prs', '--debug')
assert_success(
["status"],
"""
Expand Down Expand Up @@ -198,3 +198,31 @@ def test_github_anno_prs_local_branch_name_different_than_tracking_branch_name(s
['status'],
expected_result=expected_status_output
)

def test_github_anno_prs_no_remotes(self) -> None:
assert_failure(
["github", "anno-prs"],
"""
Remotes are defined for this repository, but none of them seems to correspond to GitHub (see git remote -v for details).
It is possible that you are using a custom GitHub URL.
If that is the case, you can provide repository information explicitly via some or all of git config keys: machete.github.{domain,remote,organization,repository}.
""" # noqa: E501
)

self.repo_sandbox.remove_remote()
assert_failure(["github", "anno-prs"], "No remotes defined for this repository (see git remote)")

def test_github_anno_prs_multiple_non_origin_github_remotes(self) -> None:
(
self.repo_sandbox
.remove_remote("origin")
.add_remote("origin-1", "https://github.com/tester/repo_sandbox-1.git")
.add_remote("origin-2", "https://github.com/tester/repo_sandbox-2.git")
)
assert_failure(
["github", "anno-prs"],
"""
Multiple non-origin remotes correspond to GitHub in this repository: origin-1, origin-2 -> aborting.
You can also select the repository by providing some or all of git config keys: machete.github.{domain,remote,organization,repository}.
""" # noqa: E501
)
Loading

0 comments on commit 6d836b9

Please sign in to comment.