From ecd060665e69349829938049531dd5293fa1f8b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:01:29 +0000 Subject: [PATCH 1/4] Initial plan From 4b156a01970d24a2e78a7f847cad269224c6d5f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:08:06 +0000 Subject: [PATCH 2/4] Add tests for CLI dispatcher and GitHub Actions workflow Co-authored-by: steveward <721500+steveward@users.noreply.github.com> --- .coverage | Bin 0 -> 53248 bytes .github/workflows/tests.yml | 43 +++++++++++++++++ tests/__init__.py | 1 + tests/test_main.py | 92 ++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 .coverage create mode 100644 .github/workflows/tests.yml create mode 100644 tests/__init__.py create mode 100644 tests/test_main.py diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..4e711de39258eb62de82a68573e70c1dc1f8a414 GIT binary patch literal 53248 zcmeI)&u`mg7zc1W>5?W*COd5lV3liR&EtVlBzOE&|n7f%2Lv z)KRQCt@YyiqaTX-%EE$qqT)Kqph-V-W3{0J!>ZhFQ$bBXXmRw7KzhwR6;_2D)UfGO zoQILFZQ#4L$QK>Qi>v8{PUQHWP=~77i&X2v3RW2{-3V{AHdNMquF!p*Gr87?&M@-@ zIg{i`<~9ZA`6=r#BVU>_$1!_7w?X9J_S`Nv4&~4nj{HeEC*_U&q_QvEHW#$zu)br> znUZsh>Rdg~+3%@A<5$HnXEm;d=T`++f_lJPbGgcU3#LK6QXPi-9eTfI%UN@p8uCl!{sp|~7fL$N#7LS*5`O5OL`LGaoqolQxU-_{vl(ysr z(`b6iRWj@a=|u9pNixkboF&sSlANLHY~*v5t>sD8Nz&Q%WM}p`Ka;O4E}F-BMDV=C zk85L<;3LB!aAqNR@$kDc+7stv=ff2E>a|?ugT+aKa|m{wpL37C&cq>~EXDdRP5S)E zj)lxeh9Q5Zjy4Wthh~$mbOIW(GzaSyKybpAq{On}_oBG}^2@k;^4c?uR~ImRo!V2X z^*A{V@6Y`(bZA-SWh;C?Jt|iBWXQ8nxGEaH-%--jYXjxD9nv+OP{c8uUzI)_mJuFt z8M_CoaZKsr!qfZ?4Z3uE(T?j%ua&G2cbH(Y^=u;V~$Z?h6Bylit$Lh;aGy_E^X)Rq}%|5Ri zaBJChe&)O6S$->bykh1nH*T26y<{-zdBzTDQFmn;cJeYa)=AEs9QK#HG~v>_ozZ^6 zb|W18QeS~5H{F5_t&pZl-s=?C`3B##P7V6O1_1~_00Izz00bZa0SG_<0uX?}e@`H5 zX3RX_|7Wbf4C`-t!Uh2dKmY;|fB*y_009U<00Izzz$+UM8tBm!;u%1}|ypk0}&=7zC1Rwwb2tWV=5P$##AOHaf3t_0AfJ`yF zTuA;3puhkB*svZCl41t}5P$##AOHafKmY;|fB*y_0D-9#xMgOIer?ZpRW0awo(gJx zKX_0J=#D?^9-aGb+pcsx+ou07fj|E@tv?LivjL{Jcb00bZa0SG_<0uX=z1Rwwb z2wX;>Y|a!4Z@z9)-tT^YBcnh6KQ*k=%M^w@5P$##AOHafKmY;|fB*y_009V0xxftl zAt3(z-SyWQG6)AOHafKmY;| tfB*y_009V0y#W9Ff8761eKR3I2tWV=5P$##AOHafKmY;|fWVam{snGHRc8PI literal 0 HcmV?d00001 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..5c094b5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,43 @@ +name: Tests + +on: + push: + branches: [ master, main ] + pull_request: + branches: [ master, main ] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pytest pytest-cov + + - name: Run tests + run: | + pytest tests/ -v --cov=rhasspy --cov-report=term-missing + + - name: Run tests with coverage report + if: matrix.python-version == '3.9' + run: | + pytest tests/ --cov=rhasspy --cov-report=xml + + - name: Upload coverage to Codecov + if: matrix.python-version == '3.9' + uses: codecov/codecov-action@v3 + with: + file: ./coverage.xml + fail_ci_if_error: false diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..f6abdf5 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Tests package for rhasspy.""" diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..00c7c23 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,92 @@ +"""Tests for rhasspy.__main__ CLI dispatcher.""" +import sys +from unittest import mock +import pytest +from rhasspy.__main__ import main, _COMMANDS + + +def test_commands_list_not_empty(): + """Test that the commands list is populated.""" + assert len(_COMMANDS) > 0 + assert "hermes" in _COMMANDS + + +def test_main_no_arguments(capsys): + """Test main() with no arguments shows usage.""" + with mock.patch.object(sys, "argv", ["rhasspy"]): + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 1 + + captured = capsys.readouterr() + assert "Usage: rhasspy COMMAND ARGS" in captured.out + assert "Available commands:" in captured.out + + +def test_main_unknown_command(capsys): + """Test main() with unknown command shows error.""" + with mock.patch.object(sys, "argv", ["rhasspy", "unknown-command"]): + with pytest.raises(SystemExit) as exc_info: + main() + assert exc_info.value.code == 1 + + captured = capsys.readouterr() + assert "Unknown command:" in captured.out + assert "Available commands:" in captured.out + + +def test_main_valid_command_module_not_found(): + """Test main() with valid command that can't be imported.""" + # Use a valid command name but the module won't exist in test environment + with mock.patch.object(sys, "argv", ["rhasspy", "hermes", "--help"]): + with pytest.raises((ImportError, ModuleNotFoundError)): + main() + + +def test_main_command_passes_arguments(): + """Test that arguments are properly passed to subcommand.""" + # Mock the module import and main function + mock_module = mock.MagicMock() + mock_module.main = mock.MagicMock() + + with mock.patch.object(sys, "argv", ["rhasspy", "hermes", "--arg1", "value1"]): + with mock.patch("builtins.__import__", return_value=mock_module): + # Capture sys.argv during the main() call + captured_argv = None + def capture_and_call(): + nonlocal captured_argv + captured_argv = sys.argv[:] + mock_module.main.side_effect = capture_and_call + + main() + + # Verify the submodule's main was called + mock_module.main.assert_called_once() + # Verify sys.argv was modified correctly (command name removed) + assert captured_argv == ["rhasspy", "--arg1", "value1"] + + +def test_to_python_name_from_setup(): + """Test the module name conversion logic.""" + # Import the function from setup.py logic + # This tests the naming convention used in the dispatcher + + # Test that command names map to expected module names + test_cases = { + "hermes": "rhasspyhermes", + "asr-pocketsphinx": "rhasspyasr_pocketsphinx", + "nlu-hermes": "rhasspynlu_hermes", + } + + for command, expected_module in test_cases.items(): + # The __main__.py converts "rhasspy-MODULE" to "rhasspyMODULE" + # It replaces hyphens with underscores + module_name = "rhasspy" + command.replace("-", "_") + assert module_name == expected_module + + +def test_all_commands_are_strings(): + """Test that all commands in _COMMANDS are strings.""" + for command in _COMMANDS: + assert isinstance(command, str) + assert len(command) > 0 From a0a3ccf076e5a21ff85ab8c20a148252eccb87e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:08:57 +0000 Subject: [PATCH 3/4] Update .gitignore to exclude test artifacts Co-authored-by: steveward <721500+steveward@users.noreply.github.com> --- .coverage | Bin 53248 -> 0 bytes .gitignore | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 .coverage diff --git a/.coverage b/.coverage deleted file mode 100644 index 4e711de39258eb62de82a68573e70c1dc1f8a414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeI)&u`mg7zc1W>5?W*COd5lV3liR&EtVlBzOE&|n7f%2Lv z)KRQCt@YyiqaTX-%EE$qqT)Kqph-V-W3{0J!>ZhFQ$bBXXmRw7KzhwR6;_2D)UfGO zoQILFZQ#4L$QK>Qi>v8{PUQHWP=~77i&X2v3RW2{-3V{AHdNMquF!p*Gr87?&M@-@ zIg{i`<~9ZA`6=r#BVU>_$1!_7w?X9J_S`Nv4&~4nj{HeEC*_U&q_QvEHW#$zu)br> znUZsh>Rdg~+3%@A<5$HnXEm;d=T`++f_lJPbGgcU3#LK6QXPi-9eTfI%UN@p8uCl!{sp|~7fL$N#7LS*5`O5OL`LGaoqolQxU-_{vl(ysr z(`b6iRWj@a=|u9pNixkboF&sSlANLHY~*v5t>sD8Nz&Q%WM}p`Ka;O4E}F-BMDV=C zk85L<;3LB!aAqNR@$kDc+7stv=ff2E>a|?ugT+aKa|m{wpL37C&cq>~EXDdRP5S)E zj)lxeh9Q5Zjy4Wthh~$mbOIW(GzaSyKybpAq{On}_oBG}^2@k;^4c?uR~ImRo!V2X z^*A{V@6Y`(bZA-SWh;C?Jt|iBWXQ8nxGEaH-%--jYXjxD9nv+OP{c8uUzI)_mJuFt z8M_CoaZKsr!qfZ?4Z3uE(T?j%ua&G2cbH(Y^=u;V~$Z?h6Bylit$Lh;aGy_E^X)Rq}%|5Ri zaBJChe&)O6S$->bykh1nH*T26y<{-zdBzTDQFmn;cJeYa)=AEs9QK#HG~v>_ozZ^6 zb|W18QeS~5H{F5_t&pZl-s=?C`3B##P7V6O1_1~_00Izz00bZa0SG_<0uX?}e@`H5 zX3RX_|7Wbf4C`-t!Uh2dKmY;|fB*y_009U<00Izzz$+UM8tBm!;u%1}|ypk0}&=7zC1Rwwb2tWV=5P$##AOHaf3t_0AfJ`yF zTuA;3puhkB*svZCl41t}5P$##AOHafKmY;|fB*y_0D-9#xMgOIer?ZpRW0awo(gJx zKX_0J=#D?^9-aGb+pcsx+ou07fj|E@tv?LivjL{Jcb00bZa0SG_<0uX=z1Rwwb z2wX;>Y|a!4Z@z9)-tT^YBcnh6KQ*k=%M^w@5P$##AOHafKmY;|fB*y_009V0xxftl zAt3(z-SyWQG6)AOHafKmY;| tfB*y_009V0y#W9Ff8761eKR3I2tWV=5P$##AOHafKmY;|fWVam{snGHRc8PI diff --git a/.gitignore b/.gitignore index 735f919..415b24e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,10 @@ site/ web/ download/ -*.log \ No newline at end of file +*.log + +# Testing +.coverage +.pytest_cache/ +htmlcov/ +coverage.xml \ No newline at end of file From 40c3468ba6112bb74c3d605202147394b53f6402 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:11:43 +0000 Subject: [PATCH 4/4] Add explicit permissions to GitHub Actions workflow Co-authored-by: steveward <721500+steveward@users.noreply.github.com> --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5c094b5..f434c99 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master, main ] +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest