diff --git a/CHANGES b/CHANGES index 50cce62b63..b0c485a056 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,22 @@ $ pipx install --suffix=@next 'tmuxp' --pip-args '\--pre' --force - _Future release notes will be placed here_ +### Development + +- Tests: Improve parametrized test suite (#964) + + Convert remaining `pytest.mark.parametrize()` tests to `NamedTuple` fixtures: + + - Improved test maintainability and readability + - Added descriptive test IDs for better failure reporting + - Added docstrings to test fixtures + - Files updated: + - `test_cli.py`: Added `HelpTestFixture` + - `test_convert.py`: Added `ConvertTestFixture` and `ConvertJsonTestFixture` + - `test_freeze.py`: Added `FreezeTestFixture` and `FreezeOverwriteTestFixture` + - `test_import.py`: Added `ImportTestFixture`, `ImportTeamocilTestFixture`, and `ImportTmuxinatorTestFixture` + - `test_load.py`: Added `ZshAutotitleTestFixture`, `LogFileTestFixture`, `PluginVersionTestFixture`, and `PluginMissingTestFixture` + ## tmuxp 1.52.2 (2025-02-02) ### Bug fixes diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index 14e0b30da0..34524946d4 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -31,14 +31,32 @@ def test_creates_config_dir_not_exists(tmp_path: pathlib.Path) -> None: assert tmp_path.exists() +class HelpTestFixture(t.NamedTuple): + """Test fixture for help command tests.""" + + test_id: str + cli_args: list[str] + + +HELP_TEST_FIXTURES: list[HelpTestFixture] = [ + HelpTestFixture( + test_id="help_long_flag", + cli_args=["--help"], + ), + HelpTestFixture( + test_id="help_short_flag", + cli_args=["-h"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [ - (["--help"]), - (["-h"]), - ], + list(HelpTestFixture._fields), + HELP_TEST_FIXTURES, + ids=[test.test_id for test in HELP_TEST_FIXTURES], ) def test_help( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, diff --git a/tests/cli/test_convert.py b/tests/cli/test_convert.py index f57f771f77..8cafecd12c 100644 --- a/tests/cli/test_convert.py +++ b/tests/cli/test_convert.py @@ -15,17 +15,44 @@ import pathlib +class ConvertTestFixture(t.NamedTuple): + """Test fixture for tmuxp convert command tests.""" + + test_id: str + cli_args: list[str] + + +CONVERT_TEST_FIXTURES: list[ConvertTestFixture] = [ + ConvertTestFixture( + test_id="convert_current_dir", + cli_args=["convert", "."], + ), + ConvertTestFixture( + test_id="convert_yaml_file", + cli_args=["convert", ".tmuxp.yaml"], + ), + ConvertTestFixture( + test_id="convert_yaml_file_auto_confirm", + cli_args=["convert", ".tmuxp.yaml", "-y"], + ), + ConvertTestFixture( + test_id="convert_yml_file", + cli_args=["convert", ".tmuxp.yml"], + ), + ConvertTestFixture( + test_id="convert_yml_file_auto_confirm", + cli_args=["convert", ".tmuxp.yml", "-y"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [ - (["convert", "."]), - (["convert", ".tmuxp.yaml"]), - (["convert", ".tmuxp.yaml", "-y"]), - (["convert", ".tmuxp.yml"]), - (["convert", ".tmuxp.yml", "-y"]), - ], + list(ConvertTestFixture._fields), + CONVERT_TEST_FIXTURES, + ids=[test.test_id for test in CONVERT_TEST_FIXTURES], ) def test_convert( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, @@ -57,15 +84,36 @@ def test_convert( assert tmuxp_json.open().read() == json.dumps({"session_name": "hello"}, indent=2) +class ConvertJsonTestFixture(t.NamedTuple): + """Test fixture for tmuxp convert json command tests.""" + + test_id: str + cli_args: list[str] + + +CONVERT_JSON_TEST_FIXTURES: list[ConvertJsonTestFixture] = [ + ConvertJsonTestFixture( + test_id="convert_json_current_dir", + cli_args=["convert", "."], + ), + ConvertJsonTestFixture( + test_id="convert_json_file", + cli_args=["convert", ".tmuxp.json"], + ), + ConvertJsonTestFixture( + test_id="convert_json_file_auto_confirm", + cli_args=["convert", ".tmuxp.json", "-y"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [ - (["convert", "."]), - (["convert", ".tmuxp.json"]), - (["convert", ".tmuxp.json", "-y"]), - ], + list(ConvertJsonTestFixture._fields), + CONVERT_JSON_TEST_FIXTURES, + ids=[test.test_id for test in CONVERT_JSON_TEST_FIXTURES], ) def test_convert_json( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, diff --git a/tests/cli/test_freeze.py b/tests/cli/test_freeze.py index ef3a15812e..fd828dbb4a 100644 --- a/tests/cli/test_freeze.py +++ b/tests/cli/test_freeze.py @@ -17,23 +17,68 @@ from libtmux.server import Server +class FreezeTestFixture(t.NamedTuple): + """Test fixture for tmuxp freeze command tests.""" + + test_id: str + cli_args: list[str] + inputs: list[str] + + +class FreezeOverwriteTestFixture(t.NamedTuple): + """Test fixture for tmuxp freeze overwrite command tests.""" + + test_id: str + cli_args: list[str] + inputs: list[str] + + +FREEZE_TEST_FIXTURES: list[FreezeTestFixture] = [ + FreezeTestFixture( + test_id="freeze_named_session", + cli_args=["freeze", "myfrozensession"], + inputs=["y\n", "./la.yaml\n", "y\n"], + ), + FreezeTestFixture( + test_id="freeze_named_session_exists", + cli_args=["freeze", "myfrozensession"], + inputs=["y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), + FreezeTestFixture( + test_id="freeze_current_session", + cli_args=["freeze"], + inputs=["y\n", "./la.yaml\n", "y\n"], + ), + FreezeTestFixture( + test_id="freeze_current_session_exists", + cli_args=["freeze"], + inputs=["y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), +] + + +FREEZE_OVERWRITE_TEST_FIXTURES: list[FreezeOverwriteTestFixture] = [ + FreezeOverwriteTestFixture( + test_id="force_overwrite_named_session", + cli_args=["freeze", "mysession", "--force"], + inputs=["\n", "\n", "y\n", "./exists.yaml\n", "y\n"], + ), + FreezeOverwriteTestFixture( + test_id="force_overwrite_current_session", + cli_args=["freeze", "--force"], + inputs=["\n", "\n", "y\n", "./exists.yaml\n", "y\n"], + ), +] + + @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - (["freeze", "myfrozensession"], ["y\n", "./la.yaml\n", "y\n"]), - ( # Exists - ["freeze", "myfrozensession"], - ["y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], - ), - ( # Imply current session if not entered - ["freeze"], - ["y\n", "./la.yaml\n", "y\n"], - ), - (["freeze"], ["y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"]), # Exists - ], + list(FreezeTestFixture._fields), + FREEZE_TEST_FIXTURES, + ids=[test.test_id for test in FREEZE_TEST_FIXTURES], ) def test_freeze( server: Server, + test_id: str, cli_args: list[str], inputs: list[str], tmp_path: pathlib.Path, @@ -72,20 +117,13 @@ def test_freeze( @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - ( # Overwrite - ["freeze", "mysession", "--force"], - ["\n", "\n", "y\n", "./exists.yaml\n", "y\n"], - ), - ( # Imply current session if not entered - ["freeze", "--force"], - ["\n", "\n", "y\n", "./exists.yaml\n", "y\n"], - ), - ], + list(FreezeOverwriteTestFixture._fields), + FREEZE_OVERWRITE_TEST_FIXTURES, + ids=[test.test_id for test in FREEZE_OVERWRITE_TEST_FIXTURES], ) def test_freeze_overwrite( server: Server, + test_id: str, cli_args: list[str], inputs: list[str], tmp_path: pathlib.Path, diff --git a/tests/cli/test_import.py b/tests/cli/test_import.py index a3bfe71a7f..4faad8fe2c 100644 --- a/tests/cli/test_import.py +++ b/tests/cli/test_import.py @@ -15,8 +15,28 @@ import pathlib -@pytest.mark.parametrize("cli_args", [(["import"])]) +class ImportTestFixture(t.NamedTuple): + """Test fixture for basic tmuxp import command tests.""" + + test_id: str + cli_args: list[str] + + +IMPORT_TEST_FIXTURES: list[ImportTestFixture] = [ + ImportTestFixture( + test_id="basic_import", + cli_args=["import"], + ), +] + + +@pytest.mark.parametrize( + list(ImportTestFixture._fields), + IMPORT_TEST_FIXTURES, + ids=[test.test_id for test in IMPORT_TEST_FIXTURES], +) def test_import( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, @@ -29,24 +49,40 @@ def test_import( assert "teamocil" in result.out +class ImportTeamocilTestFixture(t.NamedTuple): + """Test fixture for tmuxp import teamocil command tests.""" + + test_id: str + cli_args: list[str] + inputs: list[str] + + +IMPORT_TEAMOCIL_TEST_FIXTURES: list[ImportTeamocilTestFixture] = [ + ImportTeamocilTestFixture( + test_id="import_teamocil_config_file", + cli_args=["import", "teamocil", "./.teamocil/config.yaml"], + inputs=["\n", "y\n", "./la.yaml\n", "y\n"], + ), + ImportTeamocilTestFixture( + test_id="import_teamocil_config_file_exists", + cli_args=["import", "teamocil", "./.teamocil/config.yaml"], + inputs=["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), + ImportTeamocilTestFixture( + test_id="import_teamocil_config_name", + cli_args=["import", "teamocil", "config"], + inputs=["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), +] + + @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - ( - ["import", "teamocil", "./.teamocil/config.yaml"], - ["\n", "y\n", "./la.yaml\n", "y\n"], - ), - ( - ["import", "teamocil", "./.teamocil/config.yaml"], - ["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], - ), - ( - ["import", "teamocil", "config"], - ["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], - ), - ], + list(ImportTeamocilTestFixture._fields), + IMPORT_TEAMOCIL_TEST_FIXTURES, + ids=[test.test_id for test in IMPORT_TEAMOCIL_TEST_FIXTURES], ) def test_import_teamocil( + test_id: str, cli_args: list[str], inputs: list[str], tmp_path: pathlib.Path, @@ -76,24 +112,40 @@ def test_import_teamocil( assert new_config_yaml.exists() +class ImportTmuxinatorTestFixture(t.NamedTuple): + """Test fixture for tmuxp import tmuxinator command tests.""" + + test_id: str + cli_args: list[str] + inputs: list[str] + + +IMPORT_TMUXINATOR_TEST_FIXTURES: list[ImportTmuxinatorTestFixture] = [ + ImportTmuxinatorTestFixture( + test_id="import_tmuxinator_config_file", + cli_args=["import", "tmuxinator", "./.tmuxinator/config.yaml"], + inputs=["\n", "y\n", "./la.yaml\n", "y\n"], + ), + ImportTmuxinatorTestFixture( + test_id="import_tmuxinator_config_file_exists", + cli_args=["import", "tmuxinator", "./.tmuxinator/config.yaml"], + inputs=["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), + ImportTmuxinatorTestFixture( + test_id="import_tmuxinator_config_name", + cli_args=["import", "tmuxinator", "config"], + inputs=["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], + ), +] + + @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - ( - ["import", "tmuxinator", "./.tmuxinator/config.yaml"], - ["\n", "y\n", "./la.yaml\n", "y\n"], - ), - ( - ["import", "tmuxinator", "./.tmuxinator/config.yaml"], - ["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], - ), - ( - ["import", "tmuxinator", "config"], - ["\n", "y\n", "./exists.yaml\n", "./la.yaml\n", "y\n"], - ), - ], + list(ImportTmuxinatorTestFixture._fields), + IMPORT_TMUXINATOR_TEST_FIXTURES, + ids=[test.test_id for test in IMPORT_TMUXINATOR_TEST_FIXTURES], ) def test_import_tmuxinator( + test_id: str, cli_args: list[str], inputs: list[str], tmp_path: pathlib.Path, diff --git a/tests/cli/test_load.py b/tests/cli/test_load.py index 95925a1dd9..da473b9543 100644 --- a/tests/cli/test_load.py +++ b/tests/cli/test_load.py @@ -359,18 +359,39 @@ def test_regression_00132_session_name_with_dots( cli.cli(["load", *cli_args]) +class ZshAutotitleTestFixture(t.NamedTuple): + """Test fixture for zsh auto title warning tests.""" + + test_id: str + cli_args: list[str] + + +ZSH_AUTOTITLE_TEST_FIXTURES: list[ZshAutotitleTestFixture] = [ + ZshAutotitleTestFixture( + test_id="load_dot_detached", + cli_args=["load", ".", "-d"], + ), + ZshAutotitleTestFixture( + test_id="load_yaml_detached", + cli_args=["load", ".tmuxp.yaml", "-d"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [["load", ".", "-d"], ["load", ".tmuxp.yaml", "-d"]], + list(ZshAutotitleTestFixture._fields), + ZSH_AUTOTITLE_TEST_FIXTURES, + ids=[test.test_id for test in ZSH_AUTOTITLE_TEST_FIXTURES], ) def test_load_zsh_autotitle_warning( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], server: Server, ) -> None: - """Test loading ZSH without DISABLE_AUTO_TITLE raises warning.""" + """Test warning when ZSH auto title is enabled.""" # create dummy tmuxp yaml so we don't get yelled at yaml_config = tmp_path / ".tmuxp.yaml" yaml_config.write_text( @@ -417,19 +438,34 @@ def test_load_zsh_autotitle_warning( assert "Please set" not in result.out +class LogFileTestFixture(t.NamedTuple): + """Test fixture for log file tests.""" + + test_id: str + cli_args: list[str] + + +LOG_FILE_TEST_FIXTURES: list[LogFileTestFixture] = [ + LogFileTestFixture( + test_id="load_with_log_file", + cli_args=["load", ".", "--log-file", "log.txt", "-d"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [ - (["load", ".", "--log-file", "log.txt", "-d"]), - ], + list(LogFileTestFixture._fields), + LOG_FILE_TEST_FIXTURES, + ids=[test.test_id for test in LOG_FILE_TEST_FIXTURES], ) def test_load_log_file( + test_id: str, cli_args: list[str], tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], ) -> None: - """Test loading via tmuxp load with --log-file.""" + """Test loading with a log file.""" # create dummy tmuxp yaml that breaks to prevent actually loading tmux tmuxp_config_path = tmp_path / ".tmuxp.yaml" tmuxp_config_path.write_text( @@ -478,23 +514,37 @@ def test_load_plugins( assert plugin.__class__ in test_plugin_class_types +class PluginVersionTestFixture(t.NamedTuple): + """Test fixture for plugin version tests.""" + + test_id: str + cli_args: list[str] + inputs: list[str] + + +PLUGIN_VERSION_SKIP_TEST_FIXTURES: list[PluginVersionTestFixture] = [ + PluginVersionTestFixture( + test_id="skip_version_fail", + cli_args=["load", "tests/fixtures/workspace/builder/plugin_versions_fail.yaml"], + inputs=["y\n"], + ), +] + + @pytest.mark.skip("Not sure how to clean up the tmux session this makes") @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - ( - ["load", "tests/fixtures/workspace/builder/plugin_versions_fail.yaml"], - ["y\n"], - ), - ], + list(PluginVersionTestFixture._fields), + PLUGIN_VERSION_SKIP_TEST_FIXTURES, + ids=[test.test_id for test in PLUGIN_VERSION_SKIP_TEST_FIXTURES], ) def test_load_plugins_version_fail_skip( monkeypatch_plugin_test_packages: None, + test_id: str, cli_args: list[str], inputs: list[str], capsys: pytest.CaptureFixture[str], ) -> None: - """Test tmuxp load with plugins failing version constraints can continue.""" + """Test plugin version failure with skip.""" with contextlib.suppress(SystemExit): cli.cli(cli_args) @@ -503,23 +553,29 @@ def test_load_plugins_version_fail_skip( assert "[Loading]" in result.out +PLUGIN_VERSION_NO_SKIP_TEST_FIXTURES: list[PluginVersionTestFixture] = [ + PluginVersionTestFixture( + test_id="no_skip_version_fail", + cli_args=["load", "tests/fixtures/workspace/builder/plugin_versions_fail.yaml"], + inputs=["n\n"], + ), +] + + @pytest.mark.parametrize( - ("cli_args", "inputs"), - [ - ( - ["load", "tests/fixtures/workspace/builder/plugin_versions_fail.yaml"], - ["n\n"], - ), - ], + list(PluginVersionTestFixture._fields), + PLUGIN_VERSION_NO_SKIP_TEST_FIXTURES, + ids=[test.test_id for test in PLUGIN_VERSION_NO_SKIP_TEST_FIXTURES], ) def test_load_plugins_version_fail_no_skip( monkeypatch_plugin_test_packages: None, + test_id: str, cli_args: list[str], inputs: list[str], monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], ) -> None: - """Test tmuxp load with plugins failing version constraints can exit.""" + """Test plugin version failure without skip.""" monkeypatch.setattr("sys.stdin", io.StringIO("".join(inputs))) with contextlib.suppress(SystemExit): @@ -530,16 +586,33 @@ def test_load_plugins_version_fail_no_skip( assert "[Not Skipping]" in result.out +class PluginMissingTestFixture(t.NamedTuple): + """Test fixture for plugin missing tests.""" + + test_id: str + cli_args: list[str] + + +PLUGIN_MISSING_TEST_FIXTURES: list[PluginMissingTestFixture] = [ + PluginMissingTestFixture( + test_id="missing_plugin", + cli_args=["load", "tests/fixtures/workspace/builder/plugin_missing_fail.yaml"], + ), +] + + @pytest.mark.parametrize( - "cli_args", - [(["load", "tests/fixtures/workspace/builder/plugin_missing_fail.yaml"])], + list(PluginMissingTestFixture._fields), + PLUGIN_MISSING_TEST_FIXTURES, + ids=[test.test_id for test in PLUGIN_MISSING_TEST_FIXTURES], ) def test_load_plugins_plugin_missing( monkeypatch_plugin_test_packages: None, + test_id: str, cli_args: list[str], capsys: pytest.CaptureFixture[str], ) -> None: - """Test tmuxp load with plugins missing raise an error.""" + """Test loading with missing plugin.""" with contextlib.suppress(SystemExit): cli.cli(cli_args) diff --git a/tests/cli/test_shell.py b/tests/cli/test_shell.py index 65ad67b2ef..79e130e493 100644 --- a/tests/cli/test_shell.py +++ b/tests/cli/test_shell.py @@ -25,6 +25,7 @@ class CLIShellFixture(t.NamedTuple): test_id: str # test params + cli_cmd: list[str] cli_args: list[str] inputs: list[t.Any] env: dict[str, str] @@ -32,8 +33,10 @@ class CLIShellFixture(t.NamedTuple): TEST_SHELL_FIXTURES: list[CLIShellFixture] = [ + # Regular shell command CLIShellFixture( test_id="print-socket-name", + cli_cmd=["shell"], cli_args=["-L{SOCKET_NAME}", "-c", "print(str(server.socket_name))"], inputs=[], env={}, @@ -41,6 +44,7 @@ class CLIShellFixture(t.NamedTuple): ), CLIShellFixture( test_id="print-session-name", + cli_cmd=["shell"], cli_args=[ "-L{SOCKET_NAME}", "{SESSION_NAME}", @@ -53,6 +57,7 @@ class CLIShellFixture(t.NamedTuple): ), CLIShellFixture( test_id="print-has-session", + cli_cmd=["shell"], cli_args=[ "-L{SOCKET_NAME}", "{SESSION_NAME}", @@ -66,6 +71,7 @@ class CLIShellFixture(t.NamedTuple): ), CLIShellFixture( test_id="print-window-name", + cli_cmd=["shell"], cli_args=[ "-L{SOCKET_NAME}", "{SESSION_NAME}", @@ -79,6 +85,7 @@ class CLIShellFixture(t.NamedTuple): ), CLIShellFixture( test_id="print-pane-id", + cli_cmd=["shell"], cli_args=[ "-L{SOCKET_NAME}", "{SESSION_NAME}", @@ -92,6 +99,83 @@ class CLIShellFixture(t.NamedTuple): ), CLIShellFixture( test_id="print-pane-id-obeys-tmux-pane-env-var", + cli_cmd=["shell"], + cli_args=[ + "-L{SOCKET_NAME}", + "-c", + "print(pane.id)", + ], + inputs=[], + env={"TMUX_PANE": "{PANE_ID}"}, + expected_output="{PANE_ID}", + ), + # Shell with --pdb + CLIShellFixture( + test_id="print-socket-name-pdb", + cli_cmd=["shell", "--pdb"], + cli_args=["-L{SOCKET_NAME}", "-c", "print(str(server.socket_name))"], + inputs=[], + env={}, + expected_output="{SERVER_SOCKET_NAME}", + ), + CLIShellFixture( + test_id="print-session-name-pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "-c", + "print(session.name)", + ], + inputs=[], + env={}, + expected_output="{SESSION_NAME}", + ), + CLIShellFixture( + test_id="print-has-session-pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "{WINDOW_NAME}", + "-c", + "print(server.has_session(session.name))", + ], + inputs=[], + env={}, + expected_output="True", + ), + CLIShellFixture( + test_id="print-window-name-pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "{WINDOW_NAME}", + "-c", + "print(window.name)", + ], + inputs=[], + env={}, + expected_output="{WINDOW_NAME}", + ), + CLIShellFixture( + test_id="print-pane-id-pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "{WINDOW_NAME}", + "-c", + "print(pane.id)", + ], + inputs=[], + env={}, + expected_output="{PANE_ID}", + ), + CLIShellFixture( + test_id="print-pane-id-obeys-tmux-pane-env-var-pdb", + cli_cmd=["shell", "--pdb"], cli_args=[ "-L{SOCKET_NAME}", "-c", @@ -104,15 +188,14 @@ class CLIShellFixture(t.NamedTuple): ] -@pytest.mark.parametrize("cli_cmd", [["shell"], ["shell", "--pdb"]]) @pytest.mark.parametrize( list(CLIShellFixture._fields), TEST_SHELL_FIXTURES, ids=[test.test_id for test in TEST_SHELL_FIXTURES], ) def test_shell( - cli_cmd: list[str], test_id: str, + cli_cmd: list[str], cli_args: list[str], inputs: list[t.Any], env: dict[str, str], @@ -151,54 +234,114 @@ def test_shell( assert expected_output.format(**template_ctx) in result.out +class CLIShellTargetMissingFixture(t.NamedTuple): + """Test fixture for tmuxp shell target missing tests.""" + + test_id: str + cli_cmd: list[str] + cli_args: list[str] + inputs: list[t.Any] + env: dict[t.Any, t.Any] + template_ctx: dict[str, str] + exception: type[exc.TmuxpException | subprocess.CalledProcessError] + message: str + + +TEST_SHELL_TARGET_MISSING_FIXTURES: list[CLIShellTargetMissingFixture] = [ + # Regular shell command + CLIShellTargetMissingFixture( + test_id="nonexistent_socket", + cli_cmd=["shell"], + cli_args=["-LDoesNotExist", "-c", "print(str(server.socket_name))"], + inputs=[], + env={}, + template_ctx={}, + exception=subprocess.CalledProcessError, + message=r".*DoesNotExist.*", + ), + CLIShellTargetMissingFixture( + test_id="nonexistent_session", + cli_cmd=["shell"], + cli_args=[ + "-L{SOCKET_NAME}", + "nonexistent_session", + "-c", + "print(str(server.socket_name))", + ], + inputs=[], + env={}, + template_ctx={"session_name": "nonexistent_session"}, + exception=exc.TmuxpException, + message="Session not found: nonexistent_session", + ), + CLIShellTargetMissingFixture( + test_id="nonexistent_window", + cli_cmd=["shell"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "nonexistent_window", + "-c", + "print(str(server.socket_name))", + ], + inputs=[], + env={}, + template_ctx={"window_name": "nonexistent_window"}, + exception=exc.TmuxpException, + message="Window not found: {WINDOW_NAME}", + ), + # Shell with --pdb + CLIShellTargetMissingFixture( + test_id="nonexistent_socket_pdb", + cli_cmd=["shell", "--pdb"], + cli_args=["-LDoesNotExist", "-c", "print(str(server.socket_name))"], + inputs=[], + env={}, + template_ctx={}, + exception=subprocess.CalledProcessError, + message=r".*DoesNotExist.*", + ), + CLIShellTargetMissingFixture( + test_id="nonexistent_session_pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "nonexistent_session", + "-c", + "print(str(server.socket_name))", + ], + inputs=[], + env={}, + template_ctx={"session_name": "nonexistent_session"}, + exception=exc.TmuxpException, + message="Session not found: nonexistent_session", + ), + CLIShellTargetMissingFixture( + test_id="nonexistent_window_pdb", + cli_cmd=["shell", "--pdb"], + cli_args=[ + "-L{SOCKET_NAME}", + "{SESSION_NAME}", + "nonexistent_window", + "-c", + "print(str(server.socket_name))", + ], + inputs=[], + env={}, + template_ctx={"window_name": "nonexistent_window"}, + exception=exc.TmuxpException, + message="Window not found: {WINDOW_NAME}", + ), +] + + @pytest.mark.parametrize( - "cli_cmd", - [ - ["shell"], - ["shell", "--pdb"], - ], -) -@pytest.mark.parametrize( - ("cli_args", "inputs", "env", "template_ctx", "exception", "message"), - [ - ( - ["-LDoesNotExist", "-c", "print(str(server.socket_name))"], - [], - {}, - {}, - subprocess.CalledProcessError, - r".*DoesNotExist.*", - ), - ( - [ - "-L{SOCKET_NAME}", - "nonexistent_session", - "-c", - "print(str(server.socket_name))", - ], - [], - {}, - {"session_name": "nonexistent_session"}, - exc.TmuxpException, - "Session not found: nonexistent_session", - ), - ( - [ - "-L{SOCKET_NAME}", - "{SESSION_NAME}", - "nonexistent_window", - "-c", - "print(str(server.socket_name))", - ], - [], - {}, - {"window_name": "nonexistent_window"}, - exc.TmuxpException, - "Window not found: {WINDOW_NAME}", - ), - ], + list(CLIShellTargetMissingFixture._fields), + TEST_SHELL_TARGET_MISSING_FIXTURES, + ids=[test.test_id for test in TEST_SHELL_TARGET_MISSING_FIXTURES], ) def test_shell_target_missing( + test_id: str, cli_cmd: list[str], cli_args: list[str], inputs: list[t.Any], @@ -206,7 +349,6 @@ def test_shell_target_missing( template_ctx: dict[str, str], exception: type[exc.TmuxpException | subprocess.CalledProcessError], message: str, - socket_name: str, server: Server, session: Session, tmp_path: pathlib.Path, @@ -245,40 +387,48 @@ def test_shell_target_missing( assert message.format(**template_ctx) in result.out +class CLIShellInteractiveFixture(t.NamedTuple): + """Test fixture for tmuxp shell interactive tests.""" + + test_id: str + cli_cmd: list[str] + cli_args: list[str] + inputs: list[t.Any] + env: dict[str, str] + message: str + + +TEST_SHELL_INTERACTIVE_FIXTURES: list[CLIShellInteractiveFixture] = [ + CLIShellInteractiveFixture( + test_id="basic_interactive", + cli_cmd=["shell", "--code"], + cli_args=[ + "-L{SOCKET_NAME}", + ], + inputs=[], + env={}, + message="(InteractiveConsole)", + ), + CLIShellInteractiveFixture( + test_id="interactive_with_pane_id", + cli_cmd=["shell", "--code"], + cli_args=[ + "-L{SOCKET_NAME}", + ], + inputs=[], + env={"PANE_ID": "{PANE_ID}"}, + message="(InteractiveConsole)", + ), +] + + @pytest.mark.parametrize( - "cli_cmd", - [ - # ['shell'], - # ['shell', '--pdb'), - ["shell", "--code"], - # ['shell', '--bpython'], - # ['shell', '--ptipython'], - # ['shell', '--ptpython'], - # ['shell', '--ipython'], - ], -) -@pytest.mark.parametrize( - ("cli_args", "inputs", "env", "message"), - [ - ( - [ - "-L{SOCKET_NAME}", - ], - [], - {}, - "(InteractiveConsole)", - ), - ( - [ - "-L{SOCKET_NAME}", - ], - [], - {"PANE_ID": "{PANE_ID}"}, - "(InteractiveConsole)", - ), - ], + list(CLIShellInteractiveFixture._fields), + TEST_SHELL_INTERACTIVE_FIXTURES, + ids=[test.test_id for test in TEST_SHELL_INTERACTIVE_FIXTURES], ) def test_shell_interactive( + test_id: str, cli_cmd: list[str], cli_args: list[str], inputs: list[t.Any], diff --git a/tests/test_util.py b/tests/test_util.py index 6585169719..896912b7d7 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -51,17 +51,38 @@ def temp_script(tmp_path: pathlib.Path) -> pathlib.Path: return script +class TTYTestFixture(t.NamedTuple): + """Test fixture for isatty behavior verification.""" + + test_id: str + isatty_value: bool + expected_output: str + + +TTY_TEST_FIXTURES: list[TTYTestFixture] = [ + TTYTestFixture( + test_id="tty_enabled_shows_output", + isatty_value=True, + expected_output="Hello, World!", + ), + TTYTestFixture( + test_id="tty_disabled_suppresses_output", + isatty_value=False, + expected_output="", + ), +] + + @pytest.mark.parametrize( - ["isatty_value", "expected_output"], - [ - (True, "Hello, World!"), # if stdout is a TTY, output should be passed through - (False, ""), # if not a TTY, output is not written to sys.stdout - ], + list(TTYTestFixture._fields), + TTY_TEST_FIXTURES, + ids=[test.test_id for test in TTY_TEST_FIXTURES], ) def test_run_before_script_isatty( temp_script: pathlib.Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], + test_id: str, isatty_value: bool, expected_output: str, ) -> None: diff --git a/tests/workspace/test_builder.py b/tests/workspace/test_builder.py index 99115e6da1..a888a1ca56 100644 --- a/tests/workspace/test_builder.py +++ b/tests/workspace/test_builder.py @@ -1099,25 +1099,34 @@ def test_find_current_active_pane( assert builder.find_current_attached_session() == second_session -@pytest.mark.parametrize( - ("yaml", "output", "should_see"), - [ - ( - textwrap.dedent( - """ +class WorkspaceEnterFixture(t.NamedTuple): + """Test fixture for workspace enter behavior verification.""" + + test_id: str + yaml: str + output: str + should_see: bool + + +WORKSPACE_ENTER_FIXTURES: list[WorkspaceEnterFixture] = [ + WorkspaceEnterFixture( + test_id="pane_enter_false_shortform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: - shell_command: echo "___$((1 + 3))___" enter: false """, - ), - "___4___", - False, ), - ( - textwrap.dedent( - """ + output="___4___", + should_see=False, + ), + WorkspaceEnterFixture( + test_id="pane_enter_false_longform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1125,38 +1134,41 @@ def test_find_current_active_pane( - echo "___$((1 + 3))___" enter: false """, - ), - "___4___", - False, ), - ( - textwrap.dedent( - """ + output="___4___", + should_see=False, + ), + WorkspaceEnterFixture( + test_id="pane_enter_default_shortform", + yaml=textwrap.dedent( + """ session_name: Should execute windows: - panes: - shell_command: echo "___$((1 + 3))___" """, - ), - "___4___", - True, ), - ( - textwrap.dedent( - """ + output="___4___", + should_see=True, + ), + WorkspaceEnterFixture( + test_id="pane_enter_default_longform", + yaml=textwrap.dedent( + """ session_name: Should execute windows: - panes: - shell_command: - echo "___$((1 + 3))___" """, - ), - "___4___", - True, ), - ( - textwrap.dedent( - """ + output="___4___", + should_see=True, + ), + WorkspaceEnterFixture( + test_id="pane_command_enter_false_shortform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1164,13 +1176,14 @@ def test_find_current_active_pane( - cmd: echo "___$((1 + 3))___" enter: false """, - ), - "___4___", - False, ), - ( # NOQA: PT014 RUF100 - textwrap.dedent( - """ + output="___4___", + should_see=False, + ), + WorkspaceEnterFixture( # NOQA: PT014 RUF100 + test_id="pane_command_enter_false_longform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1178,25 +1191,27 @@ def test_find_current_active_pane( - cmd: echo "___$((1 + 3))___" enter: false """, - ), - "___4___", - False, ), - ( # NOQA: PT014 RUF100 - textwrap.dedent( - """ + output="___4___", + should_see=False, + ), + WorkspaceEnterFixture( # NOQA: PT014 RUF100 + test_id="pane_command_enter_default_shortform", + yaml=textwrap.dedent( + """ session_name: Should execute windows: - panes: - shell_command: echo "___$((1 + 3))___" """, - ), - "___4___", - True, ), - ( - textwrap.dedent( - """ + output="___4___", + should_see=True, + ), + WorkspaceEnterFixture( + test_id="pane_command_enter_default_longform", + yaml=textwrap.dedent( + """ session_name: Should execute windows: - panes: @@ -1204,26 +1219,23 @@ def test_find_current_active_pane( - cmd: echo "other command" - cmd: echo "___$((1 + 3))___" """, - ), - "___4___", - True, ), - ], - ids=[ - "pane_enter_false_shortform", - "pane_enter_false_longform", - "pane_enter_default_shortform", - "pane_enter_default_longform", - "pane_command_enter_false_shortform", - "pane_command_enter_false_longform", - "pane_command_enter_default_shortform", - "pane_command_enter_default_longform", - ], + output="___4___", + should_see=True, + ), +] + + +@pytest.mark.parametrize( + list(WorkspaceEnterFixture._fields), + WORKSPACE_ENTER_FIXTURES, + ids=[test.test_id for test in WORKSPACE_ENTER_FIXTURES], ) def test_load_workspace_enter( tmp_path: pathlib.Path, server: Server, monkeypatch: pytest.MonkeyPatch, + test_id: str, yaml: str, output: str, should_see: bool, @@ -1255,12 +1267,20 @@ def fn() -> bool: ), f"Should{' ' if should_see else 'not '} output in captured pane" -@pytest.mark.parametrize( - ("yaml", "sleep", "output"), - [ - ( - textwrap.dedent( - """ +class WorkspaceSleepFixture(t.NamedTuple): + """Test fixture for workspace sleep behavior verification.""" + + test_id: str + yaml: str + sleep: float + output: str + + +WORKSPACE_SLEEP_FIXTURES: list[WorkspaceSleepFixture] = [ + WorkspaceSleepFixture( + test_id="command_level_sleep_shortform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1270,13 +1290,14 @@ def fn() -> bool: - cmd: echo "___$((1 + 3))___" sleep_before: .35 """, - ), - 0.5, - "___4___", ), - ( - textwrap.dedent( - """ + sleep=0.5, + output="___4___", + ), + WorkspaceSleepFixture( + test_id="command_level_pane_sleep_longform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1286,13 +1307,14 @@ def fn() -> bool: - cmd: echo "___$((1 + 3))___" sleep_before: .25 """, - ), - 1.25, - "___4___", ), - ( - textwrap.dedent( - """ + sleep=1.25, + output="___4___", + ), + WorkspaceSleepFixture( + test_id="pane_sleep_shortform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1300,13 +1322,14 @@ def fn() -> bool: - cmd: echo "___$((1 + 3))___" sleep_before: .5 """, - ), - 0.5, - "___4___", ), - ( - textwrap.dedent( - """ + sleep=0.5, + output="___4___", + ), + WorkspaceSleepFixture( + test_id="pane_sleep_longform", + yaml=textwrap.dedent( + """ session_name: Should not execute windows: - panes: @@ -1314,13 +1337,14 @@ def fn() -> bool: - cmd: echo "___$((1 + 3))___" sleep_before: 1 """, - ), - 1, - "___4___", ), - ( - textwrap.dedent( - """ + sleep=1, + output="___4___", + ), + WorkspaceSleepFixture( + test_id="shell_before_before_command_level", + yaml=textwrap.dedent( + """ session_name: Should not execute shell_command_before: - cmd: echo "sleeping before" @@ -1329,26 +1353,26 @@ def fn() -> bool: - panes: - echo "___$((1 + 3))___" """, - ), - 0.5, - "___4___", ), - ], - ids=[ - "command_level_sleep_shortform", - "command_level_pane_sleep_longform", - "pane_sleep_shortform", - "pane_sleep_longform", - "shell_before_before_command_level", - ], + sleep=0.5, + output="___4___", + ), +] + + +@pytest.mark.parametrize( + list(WorkspaceSleepFixture._fields), + WORKSPACE_SLEEP_FIXTURES, + ids=[test.test_id for test in WORKSPACE_SLEEP_FIXTURES], ) @pytest.mark.flaky(reruns=3) def test_load_workspace_sleep( tmp_path: pathlib.Path, server: Server, monkeypatch: pytest.MonkeyPatch, + test_id: str, yaml: str, - sleep: int, + sleep: float, output: str, ) -> None: """Test sleep commands in tmuxp configuration.""" diff --git a/tests/workspace/test_finder.py b/tests/workspace/test_finder.py index 862389e29c..20aee8703a 100644 --- a/tests/workspace/test_finder.py +++ b/tests/workspace/test_finder.py @@ -63,23 +63,83 @@ def test_get_configs_cwd( assert ".tmuxp.json" in configs_found +class PureNameTestFixture(t.NamedTuple): + """Test fixture for verifying pure name path validation.""" + + test_id: str + path: str + expect: bool + + +PURE_NAME_TEST_FIXTURES: list[PureNameTestFixture] = [ + PureNameTestFixture( + test_id="current_dir", + path=".", + expect=False, + ), + PureNameTestFixture( + test_id="current_dir_slash", + path="./", + expect=False, + ), + PureNameTestFixture( + test_id="empty_path", + path="", + expect=False, + ), + PureNameTestFixture( + test_id="tmuxp_yaml", + path=".tmuxp.yaml", + expect=False, + ), + PureNameTestFixture( + test_id="parent_tmuxp_yaml", + path="../.tmuxp.yaml", + expect=False, + ), + PureNameTestFixture( + test_id="parent_dir", + path="../", + expect=False, + ), + PureNameTestFixture( + test_id="absolute_path", + path="/hello/world", + expect=False, + ), + PureNameTestFixture( + test_id="home_tmuxp_path", + path="~/.tmuxp/hey", + expect=False, + ), + PureNameTestFixture( + test_id="home_work_path", + path="~/work/c/tmux/", + expect=False, + ), + PureNameTestFixture( + test_id="home_work_tmuxp_yaml", + path="~/work/c/tmux/.tmuxp.yaml", + expect=False, + ), + PureNameTestFixture( + test_id="pure_name", + path="myproject", + expect=True, + ), +] + + @pytest.mark.parametrize( - ("path", "expect"), - [ - (".", False), - ("./", False), - ("", False), - (".tmuxp.yaml", False), - ("../.tmuxp.yaml", False), - ("../", False), - ("/hello/world", False), - ("~/.tmuxp/hey", False), - ("~/work/c/tmux/", False), - ("~/work/c/tmux/.tmuxp.yaml", False), - ("myproject", True), - ], + list(PureNameTestFixture._fields), + PURE_NAME_TEST_FIXTURES, + ids=[test.test_id for test in PURE_NAME_TEST_FIXTURES], ) -def test_is_pure_name(path: str, expect: bool) -> None: +def test_is_pure_name( + test_id: str, + path: str, + expect: bool, +) -> None: """Test is_pure_name() is truthy when file, not directory or config alias.""" assert is_pure_name(path) == expect diff --git a/tests/workspace/test_import_teamocil.py b/tests/workspace/test_import_teamocil.py index d86a305bc2..7de727684b 100644 --- a/tests/workspace/test_import_teamocil.py +++ b/tests/workspace/test_import_teamocil.py @@ -11,32 +11,50 @@ from tmuxp.workspace import importers, validation +class TeamocilConfigTestFixture(t.NamedTuple): + """Test fixture for teamocil config conversion tests.""" + + test_id: str + teamocil_yaml: str + teamocil_dict: dict[str, t.Any] + tmuxp_dict: dict[str, t.Any] + + +TEAMOCIL_CONFIG_TEST_FIXTURES: list[TeamocilConfigTestFixture] = [ + TeamocilConfigTestFixture( + test_id="test1", + teamocil_yaml=fixtures.test1.teamocil_yaml, + teamocil_dict=fixtures.test1.teamocil_conf, + tmuxp_dict=fixtures.test1.expected, + ), + TeamocilConfigTestFixture( + test_id="test2", + teamocil_yaml=fixtures.test2.teamocil_yaml, + teamocil_dict=fixtures.test2.teamocil_dict, + tmuxp_dict=fixtures.test2.expected, + ), + TeamocilConfigTestFixture( + test_id="test3", + teamocil_yaml=fixtures.test3.teamocil_yaml, + teamocil_dict=fixtures.test3.teamocil_dict, + tmuxp_dict=fixtures.test3.expected, + ), + TeamocilConfigTestFixture( + test_id="test4", + teamocil_yaml=fixtures.test4.teamocil_yaml, + teamocil_dict=fixtures.test4.teamocil_dict, + tmuxp_dict=fixtures.test4.expected, + ), +] + + @pytest.mark.parametrize( - ("teamocil_yaml", "teamocil_dict", "tmuxp_dict"), - [ - ( - fixtures.test1.teamocil_yaml, - fixtures.test1.teamocil_conf, - fixtures.test1.expected, - ), - ( - fixtures.test2.teamocil_yaml, - fixtures.test2.teamocil_dict, - fixtures.test2.expected, - ), - ( - fixtures.test3.teamocil_yaml, - fixtures.test3.teamocil_dict, - fixtures.test3.expected, - ), - ( - fixtures.test4.teamocil_yaml, - fixtures.test4.teamocil_dict, - fixtures.test4.expected, - ), - ], + list(TeamocilConfigTestFixture._fields), + TEAMOCIL_CONFIG_TEST_FIXTURES, + ids=[test.test_id for test in TEAMOCIL_CONFIG_TEST_FIXTURES], ) def test_config_to_dict( + test_id: str, teamocil_yaml: str, teamocil_dict: dict[str, t.Any], tmuxp_dict: dict[str, t.Any], @@ -71,22 +89,45 @@ def multisession_config() -> dict[ return teamocil_dict +class TeamocilMultiSessionTestFixture(t.NamedTuple): + """Test fixture for teamocil multisession config tests.""" + + test_id: str + session_name: str + expected: dict[str, t.Any] + + +TEAMOCIL_MULTISESSION_TEST_FIXTURES: list[TeamocilMultiSessionTestFixture] = [ + TeamocilMultiSessionTestFixture( + test_id="basic_two_windows", + session_name="two-windows", + expected=fixtures.layouts.two_windows, + ), + TeamocilMultiSessionTestFixture( + test_id="two_windows_with_filters", + session_name="two-windows-with-filters", + expected=fixtures.layouts.two_windows_with_filters, + ), + TeamocilMultiSessionTestFixture( + test_id="two_windows_with_custom_command_options", + session_name="two-windows-with-custom-command-options", + expected=fixtures.layouts.two_windows_with_custom_command_options, + ), + TeamocilMultiSessionTestFixture( + test_id="three_windows_within_session", + session_name="three-windows-within-a-session", + expected=fixtures.layouts.three_windows_within_a_session, + ), +] + + @pytest.mark.parametrize( - ("session_name", "expected"), - [ - ("two-windows", fixtures.layouts.two_windows), - ("two-windows-with-filters", fixtures.layouts.two_windows_with_filters), - ( - "two-windows-with-custom-command-options", - fixtures.layouts.two_windows_with_custom_command_options, - ), - ( - "three-windows-within-a-session", - fixtures.layouts.three_windows_within_a_session, - ), - ], + list(TeamocilMultiSessionTestFixture._fields), + TEAMOCIL_MULTISESSION_TEST_FIXTURES, + ids=[test.test_id for test in TEAMOCIL_MULTISESSION_TEST_FIXTURES], ) def test_multisession_config( + test_id: str, session_name: str, expected: dict[str, t.Any], multisession_config: dict[str, t.Any], diff --git a/tests/workspace/test_import_tmuxinator.py b/tests/workspace/test_import_tmuxinator.py index e6443e3204..23f567ae5d 100644 --- a/tests/workspace/test_import_tmuxinator.py +++ b/tests/workspace/test_import_tmuxinator.py @@ -11,27 +11,44 @@ from tmuxp.workspace import importers, validation +class TmuxinatorConfigTestFixture(t.NamedTuple): + """Test fixture for tmuxinator config conversion tests.""" + + test_id: str + tmuxinator_yaml: str + tmuxinator_dict: dict[str, t.Any] + tmuxp_dict: dict[str, t.Any] + + +TMUXINATOR_CONFIG_TEST_FIXTURES: list[TmuxinatorConfigTestFixture] = [ + TmuxinatorConfigTestFixture( + test_id="basic_config", + tmuxinator_yaml=fixtures.test1.tmuxinator_yaml, + tmuxinator_dict=fixtures.test1.tmuxinator_dict, + tmuxp_dict=fixtures.test1.expected, + ), + TmuxinatorConfigTestFixture( + test_id="legacy_tabs_config", # older vers use `tabs` instead of `windows` + tmuxinator_yaml=fixtures.test2.tmuxinator_yaml, + tmuxinator_dict=fixtures.test2.tmuxinator_dict, + tmuxp_dict=fixtures.test2.expected, + ), + TmuxinatorConfigTestFixture( + test_id="sample_config", # Test importing + tmuxinator_yaml=fixtures.test3.tmuxinator_yaml, + tmuxinator_dict=fixtures.test3.tmuxinator_dict, + tmuxp_dict=fixtures.test3.expected, + ), +] + + @pytest.mark.parametrize( - ("tmuxinator_yaml", "tmuxinator_dict", "tmuxp_dict"), - [ - ( - fixtures.test1.tmuxinator_yaml, - fixtures.test1.tmuxinator_dict, - fixtures.test1.expected, - ), - ( - fixtures.test2.tmuxinator_yaml, - fixtures.test2.tmuxinator_dict, - fixtures.test2.expected, - ), # older vers use `tabs` instead of `windows` - ( - fixtures.test3.tmuxinator_yaml, - fixtures.test3.tmuxinator_dict, - fixtures.test3.expected, - ), # Test importing - ], + list(TmuxinatorConfigTestFixture._fields), + TMUXINATOR_CONFIG_TEST_FIXTURES, + ids=[test.test_id for test in TMUXINATOR_CONFIG_TEST_FIXTURES], ) def test_config_to_dict( + test_id: str, tmuxinator_yaml: str, tmuxinator_dict: dict[str, t.Any], tmuxp_dict: dict[str, t.Any],