From 9250d73d2fa3db0669059b236837bde6770362ea Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Fri, 30 Jan 2026 15:34:15 +0000 Subject: [PATCH] Initial upload: gitignore-generator-cli v1.0.0 with CI/CD workflow --- tests/test_cli.py | 227 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 tests/test_cli.py diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..207cf2d --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,227 @@ +"""Tests for cli.py.""" + +import tempfile +import os +from pathlib import Path +from unittest.mock import patch, MagicMock + +import pytest +from click.testing import CliRunner + +from gitignore_generator.cli import main, generate, detect, list, show, cache, clear_cache + + +class TestCLI: + """Tests for CLI commands.""" + + @pytest.fixture + def runner(self): + """Create CLI runner.""" + return CliRunner() + + @pytest.fixture + def temp_dir(self): + """Create temporary directory.""" + with tempfile.TemporaryDirectory() as tmpdir: + yield Path(tmpdir) + + def test_main_help(self, runner): + """Test main help command.""" + result = runner.invoke(main, ['--help']) + assert result.exit_code == 0 + assert 'generate' in result.output + assert 'detect' in result.output + assert 'list' in result.output + + def test_generate_help(self, runner): + """Test generate help.""" + result = runner.invoke(generate, ['--help']) + assert result.exit_code == 0 + assert 'TECH' in result.output + assert '--output' in result.output + assert '--preview' in result.output + + def test_generate_single_tech(self, runner): + """Test generating gitignore for single tech.""" + with patch('gitignore_generator.api.get_patterns') as mock: + mock.return_value = '__pycache__/\n*.pyc\n' + result = runner.invoke(generate, ['python', '--preview']) + + assert result.exit_code == 0 + assert '__pycache__' in result.output + + def test_generate_multiple_techs(self, runner): + """Test generating gitignore for multiple techs.""" + with patch('gitignore_generator.api.get_patterns') as mock: + def side_effect(tech, force=False): + if tech == 'node': + return 'node_modules/\n' + elif tech == 'python': + return '__pycache__/\n' + return '' + mock.side_effect = side_effect + result = runner.invoke(generate, ['node', 'python', '--preview']) + + assert result.exit_code == 0 + assert 'node_modules' in result.output + assert '__pycache__' in result.output + + def test_generate_to_file(self, runner, temp_dir): + """Test generating gitignore to file.""" + output_path = temp_dir / '.gitignore' + + with patch('gitignore_generator.api.get_patterns') as mock: + mock.return_value = '__pycache__/\n' + result = runner.invoke(generate, ['python', '-o', str(output_path)]) + + assert result.exit_code == 0 + assert output_path.exists() + content = output_path.read_text() + assert '__pycache__' in content + + def test_generate_with_add_pattern(self, runner): + """Test generating with additional pattern.""" + with patch('gitignore_generator.api.get_patterns') as mock: + mock.return_value = '__pycache__/\n' + result = runner.invoke(generate, ['python', '--preview', '--add-pattern', '*.custom']) + + assert result.exit_code == 0 + assert '*.custom' in result.output + + def test_generate_preview_and_output_conflict(self, runner, temp_dir): + """Test that --preview and -o cannot be used together.""" + output_path = temp_dir / '.gitignore' + + with patch('gitignore_generator.api.get_patterns') as mock: + mock.return_value = '__pycache__/\n' + result = runner.invoke(generate, ['python', '--preview', '-o', str(output_path)]) + + assert result.exit_code != 0 + assert 'cannot be used together' in result.output + + def test_detect_help(self, runner): + """Test detect help.""" + result = runner.invoke(detect, ['--help']) + assert result.exit_code == 0 + assert '--preview' in result.output + assert '--output' in result.output + + def test_detect_no_project(self, runner, temp_dir): + """Test detect when no project is found.""" + with patch('gitignore_generator.detector.ProjectDetector') as mock_detector: + mock_instance = MagicMock() + mock_instance.detect.return_value = [] + mock_instance.suggest_gitignore.return_value = [] + mock_instance.get_detection_details.return_value = [] + mock_detector.return_value = mock_instance + + with runner.isolated_filesystem(): + result = runner.invoke(detect, []) + + assert result.exit_code == 0 + assert 'No project type detected' in result.output + + def test_detect_with_project(self, runner, temp_dir): + """Test detect when project is found.""" + with patch('gitignore_generator.detector.ProjectDetector') as mock_detector: + mock_instance = MagicMock() + mock_instance.detect.return_value = ['python'] + mock_instance.suggest_gitignore.return_value = ['python'] + mock_instance.get_detection_details.return_value = [ + {'technology': 'python', 'matched_files': ['requirements.txt'], 'confidence': 1} + ] + mock_detector.return_value = mock_instance + + with patch('gitignore_generator.api.get_patterns') as mock_patterns: + mock_patterns.return_value = '__pycache__/\n' + with runner.isolated_filesystem(): + result = runner.invoke(detect, ['--preview']) + + assert result.exit_code == 0 + assert 'python' in result.output + + def test_list_help(self, runner): + """Test list help.""" + result = runner.invoke(list, ['--help']) + assert result.exit_code == 0 + assert '--force-refresh' in result.output + + def test_list_all(self, runner): + """Test listing all technologies.""" + with patch('gitignore_generator.cli.get_list') as mock: + mock.return_value = ['node', 'python', 'django'] + result = runner.invoke(list, []) + + assert result.exit_code == 0 + assert 'node' in result.output + assert 'python' in result.output + + def test_list_filtered(self, runner): + """Test listing filtered technologies.""" + with patch('gitignore_generator.cli.get_list') as mock: + mock.return_value = ['node', 'python', 'nodemon'] + result = runner.invoke(list, ['node']) + + assert result.exit_code == 0 + assert 'Matching' in result.output + + def test_show_help(self, runner): + """Test show help.""" + result = runner.invoke(show, ['--help']) + assert result.exit_code == 0 + assert '--force-refresh' in result.output + + def test_show_tech(self, runner): + """Test showing patterns for a tech.""" + with patch('gitignore_generator.cli.get_patterns') as mock: + mock.return_value = 'node_modules/\n*.log\n' + result = runner.invoke(show, ['node']) + + assert result.exit_code == 0 + assert 'node_modules' in result.output + + def test_cache_help(self, runner): + """Test cache help.""" + result = runner.invoke(cache, ['--help']) + assert result.exit_code == 0 + + def test_cache_show_stats(self, runner): + """Test showing cache stats.""" + with patch('gitignore_generator.cli.CacheManager') as mock: + mock_instance = MagicMock() + mock_instance.get_stats.return_value = { + 'total_items': 10, + 'valid_items': 8, + 'expired_items': 2, + 'cache_dir': '/tmp/cache' + } + mock.return_value = mock_instance + + result = runner.invoke(cache, []) + + assert result.exit_code == 0 + assert '10' in result.output + assert '8' in result.output + + def test_clear_cache(self, runner): + """Test clearing cache.""" + with patch('gitignore_generator.cli.CacheManager') as mock: + mock_instance = MagicMock() + mock_instance.clear.return_value = 5 + mock.return_value = mock_instance + + result = runner.invoke(clear_cache, []) + + assert result.exit_code == 0 + assert '5' in result.output + + def test_cli_error_handling(self, runner): + """Test CLI error handling.""" + with patch('gitignore_generator.cli.get_patterns') as mock: + from gitignore_generator.api import GitignoreIOError + mock.side_effect = GitignoreIOError("Test error") + + result = runner.invoke(show, ['nonexistent']) + + assert result.exit_code != 0 + assert 'Error' in result.output