"""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()