Skip to content

Commit b5cf15e

Browse files
committed
adding more tests
1 parent ed23f3a commit b5cf15e

File tree

2 files changed

+106
-31
lines changed

2 files changed

+106
-31
lines changed

src/edit_python_pe/main.py

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121
class MemberApp(App):
2222
"""Single app that toggles between a file list and a form while connected to a GitHub fork+push flow."""
2323

24-
def __init__(self, token: str, original_repo: Repository) -> None:
24+
def __init__(self, repo_path: str) -> None:
2525
super().__init__()
26-
self.token = token
27-
self.original_repo = original_repo
26+
self.repo_path = repo_path
2827

2928
def compose(self) -> ComposeResult:
3029
# Two main containers: self.list_container for the file list, self.form_container for the form.
@@ -35,23 +34,7 @@ def compose(self) -> ComposeResult:
3534
yield self.form_container
3635

3736
def on_mount(self) -> None:
38-
"""Perform setup: do fork if needed, set up UI."""
39-
self.forked_repo = self.original_repo.create_fork()
40-
self.FORKED_REPO_URL = self.forked_repo.clone_url
41-
self.REPO_PATH = user_data_dir(
42-
appname="edit-python-pe", appauthor="python.pe"
43-
)
44-
45-
if not os.path.exists(self.REPO_PATH):
46-
callbacks = pygit2.callbacks.RemoteCallbacks(
47-
credentials=pygit2.UserPass(self.token, "x-oauth-basic")
48-
)
49-
sleep(3)
50-
pygit2.clone_repository(
51-
self.FORKED_REPO_URL, self.REPO_PATH, callbacks=callbacks
52-
)
53-
54-
# 2) Build the list portion
37+
# 1) Build the list portion
5538
self.list_title = Static("Archivos en 'blog/members':")
5639
self.list_view = ListView()
5740
self.quit_list_button = Button("Salir", id="quit_list")
@@ -63,13 +46,13 @@ def on_mount(self) -> None:
6346
self.list_container.mount(self.quit_list_button)
6447

6548
md_files = glob.glob(
66-
os.path.join(self.REPO_PATH, "blog", "members", "*.md")
49+
os.path.join(self.repo_path, "blog", "members", "*.md")
6750
)
6851
for f in md_files:
6952
basename = os.path.basename(f)
7053
self.list_view.append(ListItem(Static(basename)))
7154

72-
# 3) Build the form portion, hidden at first
55+
# 2) Build the form portion, hidden at first
7356
self.form_header = Static("Formulario de Miembro", classes="header")
7457
self.name_input = Input(placeholder="Nombre")
7558
self.email_input = Input(placeholder="Correo electrónico")
@@ -175,7 +158,7 @@ def on_list_view_selected(self, event: ListView.Selected) -> None:
175158
self.show_form()
176159

177160
def load_file_into_form(self, filename: str) -> None:
178-
path_md = os.path.join(self.REPO_PATH, "blog", "members", filename)
161+
path_md = os.path.join(self.repo_path, "blog", "members", filename)
179162
if not os.path.exists(path_md):
180163
return
181164
try:
@@ -494,20 +477,20 @@ def save_member(self) -> None:
494477

495478
# Write file
496479
file_path = os.path.join(
497-
self.REPO_PATH, "blog", "members", f"{name_file}.md"
480+
self.repo_path, "blog", "members", f"{name_file}.md"
498481
)
499482
else:
500483
name_file = self.current_file
501484
file_path = os.path.join(
502-
self.REPO_PATH, "blog", "members", f"{name_file}"
485+
self.repo_path, "blog", "members", f"{name_file}"
503486
)
504487
os.makedirs(os.path.dirname(file_path), exist_ok=True)
505488
with open(file_path, "w", encoding="utf-8") as f:
506489
f.write(md_content)
507490

508491
# commit & push
509-
repo = pygit2.Repository(self.REPO_PATH)
510-
rel_path = os.path.relpath(file_path, self.REPO_PATH)
492+
repo = pygit2.Repository(self.repo_path)
493+
rel_path = os.path.relpath(file_path, self.repo_path)
511494
rel_path = pathlib.Path(rel_path).as_posix() # Force path to POSIX format so Windows backslashes (\) don't break pygit2
512495
repo.index.add(rel_path)
513496
repo.index.write()
@@ -592,7 +575,7 @@ async def on_event(self, event: Event) -> None:
592575

593576

594577
def get_repo() -> tuple[str, Repository]:
595-
token: str = getpass.getpass(
578+
token = getpass.getpass(
596579
"Por favor ingrese su access token personal de GitHub: "
597580
)
598581
g = Github(token)
@@ -609,9 +592,28 @@ def get_repo() -> tuple[str, Repository]:
609592
exit(1)
610593

611594

595+
def fork_repo(token: str, original_repo: Repository) -> str:
596+
forked_repo = original_repo.create_fork()
597+
forked_repo_url = forked_repo.clone_url
598+
repo_path = user_data_dir(
599+
appname="edit-python-pe", appauthor="python.pe"
600+
)
601+
602+
if not os.path.exists(repo_path):
603+
callbacks = pygit2.callbacks.RemoteCallbacks(
604+
credentials=pygit2.UserPass(token, "x-oauth-basic")
605+
)
606+
sleep(3)
607+
pygit2.clone_repository(
608+
forked_repo_url, repo_path, callbacks=callbacks
609+
)
610+
return repo_path
611+
612+
612613
def main() -> None:
613614
token, original_repo = get_repo()
614-
app = MemberApp(token=token, original_repo=original_repo)
615+
repo_path = fork_repo(token, original_repo)
616+
app = MemberApp(repo_path)
615617
app.run()
616618

617619

tests/test_member_app.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def setUp(self):
1616
# Patch Github and Repository for testing
1717
self.token = "fake-token"
1818
self.repo = MagicMock()
19-
self.app = MemberApp(token=self.token, original_repo=self.repo)
19+
self.app = MemberApp(repo_path="test_repo")
2020
self.app.social_container = MagicMock()
2121
self.app.alias_container = MagicMock()
2222
self.app.list_container = MagicMock()
@@ -447,4 +447,77 @@ def stub_add_alias_entry():
447447
self.assertEqual(self.app.city_input.value, "Lima")
448448
self.assertEqual(self.app.homepage_input.value, "https://joe-doe.org")
449449
self.assertGreaterEqual(len(self.app.social_entries), 1)
450-
self.assertGreaterEqual(len(self.app.alias_entries), 1)
450+
451+
# Test for get_repo function
452+
import builtins
453+
from edit_python_pe.main import get_repo
454+
455+
class TestGetRepo(unittest.TestCase):
456+
@patch("edit_python_pe.main.getpass.getpass", return_value="valid-token")
457+
@patch("edit_python_pe.main.Github")
458+
def test_get_repo_success(self, mock_github, mock_getpass):
459+
mock_repo = MagicMock()
460+
mock_github.return_value.get_repo.return_value = mock_repo
461+
token, repo = get_repo()
462+
self.assertEqual(token, "valid-token")
463+
self.assertEqual(repo, mock_repo)
464+
465+
@patch("edit_python_pe.main.getpass.getpass", return_value="invalid-token")
466+
@patch("edit_python_pe.main.Github")
467+
def test_get_repo_bad_credentials(self, mock_github, mock_getpass):
468+
from github.GithubException import BadCredentialsException
469+
mock_github.return_value.get_repo.side_effect = BadCredentialsException(401, "Bad credentials", None)
470+
with self.assertRaises(SystemExit):
471+
get_repo()
472+
473+
@patch("edit_python_pe.main.getpass.getpass", return_value="valid-token")
474+
@patch("edit_python_pe.main.Github")
475+
def test_get_repo_github_exception(self, mock_github, mock_getpass):
476+
from github.GithubException import GithubException
477+
mock_github.return_value.get_repo.side_effect = GithubException(404, "Not found", None)
478+
with self.assertRaises(SystemExit):
479+
get_repo()
480+
481+
482+
from edit_python_pe.main import fork_repo
483+
484+
class TestForkRepo(unittest.TestCase):
485+
@patch("edit_python_pe.main.user_data_dir", return_value="/tmp/testrepo")
486+
@patch("edit_python_pe.main.os.path.exists", return_value=False)
487+
@patch("edit_python_pe.main.pygit2.clone_repository")
488+
@patch("edit_python_pe.main.sleep", return_value=None)
489+
def test_fork_repo_clones_if_not_exists(self, mock_sleep, mock_clone, mock_exists, mock_user_data_dir):
490+
mock_forked_repo = MagicMock()
491+
mock_forked_repo.clone_url = "https://github.com/fake/fork.git"
492+
mock_original_repo = MagicMock()
493+
mock_original_repo.create_fork.return_value = mock_forked_repo
494+
token = "fake-token"
495+
repo_path = fork_repo(token, mock_original_repo)
496+
mock_original_repo.create_fork.assert_called_once()
497+
mock_clone.assert_called_once_with(
498+
mock_forked_repo.clone_url, repo_path, callbacks=unittest.mock.ANY
499+
)
500+
self.assertEqual(repo_path, "/tmp/testrepo")
501+
502+
@patch("edit_python_pe.main.user_data_dir", return_value="/tmp/testrepo")
503+
@patch("edit_python_pe.main.os.path.exists", return_value=True)
504+
@patch("edit_python_pe.main.pygit2.clone_repository")
505+
def test_fork_repo_no_clone_if_exists(self, mock_clone, mock_exists, mock_user_data_dir):
506+
mock_forked_repo = MagicMock()
507+
508+
from edit_python_pe.main import main
509+
510+
class TestMainFunction(unittest.TestCase):
511+
@patch("edit_python_pe.main.get_repo")
512+
@patch("edit_python_pe.main.fork_repo")
513+
@patch("edit_python_pe.main.MemberApp")
514+
def test_main_runs_app(self, mock_member_app, mock_fork_repo, mock_get_repo):
515+
mock_get_repo.return_value = ("token", MagicMock())
516+
mock_fork_repo.return_value = "/tmp/testrepo"
517+
mock_app_instance = MagicMock()
518+
mock_member_app.return_value = mock_app_instance
519+
main()
520+
mock_get_repo.assert_called_once()
521+
mock_fork_repo.assert_called_once()
522+
mock_member_app.assert_called_once_with("/tmp/testrepo")
523+
mock_app_instance.run.assert_called_once()

0 commit comments

Comments
 (0)