229 lines
8.3 KiB
Python
229 lines
8.3 KiB
Python
"""Focused tests for pure URL resolution behavior in the executable module."""
|
|
|
|
import importlib.machinery
|
|
import importlib.util
|
|
import os
|
|
import pathlib
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
|
|
SCRIPT_PATH = pathlib.Path(__file__).parents[1] / "git-tui"
|
|
LOADER = importlib.machinery.SourceFileLoader("git_tui", str(SCRIPT_PATH))
|
|
SPEC = importlib.util.spec_from_loader(LOADER.name, LOADER)
|
|
assert SPEC is not None
|
|
git_tui = importlib.util.module_from_spec(SPEC)
|
|
sys.modules[LOADER.name] = git_tui
|
|
LOADER.exec_module(git_tui)
|
|
|
|
|
|
class GiteaRemoteUrlTests(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.app = git_tui.GitTuiApp.__new__(git_tui.GitTuiApp)
|
|
|
|
def test_resolves_ssh_url_from_https_base_url(self) -> None:
|
|
remote_url = self.app.resolve_gitea_remote_url(
|
|
"owner/project", "https://git.example.com", transport="ssh"
|
|
)
|
|
|
|
self.assertEqual(remote_url, "git@git.example.com:owner/project.git")
|
|
|
|
def test_resolves_custom_ssh_user_and_port(self) -> None:
|
|
remote_url = self.app.resolve_gitea_remote_url(
|
|
"owner/project",
|
|
"https://git.example.com/gitea",
|
|
transport="ssh",
|
|
ssh_user="forge",
|
|
ssh_port="2222",
|
|
)
|
|
|
|
self.assertEqual(
|
|
remote_url,
|
|
"ssh://forge@git.example.com:2222/owner/project.git",
|
|
)
|
|
|
|
def test_still_supports_https(self) -> None:
|
|
remote_url = self.app.resolve_gitea_remote_url(
|
|
"owner/project", "https://git.example.com", transport="https"
|
|
)
|
|
|
|
self.assertEqual(
|
|
remote_url,
|
|
"https://git.example.com/owner/project.git",
|
|
)
|
|
|
|
def test_rejects_invalid_ssh_port(self) -> None:
|
|
remote_url = self.app.resolve_gitea_remote_url(
|
|
"owner/project",
|
|
"https://git.example.com",
|
|
transport="ssh",
|
|
ssh_port="not-a-port",
|
|
)
|
|
|
|
self.assertEqual(remote_url, "")
|
|
|
|
|
|
class RepositorySyncTests(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.app = git_tui.GitTuiApp.__new__(git_tui.GitTuiApp)
|
|
self.app.status_message = ""
|
|
self.app.show_output = lambda *_args: None
|
|
self.app.show_command_result = lambda *_args: None
|
|
self.original_cwd = pathlib.Path.cwd()
|
|
self.temp_dir = tempfile.TemporaryDirectory()
|
|
self.root = pathlib.Path(self.temp_dir.name)
|
|
|
|
def tearDown(self) -> None:
|
|
os.chdir(self.original_cwd)
|
|
self.temp_dir.cleanup()
|
|
|
|
def git(self, cwd: pathlib.Path, *args: str) -> str:
|
|
completed = subprocess.run(
|
|
["git", *args],
|
|
cwd=cwd,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
return completed.stdout.strip()
|
|
|
|
def init_worktree(self, path: pathlib.Path) -> None:
|
|
path.mkdir()
|
|
self.git(path, "init", "-b", "main")
|
|
self.git(path, "config", "user.name", "Test User")
|
|
self.git(path, "config", "user.email", "test@example.com")
|
|
self.git(path, "config", "commit.gpgsign", "false")
|
|
|
|
def test_sync_pushes_local_commit_to_empty_remote(self) -> None:
|
|
remote = self.root / "remote.git"
|
|
local = self.root / "local"
|
|
remote.mkdir()
|
|
self.git(remote, "init", "--bare")
|
|
self.init_worktree(local)
|
|
(local / "local.txt").write_text("local\n", encoding="utf-8")
|
|
self.git(local, "add", "local.txt")
|
|
self.git(local, "commit", "-m", "local")
|
|
self.git(local, "remote", "add", "origin", str(remote))
|
|
|
|
os.chdir(local)
|
|
self.assertTrue(self.app.sync_origin_repository())
|
|
self.assertEqual(
|
|
self.git(remote, "rev-parse", "refs/heads/main"),
|
|
self.git(local, "rev-parse", "HEAD"),
|
|
)
|
|
|
|
def test_sync_populates_unborn_local_repository_from_remote(self) -> None:
|
|
remote = self.root / "remote.git"
|
|
seed = self.root / "seed"
|
|
local = self.root / "local"
|
|
remote.mkdir()
|
|
self.git(remote, "init", "--bare")
|
|
self.git(remote, "symbolic-ref", "HEAD", "refs/heads/main")
|
|
self.init_worktree(seed)
|
|
(seed / "remote.txt").write_text("remote\n", encoding="utf-8")
|
|
self.git(seed, "add", "remote.txt")
|
|
self.git(seed, "commit", "-m", "remote")
|
|
self.git(seed, "remote", "add", "origin", str(remote))
|
|
self.git(seed, "push", "origin", "main")
|
|
self.init_worktree(local)
|
|
self.git(local, "remote", "add", "origin", str(remote))
|
|
|
|
os.chdir(local)
|
|
self.assertTrue(self.app.sync_origin_repository())
|
|
self.assertEqual((local / "remote.txt").read_text(), "remote\n")
|
|
self.assertEqual(
|
|
self.git(local, "rev-parse", "HEAD"),
|
|
self.git(remote, "rev-parse", "refs/heads/main"),
|
|
)
|
|
|
|
def test_sync_merges_diverged_histories_and_pushes_result(self) -> None:
|
|
remote = self.root / "remote.git"
|
|
seed = self.root / "seed"
|
|
local = self.root / "local"
|
|
remote.mkdir()
|
|
self.git(remote, "init", "--bare")
|
|
self.git(remote, "symbolic-ref", "HEAD", "refs/heads/main")
|
|
self.init_worktree(seed)
|
|
(seed / "remote.txt").write_text("remote\n", encoding="utf-8")
|
|
self.git(seed, "add", "remote.txt")
|
|
self.git(seed, "commit", "-m", "remote")
|
|
self.git(seed, "remote", "add", "origin", str(remote))
|
|
self.git(seed, "push", "origin", "main")
|
|
self.init_worktree(local)
|
|
(local / "local.txt").write_text("local\n", encoding="utf-8")
|
|
self.git(local, "add", "local.txt")
|
|
self.git(local, "commit", "-m", "local")
|
|
self.git(local, "remote", "add", "origin", str(remote))
|
|
self.app.select_option_menu = lambda *_args: "merge"
|
|
|
|
os.chdir(local)
|
|
self.assertTrue(self.app.sync_origin_repository())
|
|
self.assertTrue((local / "local.txt").exists())
|
|
self.assertTrue((local / "remote.txt").exists())
|
|
self.assertEqual(
|
|
self.git(local, "rev-parse", "HEAD"),
|
|
self.git(remote, "rev-parse", "refs/heads/main"),
|
|
)
|
|
|
|
|
|
class GiteaPublishTests(unittest.TestCase):
|
|
def test_created_repository_can_keep_ssh_origin(self) -> None:
|
|
app = git_tui.GitTuiApp.__new__(git_tui.GitTuiApp)
|
|
app.status_message = ""
|
|
prompt_values = iter(["owner/project", "https://git.example.com"])
|
|
app.prompt_input = lambda *_args: next(prompt_values)
|
|
app.select_gitea_transport = lambda: "ssh"
|
|
app.select_repository_visibility = lambda: False
|
|
app.create_gitea_repository = lambda **_kwargs: (
|
|
True,
|
|
{
|
|
"clone_url": "https://git.example.com/owner/project.git",
|
|
"ssh_url": "git@git.example.com:owner/project.git",
|
|
"full_name": "owner/project",
|
|
},
|
|
"",
|
|
)
|
|
configured_urls = []
|
|
app.configure_origin_remote = lambda url: configured_urls.append(url) or True
|
|
app.push_head_to_remote_branch = lambda *_args, **_kwargs: True
|
|
app.current_local_branch = lambda: "main"
|
|
app.show_output = lambda *_args: None
|
|
|
|
with mock.patch.dict(os.environ, {"GITEA_TOKEN": "token"}, clear=False):
|
|
self.assertTrue(app.publish_gitea_repository())
|
|
|
|
self.assertEqual(
|
|
configured_urls,
|
|
["git@git.example.com:owner/project.git"],
|
|
)
|
|
|
|
|
|
class MainMenuTests(unittest.TestCase):
|
|
def test_remote_operations_and_disconnect_require_a_remote(self) -> None:
|
|
app = git_tui.GitTuiApp.__new__(git_tui.GitTuiApp)
|
|
app.has_any_remote = lambda: False
|
|
|
|
action_names = [action for _, action in app.main_menu_items()]
|
|
|
|
self.assertNotIn("push", action_names)
|
|
self.assertNotIn("pull", action_names)
|
|
self.assertNotIn("fetch", action_names)
|
|
self.assertNotIn("disconnect_remote", action_names)
|
|
|
|
def test_disconnect_is_available_when_a_remote_exists(self) -> None:
|
|
app = git_tui.GitTuiApp.__new__(git_tui.GitTuiApp)
|
|
app.has_any_remote = lambda: True
|
|
|
|
action_names = [action for _, action in app.main_menu_items()]
|
|
|
|
self.assertIn("push", action_names)
|
|
self.assertIn("pull", action_names)
|
|
self.assertIn("fetch", action_names)
|
|
self.assertIn("disconnect_remote", action_names)
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|