"""Tests for cli.py — argument parsing, error handling, exit codes.""" import sys from unittest.mock import patch import pytest from cli import _print_summary, _setup_argument_parser, main from schemas import ProcessingResults class TestArgumentParser: def test_input_and_config_required(self): with pytest.raises(SystemExit): _setup_argument_parser().parse_args([]) def test_input_required(self): with pytest.raises(SystemExit): _setup_argument_parser().parse_args(['--config', 'c.json']) def test_config_required(self): with pytest.raises(SystemExit): _setup_argument_parser().parse_args(['--input', 'f.csv']) def test_minimal_args(self): args = _setup_argument_parser().parse_args( ['--input', 'f.csv', '--config', 'c.json'] ) assert args.input == 'f.csv' assert args.config == 'c.json' assert args.execute is False assert args.limit is None def test_execute_flag(self): args = _setup_argument_parser().parse_args( ['--input', 'f.csv', '--config', 'c.json', '--execute'] ) assert args.execute is True def test_all_flags(self): args = _setup_argument_parser().parse_args( [ '--input', 'f.csv', '--config', 'c.json', '--execute', '--limit', '10', '--throttle-capacity', '3', '--throttle-rate', '1.5', '--skip-if-missing', '--output', 'out.csv', '--resume', 'prev.csv', ] ) assert args.limit == 10 assert args.throttle_capacity == 3 assert args.throttle_rate == 1.5 assert args.skip_if_missing is True assert args.output == 'out.csv' assert args.resume == 'prev.csv' class TestPrintSummary: def test_runs_without_error_on_empty_results(self): _print_summary(ProcessingResults()) def test_runs_with_populated_results(self): results = ProcessingResults() results.success.append(None) # type: ignore results.errors.append(None) # type: ignore results.skipped.append(None) # type: ignore _print_summary(results) class TestMainExitCodes: def test_config_error_exits_1(self, tmp_path): bad_config = str(tmp_path / 'missing.json') with patch( 'sys.argv', ['cli', '--input', 'f.csv', '--config', bad_config], ): with pytest.raises(SystemExit) as exc_info: main() assert exc_info.value.code == 1 def test_file_not_found_exits_1(self, tmp_path): config = tmp_path / 'config.json' config.write_text( '{"bearer_token": "tok", "graphql_url": "http://x", "profile_uuid": "u"}' ) with ( patch( 'sys.argv', ['cli', '--input', '/no/such/file.csv', '--config', str(config)], ), patch('app.run', side_effect=FileNotFoundError('not found')), ): with pytest.raises(SystemExit) as exc_info: main() assert exc_info.value.code == 1 def test_keyboard_interrupt_exits_130(self, tmp_path): config = tmp_path / 'config.json' config.write_text( '{"bearer_token": "tok", "graphql_url": "http://x", "profile_uuid": "u"}' ) with ( patch( 'sys.argv', ['cli', '--input', 'f.csv', '--config', str(config)], ), patch('app.run', side_effect=KeyboardInterrupt), ): with pytest.raises(SystemExit) as exc_info: main() assert exc_info.value.code == 130