diff options
Diffstat (limited to 'app/tests/test_backends_common.py')
| -rw-r--r-- | app/tests/test_backends_common.py | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/app/tests/test_backends_common.py b/app/tests/test_backends_common.py new file mode 100644 index 0000000..b8a8e90 --- /dev/null +++ b/app/tests/test_backends_common.py @@ -0,0 +1,76 @@ +"""Tests for backends.common subprocess/git helpers. + +The streaming mode of ``run_console_subprocess`` (used by the in-TUI task +view) is exercised with a real child process: output lines are captured and +forwarded, cancellation kills the child and returns 130, and an on_cancel +hook runs first. +""" + +import sys +import threading +import unittest +from unittest import mock + +from backends import common + + +class RunConsoleSubprocessStreamingTests(unittest.TestCase): + def test_streaming_emits_merged_lines(self): + lines = [] + rc = common.run_console_subprocess( + [sys.executable, "-c", + "import sys; sys.stdout.write('hello\\nworld\\n'); " + "sys.stderr.write('oops\\n')"], + emit=lines.append) + self.assertEqual(rc, 0) + # stdout/stderr are merged, in arrival order. + self.assertEqual(sorted(lines), ["hello", "oops", "world"]) + + def test_streaming_returns_the_exit_code(self): + rc = common.run_console_subprocess( + [sys.executable, "-c", "import sys; sys.exit(3)"], + emit=lambda line: None) + self.assertEqual(rc, 3) + + def test_cancel_kills_the_process_and_returns_130(self): + cancel = threading.Event() + cancel.set() + rc = common.run_console_subprocess( + [sys.executable, "-c", "import time; time.sleep(60)"], + emit=lambda line: None, cancel=cancel) + self.assertEqual(rc, 130) + + def test_on_cancel_hook_runs_before_kill(self): + cancel = threading.Event() + cancel.set() + touched = [] + common.run_console_subprocess( + [sys.executable, "-c", "import time; time.sleep(60)"], + emit=lambda line: None, cancel=cancel, + on_cancel=lambda: touched.append(True)) + self.assertEqual(touched, [True]) + + +class GitCloneTests(unittest.TestCase): + def test_git_clone_console_passes_through(self): + with mock.patch.object(common, "run_console_subprocess", + return_value=0) as run: + self.assertEqual(common.git_clone("url", common.Path("/t")), 0) + # Console mode: no --progress flag, plain git clone. + self.assertEqual(run.call_args[0][0], + ["git", "clone", "url", "/t"]) + + def test_git_clone_streaming_adds_progress(self): + emit = lambda line: None + with mock.patch.object(common, "run_console_subprocess", + return_value=0) as run: + self.assertEqual(common.git_clone("url", common.Path("/t"), + emit=emit), 0) + argv = run.call_args[0][0] + self.assertEqual(argv[:3], ["git", "clone", "--progress"]) + self.assertIn("url", argv) + self.assertEqual(run.call_args[1]["emit"], emit) + + +if __name__ == "__main__": + unittest.main() |
