Initial upload: gitignore-generator-cli v1.0.0 with CI/CD workflow
This commit is contained in:
227
tests/test_cli.py
Normal file
227
tests/test_cli.py
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user