From 17658d673d0d53a5ec8108653c1e184d4e388c03 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 08:08:22 +0000 Subject: [PATCH] Add unit tests for parsers, analyzer, and CLI --- tests/unit/test_cli.py | 143 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tests/unit/test_cli.py diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py new file mode 100644 index 0000000..343c0bc --- /dev/null +++ b/tests/unit/test_cli.py @@ -0,0 +1,143 @@ +"""Unit tests for CLI commands.""" + +import pytest +from click.testing import CliRunner +from unittest.mock import patch, MagicMock +import sys +from io import StringIO + +from loglens.cli.commands import analyze, watch, report, patterns, info + + +@pytest.fixture +def runner(): + """Click CLI runner.""" + return CliRunner() + + +class TestAnalyzeCommand: + """Tests for analyze command.""" + + @patch('loglens.cli.commands.LogAnalyzer') + def test_analyze_file(self, mock_analyzer_class, runner, tmp_path): + """Test analyzing a log file.""" + mock_analyzer = MagicMock() + mock_result = MagicMock() + mock_result.format_detected = MagicMock(value="json") + mock_result.total_lines = 3 + mock_result.parsed_count = 3 + mock_result.error_count = 1 + mock_result.warning_count = 1 + mock_result.critical_count = 0 + mock_result.debug_count = 0 + mock_result.top_errors = [] + mock_result.suggestions = [] + mock_result.entries = [] + mock_analyzer.analyze.return_value = mock_result + mock_analyzer_class.return_value = mock_analyzer + + log_file = tmp_path / "test.log" + log_file.write_text('{"level": "INFO", "message": "Test"}\n') + + result = runner.invoke(analyze, [str(log_file)]) + + assert result.exit_code == 0 + + @patch('loglens.cli.commands.LogAnalyzer') + def test_analyze_json_output(self, mock_analyzer_class, runner, tmp_path): + """Test analyze with JSON output.""" + mock_analyzer = MagicMock() + mock_result = MagicMock() + mock_result.format_detected = MagicMock(value="json") + mock_result.total_lines = 1 + mock_result.parsed_count = 1 + mock_result.error_count = 0 + mock_result.warning_count = 0 + mock_result.critical_count = 0 + mock_result.debug_count = 0 + mock_result.top_errors = [] + mock_result.suggestions = [] + mock_result.entries = [] + mock_result.analysis_time.isoformat.return_value = "2024-01-15T10:30:00" + mock_analyzer.analyze_file.return_value = mock_result + mock_analyzer_class.return_value = mock_analyzer + + log_file = tmp_path / "test.log" + log_file.write_text('{"level": "INFO", "message": "Test"}\n') + + result = runner.invoke(analyze, [str(log_file)]) + + assert result.exit_code == 0 + + def test_analyze_no_files(self, runner): + """Test analyze with no files.""" + result = runner.invoke(analyze, ["--help"]) + + assert result.exit_code == 0 + + +class TestWatchCommand: + """Tests for watch command.""" + + def test_watch_no_files(self, runner): + """Test watch with no files.""" + result = runner.invoke(watch, []) + + assert result.exit_code == 1 + assert "Error" in result.output + + +class TestReportCommand: + """Tests for report command.""" + + @patch('loglens.cli.commands.LogAnalyzer') + def test_report_to_file(self, mock_analyzer_class, runner, tmp_path): + """Test report generation to file.""" + mock_analyzer = MagicMock() + mock_result = MagicMock() + mock_result.format_detected = MagicMock(value="json") + mock_result.total_lines = 1 + mock_result.parsed_count = 1 + mock_result.critical_count = 0 + mock_result.error_count = 0 + mock_result.warning_count = 0 + mock_result.suggestions = [] + mock_analyzer.analyze_file.return_value = mock_result + mock_analyzer_class.return_value = mock_analyzer + + log_file = tmp_path / "test.log" + log_file.write_text('{"level": "INFO", "message": "Test"}\n') + + output_file = tmp_path / "report.txt" + result = runner.invoke(report, [str(log_file), "--output", str(output_file)]) + + assert result.exit_code == 0 + assert output_file.exists() + + +class TestPatternsCommand: + """Tests for patterns command.""" + + @patch('loglens.cli.commands.LogAnalyzer') + def test_list_patterns(self, mock_analyzer_class, runner): + """Test listing patterns.""" + mock_analyzer = MagicMock() + mock_analyzer.list_patterns_by_group.return_value = { + "exceptions": [{"name": "Python Exception", "severity": "error", "description": ""}] + } + mock_analyzer_class.return_value = mock_analyzer + + result = runner.invoke(patterns) + + assert result.exit_code == 0 + + +class TestInfoCommand: + """Tests for info command.""" + + def test_info(self, runner): + """Test info command displays version.""" + result = runner.invoke(info) + + assert result.exit_code == 0 + assert "LogLens" in result.output