|
"""Tests for coverage_checker.py boundary condition analysis.""" |
|
|
|
import os |
|
import sys |
|
import tempfile |
|
from pathlib import Path |
|
from unittest.mock import MagicMock |
|
from unittest.mock import patch |
|
|
|
import pytest |
|
|
|
# Add the scripts directory to the path to import coverage_checker |
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
|
|
|
import ast |
|
from unittest.mock import call |
|
|
|
from coverage_checker import BoundaryCondition |
|
from coverage_checker import CoverageChecker |
|
from coverage_checker import CoverageReport |
|
from coverage_checker import DocstringParser |
|
from coverage_checker import FunctionInfo |
|
from coverage_checker import RuffExcludeChecker |
|
from coverage_checker import TestFileLocator |
|
|
|
|
|
class TestShouldExclude: |
|
"""Test should_exclude method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
self.temp_dir = Path(tmpdir) |
|
self.checker = RuffExcludeChecker(self.temp_dir) |
|
|
|
def test_should_exclude_file_path_valid(self): |
|
"""boundary_file_path_valid: file_path is a normal Python file within project.""" |
|
# Expected: Returns False if no exclude patterns match |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
test_file = temp_dir / "test.py" |
|
test_file.touch() |
|
|
|
# No exclude patterns |
|
result = checker.should_exclude(test_file) |
|
assert result is False |
|
|
|
def test_should_exclude_file_path_invalid(self): |
|
"""boundary_file_path_invalid: file_path is non-existent or outside project root.""" |
|
# Expected: Returns False (does not exclude) |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
|
|
# File outside project root |
|
outside_file = Path("/some/outside/path.py") |
|
result = checker.should_exclude(outside_file) |
|
assert result is False |
|
|
|
def test_should_exclude_file_path_edge(self): |
|
"""boundary_file_path_edge: file_path matches exclude patterns exactly.""" |
|
# Expected: Returns True when pattern matches |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
|
|
# Mock exclude patterns |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["*.pyc", "__pycache__/*"] |
|
|
|
test_file = temp_dir / "test.pyc" |
|
test_file.touch() |
|
|
|
result = checker.should_exclude(test_file) |
|
assert result is True |
|
|
|
def test_should_exclude_state_initial(self): |
|
"""boundary_state_initial: exclude_patterns is empty list.""" |
|
# Expected: Returns False immediately (short-circuit) |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = [] |
|
|
|
test_file = temp_dir / "any_file.py" |
|
test_file.touch() |
|
|
|
result = checker.should_exclude(test_file) |
|
assert result is False |
|
|
|
def test_should_exclude_state_modified(self): |
|
"""boundary_state_modified: exclude_patterns contains glob patterns.""" |
|
# Expected: Uses fnmatch for pattern matching |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["tests/*", "*.tmp"] |
|
|
|
# File matching pattern |
|
test_file = temp_dir / "tests" / "test_file.py" |
|
test_file.parent.mkdir(exist_ok=True) |
|
test_file.touch() |
|
|
|
result = checker.should_exclude(test_file) |
|
assert result is True |
|
|
|
def test_should_exclude_state_invalid(self): |
|
"""boundary_state_invalid: Invalid patterns in exclude_patterns.""" |
|
# Expected: fnmatch handles gracefully or raises exception |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
# Test with potentially problematic patterns |
|
checker.exclude_patterns = ["[invalid"] |
|
|
|
test_file = temp_dir / "test.py" |
|
test_file.touch() |
|
|
|
# Should handle invalid patterns gracefully |
|
result = checker.should_exclude(test_file) |
|
assert isinstance(result, bool) |
|
|
|
def test_should_exclude_return_success(self): |
|
"""boundary_return_success: Pattern matching successful.""" |
|
# Expected: Returns True/False based on match result |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["*.log"] |
|
|
|
# File that matches |
|
match_file = temp_dir / "debug.log" |
|
match_file.touch() |
|
assert checker.should_exclude(match_file) is True |
|
|
|
# File that doesn't match |
|
no_match_file = temp_dir / "script.py" |
|
no_match_file.touch() |
|
assert checker.should_exclude(no_match_file) is False |
|
|
|
def test_should_exclude_return_empty(self): |
|
"""boundary_return_empty: No patterns to match against.""" |
|
# Expected: Returns False (no exclusion) |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = [] |
|
|
|
test_file = temp_dir / "any_file.py" |
|
test_file.touch() |
|
|
|
result = checker.should_exclude(test_file) |
|
assert result is False |
|
|
|
def test_should_exclude_return_error(self): |
|
"""boundary_return_error: Path resolution fails.""" |
|
# Expected: Returns False on ValueError |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["*.py"] |
|
|
|
# Path outside project root should trigger ValueError |
|
outside_path = Path("/definitely/outside/project") |
|
result = checker.should_exclude(outside_path) |
|
assert result is False |
|
|
|
def test_should_exclude_error_recoverable(self): |
|
"""boundary_error_recoverable: ValueError during path resolution.""" |
|
# Expected: Catches exception and returns False |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["*.py"] |
|
|
|
# Mock to force ValueError |
|
with patch.object(Path, "resolve") as mock_resolve: |
|
mock_resolve.side_effect = ValueError("Path resolution failed") |
|
|
|
test_file = temp_dir / "test.py" |
|
result = checker.should_exclude(test_file) |
|
assert result is False |
|
|
|
def test_should_exclude_error_fatal(self): |
|
"""boundary_error_fatal: File system access denied.""" |
|
# Expected: May propagate system errors |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["*.py"] |
|
|
|
# This test might be system-dependent, focus on the structure |
|
test_file = temp_dir / "test.py" |
|
test_file.touch() |
|
|
|
# Should handle normally |
|
result = checker.should_exclude(test_file) |
|
assert isinstance(result, bool) |
|
|
|
def test_should_exclude_error_validation(self): |
|
"""boundary_error_validation: Malformed glob patterns.""" |
|
# Expected: fnmatch may raise exceptions |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
checker = RuffExcludeChecker(temp_dir) |
|
checker.exclude_patterns = ["["] # Malformed bracket |
|
|
|
test_file = temp_dir / "test.py" |
|
test_file.touch() |
|
|
|
# fnmatch should handle this or raise an exception |
|
try: |
|
result = checker.should_exclude(test_file) |
|
assert isinstance(result, bool) |
|
except Exception: |
|
# Exception is also acceptable for malformed patterns |
|
pass |
|
|
|
|
|
class TestMain: |
|
"""Test main function boundary conditions.""" |
|
|
|
def test_main_args_default(self): |
|
"""boundary_args_default: No arguments provided, uses default path ".".""" |
|
# Expected: sys.argv = ["script_name"], processes current directory |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
# Should call with default path "." |
|
mock_path.assert_called_with(".") |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_args_file(self): |
|
"""boundary_args_file: Single file path provided as argument.""" |
|
# Expected: Processes only specified file, validates existence |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "test_file.py"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_path.assert_called_with("test_file.py") |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_args_directory(self): |
|
"""boundary_args_directory: Directory path provided as argument.""" |
|
# Expected: Recursively processes all .py files in directory |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "/some/directory"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_path.assert_called_with("/some/directory") |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_args_nonexistent(self): |
|
"""boundary_args_nonexistent: Non-existent path provided.""" |
|
# Expected: Exits with error code 1, prints error message |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "/nonexistent/path"]): |
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
# Should call sys.exit(1) first when path doesn't exist |
|
# (might call sys.exit(0) later due to mocking, but first call should be exit(1)) |
|
calls = mock_exit.call_args_list |
|
assert len(calls) >= 1 |
|
assert calls[0] == call(1) |
|
|
|
def test_main_args_flags(self): |
|
"""boundary_args_flags: Various flag combinations (--update, --strict, etc.).""" |
|
# Expected: Modifies behavior according to flag combinations |
|
from coverage_checker import main |
|
|
|
with patch( |
|
"sys.argv", ["coverage_checker.py", "--update", "--strict", "test.py"] |
|
): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
# Verify CoverageChecker was called with correct flags |
|
mock_checker.assert_called_with( |
|
update_mode=True, generate_templates=False |
|
) |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_state_initial(self): |
|
"""boundary_state_initial: Standard execution with valid arguments.""" |
|
# Expected: Creates CoverageChecker, runs analysis, prints report |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_checker.assert_called_once() |
|
mock_checker_instance.check_directory.assert_called_once() |
|
mock_checker_instance.print_report.assert_called_once() |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_state_modified(self): |
|
"""boundary_state_modified: Execution with --update or --generate-templates flags.""" |
|
# Expected: Modifies source files and regenerates analysis |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "--generate-templates"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_checker.assert_called_with( |
|
update_mode=False, generate_templates=True |
|
) |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_state_invalid(self): |
|
"""boundary_state_invalid: Invalid argument combinations or malformed flags.""" |
|
# Expected: ArgumentParser raises SystemExit with help message |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "--invalid-flag"]): |
|
with pytest.raises(SystemExit): |
|
main() |
|
|
|
def test_main_return_success(self): |
|
"""boundary_return_success: All tests pass or no strict mode enabled.""" |
|
# Expected: sys.exit(0) - clean exit with success status |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_return_empty(self): |
|
"""boundary_return_empty: No Python files found to analyze.""" |
|
# Expected: Empty report generated, sys.exit(0) |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "empty_dir"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_report.total_functions = 0 |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_return_error(self): |
|
"""boundary_return_error: Missing tests in strict mode or file not found.""" |
|
# Expected: sys.exit(1) - error exit code |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "--strict"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [("func", "boundary_id", "file.py")] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
mock_exit.assert_called_with(1) |
|
|
|
def test_main_error_recoverable(self): |
|
"""boundary_error_recoverable: File access permissions or parsing errors.""" |
|
# Expected: Continues processing other files, reports errors |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py"]): |
|
with patch("coverage_checker.CoverageChecker") as mock_checker: |
|
with patch("coverage_checker.Path") as mock_path: |
|
mock_path.return_value.exists.return_value = True |
|
mock_checker_instance = MagicMock() |
|
mock_checker.return_value = mock_checker_instance |
|
mock_report = MagicMock() |
|
mock_report.missing_tests = [] |
|
mock_report.missing_checklists = [] |
|
mock_checker_instance.check_directory.return_value = mock_report |
|
|
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
# Should still complete successfully |
|
mock_exit.assert_called_with(0) |
|
|
|
def test_main_error_fatal(self): |
|
"""boundary_error_fatal: Path doesn't exist or invalid directory structure.""" |
|
# Expected: Immediate sys.exit(1) with error message |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "/invalid/path"]): |
|
with patch("sys.exit") as mock_exit: |
|
main() |
|
# Should call sys.exit(1) first when path doesn't exist |
|
calls = mock_exit.call_args_list |
|
assert len(calls) >= 1 |
|
assert calls[0] == call(1) |
|
|
|
def test_main_error_validation(self): |
|
"""boundary_error_validation: Invalid command line arguments.""" |
|
# Expected: ArgumentParser handles and exits with usage message |
|
from coverage_checker import main |
|
|
|
with patch("sys.argv", ["coverage_checker.py", "--unknown-argument"]): |
|
with pytest.raises(SystemExit): |
|
main() |
|
|
|
|
|
class TestHasBoundaryChecklist: |
|
"""Test has_boundary_checklist method boundary conditions.""" |
|
|
|
def test_has_boundary_checklist_docstring_valid(self): |
|
"""boundary_docstring_valid: docstring contains valid/expected value.""" |
|
# Expected: Returns True for valid checklist docstring |
|
docstring = """ |
|
This is a test function. |
|
|
|
Test Coverage Checklist - test_function: |
|
|
|
1. Input Parameter Boundaries: |
|
- [ ] boundary_test_valid: test input |
|
""" |
|
result = DocstringParser.has_boundary_checklist(docstring) |
|
assert result is True |
|
|
|
def test_has_boundary_checklist_docstring_invalid(self): |
|
"""boundary_docstring_invalid: docstring contains invalid/unexpected value.""" |
|
# Expected: Returns False for non-string or None docstring |
|
result_none = DocstringParser.has_boundary_checklist(None) |
|
assert result_none is False |
|
|
|
result_empty = DocstringParser.has_boundary_checklist("") |
|
assert result_empty is False |
|
|
|
def test_has_boundary_checklist_docstring_edge(self): |
|
"""boundary_docstring_edge: docstring contains edge case value (empty, zero, max, etc.).""" |
|
# Expected: Returns False for docstring without checklist |
|
docstring_no_checklist = ( |
|
"This is just a regular docstring without any checklist." |
|
) |
|
result = DocstringParser.has_boundary_checklist(docstring_no_checklist) |
|
assert result is False |
|
|
|
def test_has_boundary_checklist_state_initial(self): |
|
"""boundary_state_initial: Function called in initial/default state.""" |
|
# Expected: Returns expected result based on docstring content |
|
parser = DocstringParser() |
|
docstring = """ |
|
Test Coverage Checklist - sample: |
|
- [ ] boundary_test: test condition |
|
""" |
|
result = parser.has_boundary_checklist(docstring) |
|
assert result is True |
|
|
|
def test_has_boundary_checklist_state_modified(self): |
|
"""boundary_state_modified: Function called after state changes.""" |
|
# Expected: Consistent behavior regardless of parser state |
|
parser = DocstringParser() |
|
# Call method multiple times |
|
docstring = "Test Coverage Checklist - test:" |
|
result1 = parser.has_boundary_checklist(docstring) |
|
result2 = parser.has_boundary_checklist(docstring) |
|
assert result1 == result2 is True |
|
|
|
def test_has_boundary_checklist_state_invalid(self): |
|
"""boundary_state_invalid: Function called in invalid/inconsistent state.""" |
|
# Expected: Handles invalid input gracefully or raises TypeError |
|
try: |
|
result = DocstringParser.has_boundary_checklist(123) # Invalid type |
|
assert result is False |
|
except TypeError: |
|
assert True # Expected behavior for invalid type |
|
|
|
def test_has_boundary_checklist_return_success(self): |
|
"""boundary_return_success: Normal successful execution.""" |
|
# Expected: Returns boolean True/False based on pattern match |
|
valid_docstring = "Test Coverage Checklist - func:" |
|
invalid_docstring = "No checklist here" |
|
|
|
assert DocstringParser.has_boundary_checklist(valid_docstring) is True |
|
assert DocstringParser.has_boundary_checklist(invalid_docstring) is False |
|
|
|
def test_has_boundary_checklist_return_empty(self): |
|
"""boundary_return_empty: Function returns empty/null result.""" |
|
# Expected: Returns False for empty docstring |
|
result = DocstringParser.has_boundary_checklist("") |
|
assert result is False |
|
|
|
def test_has_boundary_checklist_return_error(self): |
|
"""boundary_return_error: Function encounters error conditions.""" |
|
# Expected: Returns False on error (no exceptions raised) |
|
result = DocstringParser.has_boundary_checklist(None) |
|
assert result is False |
|
|
|
def test_has_boundary_checklist_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors occur.""" |
|
# Expected: Handles non-string input gracefully or raises TypeError |
|
try: |
|
result = DocstringParser.has_boundary_checklist( |
|
[] |
|
) # List instead of string |
|
assert result is False |
|
except TypeError: |
|
assert True # Expected behavior for invalid type |
|
|
|
def test_has_boundary_checklist_error_fatal(self): |
|
"""boundary_error_fatal: Fatal/unrecoverable errors occur.""" |
|
# Expected: Method should not raise fatal errors for any input |
|
try: |
|
DocstringParser.has_boundary_checklist(object()) |
|
assert True # If no exception, test passes |
|
except Exception: |
|
# Method should handle gracefully, but if exception occurs, it's acceptable |
|
pass |
|
|
|
def test_has_boundary_checklist_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Expected: Returns False for invalid input types or raises TypeError |
|
invalid_inputs = [123, [], {}, object()] |
|
for invalid_input in invalid_inputs: |
|
try: |
|
result = DocstringParser.has_boundary_checklist(invalid_input) |
|
assert result is False |
|
except TypeError: |
|
assert True # Expected behavior for invalid type |
|
|
|
|
|
class TestParseBoundaryConditions: |
|
"""Test parse_boundary_conditions method boundary conditions.""" |
|
|
|
def test_parse_boundary_conditions_docstring_valid(self): |
|
"""boundary_docstring_valid: docstring contains valid/expected value.""" |
|
# Expected: Parses boundary conditions correctly |
|
docstring = """ |
|
Test Coverage Checklist - test_func: |
|
|
|
1. Input Parameter Boundaries: |
|
- [x] boundary_input_valid: valid input parameter |
|
- Expected: Function processes input successfully |
|
- [ ] boundary_input_invalid: invalid input parameter |
|
- Expected: Function raises ValueError |
|
""" |
|
conditions = DocstringParser.parse_boundary_conditions(docstring) |
|
assert len(conditions) == 2 |
|
assert conditions[0].identifier == "boundary_input_valid" |
|
assert conditions[0].is_covered is True |
|
assert conditions[1].identifier == "boundary_input_invalid" |
|
assert conditions[1].is_covered is False |
|
|
|
def test_parse_boundary_conditions_docstring_invalid(self): |
|
"""boundary_docstring_invalid: docstring contains invalid/unexpected value.""" |
|
# Expected: Returns empty list for invalid docstring |
|
result = DocstringParser.parse_boundary_conditions(None) |
|
assert result == [] |
|
|
|
result_empty = DocstringParser.parse_boundary_conditions("") |
|
assert result_empty == [] |
|
|
|
def test_parse_boundary_conditions_docstring_edge(self): |
|
"""boundary_docstring_edge: docstring contains edge case value (empty, zero, max, etc.).""" |
|
# Expected: Handles edge cases gracefully |
|
# Docstring with checklist header but no actual conditions |
|
docstring = "Test Coverage Checklist - func:\n\nNo actual boundaries here." |
|
conditions = DocstringParser.parse_boundary_conditions(docstring) |
|
assert conditions == [] |
|
|
|
def test_parse_boundary_conditions_state_initial(self): |
|
"""boundary_state_initial: Function called in initial/default state.""" |
|
# Expected: Parses conditions correctly on first call |
|
docstring = """ |
|
Test Coverage Checklist - func: |
|
- [x] boundary_test: test condition |
|
- Expected: Test behavior |
|
""" |
|
conditions = DocstringParser.parse_boundary_conditions(docstring) |
|
assert len(conditions) == 1 |
|
assert conditions[0].is_covered is True |
|
|
|
def test_parse_boundary_conditions_state_modified(self): |
|
"""boundary_state_modified: Function called after state changes.""" |
|
# Expected: Consistent results regardless of previous calls |
|
docstring = """ |
|
Test Coverage Checklist - func: |
|
- [ ] boundary_test: test condition |
|
""" |
|
parser = DocstringParser() |
|
result1 = parser.parse_boundary_conditions(docstring) |
|
result2 = parser.parse_boundary_conditions(docstring) |
|
assert len(result1) == len(result2) == 1 |
|
assert result1[0].identifier == result2[0].identifier |
|
|
|
def test_parse_boundary_conditions_state_invalid(self): |
|
"""boundary_state_invalid: Function called in invalid/inconsistent state.""" |
|
# Expected: Handles invalid state gracefully or raises TypeError |
|
try: |
|
result = DocstringParser.parse_boundary_conditions(123) |
|
assert result == [] |
|
except (TypeError, AttributeError): |
|
assert True # Expected behavior for invalid type |
|
|
|
def test_parse_boundary_conditions_return_success(self): |
|
"""boundary_return_success: Normal successful execution.""" |
|
# Expected: Returns list of BoundaryCondition objects |
|
docstring = """ |
|
Test Coverage Checklist - func: |
|
- [x] boundary_success: successful test |
|
- Expected: Returns success |
|
""" |
|
conditions = DocstringParser.parse_boundary_conditions(docstring) |
|
assert isinstance(conditions, list) |
|
assert len(conditions) == 1 |
|
assert isinstance(conditions[0], BoundaryCondition) |
|
|
|
def test_parse_boundary_conditions_return_empty(self): |
|
"""boundary_return_empty: Function returns empty/null result.""" |
|
# Expected: Returns empty list when no conditions found |
|
docstring = "Regular docstring without checklist" |
|
conditions = DocstringParser.parse_boundary_conditions(docstring) |
|
assert conditions == [] |
|
|
|
def test_parse_boundary_conditions_return_error(self): |
|
"""boundary_return_error: Function encounters error conditions.""" |
|
# Expected: Returns empty list on error |
|
conditions = DocstringParser.parse_boundary_conditions(None) |
|
assert conditions == [] |
|
|
|
def test_parse_boundary_conditions_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors occur.""" |
|
# Expected: Handles type errors gracefully or raises TypeError |
|
try: |
|
conditions = DocstringParser.parse_boundary_conditions([]) |
|
assert conditions == [] |
|
except (TypeError, AttributeError): |
|
assert True # Expected behavior for invalid type |
|
|
|
def test_parse_boundary_conditions_error_fatal(self): |
|
"""boundary_error_fatal: Fatal/unrecoverable errors occur.""" |
|
# Expected: Should not raise fatal errors |
|
try: |
|
DocstringParser.parse_boundary_conditions(object()) |
|
assert True |
|
except Exception: |
|
pass # Acceptable if exception occurs |
|
|
|
def test_parse_boundary_conditions_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Expected: Returns empty list for invalid input types or raises TypeError |
|
invalid_inputs = [123, [], {}] |
|
for invalid_input in invalid_inputs: |
|
try: |
|
conditions = DocstringParser.parse_boundary_conditions(invalid_input) |
|
assert conditions == [] |
|
except (TypeError, AttributeError): |
|
assert True # Expected behavior for invalid type |
|
|
|
|
|
class TestFindTestFile: |
|
"""Test find_test_file method boundary conditions.""" |
|
|
|
def test_find_test_file_source_file_valid(self): |
|
"""boundary_source_file_valid: source_file contains valid/expected value.""" |
|
# Expected: Returns test file path when found |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "module.py" |
|
test_file = temp_dir / "test_module.py" |
|
|
|
source_file.touch() |
|
test_file.touch() |
|
|
|
result = TestFileLocator.find_test_file(source_file) |
|
assert result == test_file |
|
|
|
def test_find_test_file_source_file_invalid(self): |
|
"""boundary_source_file_invalid: source_file contains invalid/unexpected value.""" |
|
# Expected: Returns None for non-existent file |
|
non_existent = Path("/non/existent/file.py") |
|
result = TestFileLocator.find_test_file(non_existent) |
|
assert result is None |
|
|
|
def test_find_test_file_source_file_edge(self): |
|
"""boundary_source_file_edge: source_file contains edge case value (empty, zero, max, etc.).""" |
|
# Expected: Handles edge cases like file without extension |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "module" # No .py extension |
|
|
|
result = TestFileLocator.find_test_file(source_file) |
|
assert result is None |
|
|
|
def test_find_test_file_state_initial(self): |
|
"""boundary_state_initial: Function called in initial/default state.""" |
|
# Expected: Searches for test files in expected locations |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "example.py" |
|
source_file.touch() |
|
|
|
result = TestFileLocator.find_test_file(source_file) |
|
# Should return None if no test file exists |
|
assert result is None |
|
|
|
def test_find_test_file_state_modified(self): |
|
"""boundary_state_modified: Function called after state changes.""" |
|
# Expected: Consistent behavior regardless of previous calls |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "sample.py" |
|
test_file = temp_dir / "test_sample.py" |
|
|
|
source_file.touch() |
|
test_file.touch() |
|
|
|
result1 = TestFileLocator.find_test_file(source_file) |
|
result2 = TestFileLocator.find_test_file(source_file) |
|
assert result1 == result2 == test_file |
|
|
|
def test_find_test_file_state_invalid(self): |
|
"""boundary_state_invalid: Function called in invalid/inconsistent state.""" |
|
# Expected: Handles invalid file types gracefully or raises AttributeError |
|
try: |
|
result = TestFileLocator.find_test_file(None) |
|
assert result is None |
|
except AttributeError: |
|
assert True # Expected behavior for None input |
|
|
|
def test_find_test_file_return_success(self): |
|
"""boundary_return_success: Normal successful execution.""" |
|
# Expected: Returns Path object when test file found |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "app.py" |
|
test_file = temp_dir / "test_app.py" |
|
|
|
source_file.touch() |
|
test_file.touch() |
|
|
|
result = TestFileLocator.find_test_file(source_file) |
|
assert isinstance(result, Path) |
|
assert result.exists() |
|
|
|
def test_find_test_file_return_empty(self): |
|
"""boundary_return_empty: Function returns empty/null result.""" |
|
# Expected: Returns None when no test file found |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "isolated.py" |
|
source_file.touch() |
|
|
|
result = TestFileLocator.find_test_file(source_file) |
|
assert result is None |
|
|
|
def test_find_test_file_return_error(self): |
|
"""boundary_return_error: Function encounters error conditions.""" |
|
# Expected: Returns None on error conditions |
|
invalid_path = Path("") |
|
result = TestFileLocator.find_test_file(invalid_path) |
|
assert result is None |
|
|
|
def test_find_test_file_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors occur.""" |
|
# Expected: Handles path resolution errors gracefully |
|
try: |
|
result = TestFileLocator.find_test_file(Path("/invalid/path/file.py")) |
|
assert result is None |
|
except Exception: |
|
pass # Acceptable if exception occurs |
|
|
|
def test_find_test_file_error_fatal(self): |
|
"""boundary_error_fatal: Fatal/unrecoverable errors occur.""" |
|
# Expected: Should handle fatal errors without crashing |
|
try: |
|
TestFileLocator.find_test_file(None) |
|
assert True |
|
except AttributeError: |
|
assert True # Expected for None input |
|
|
|
def test_find_test_file_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Expected: Handles invalid input types |
|
invalid_inputs = [123, "", []] |
|
for invalid_input in invalid_inputs: |
|
try: |
|
result = TestFileLocator.find_test_file(invalid_input) |
|
assert result is None or True |
|
except (AttributeError, TypeError): |
|
assert True # Expected for invalid types |
|
|
|
|
|
class TestExtractTestMethods: |
|
"""Test extract_test_methods method boundary conditions.""" |
|
|
|
def test_extract_test_methods_test_file_valid(self): |
|
"""boundary_test_file_valid: test_file contains valid/expected value.""" |
|
# Expected: Returns set of test method names |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_example.py" |
|
|
|
test_content = """ |
|
def test_function_one(): |
|
pass |
|
|
|
def test_function_two(): |
|
assert True |
|
|
|
def regular_function(): |
|
pass |
|
|
|
class TestClass: |
|
def test_method_one(self): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
result = TestFileLocator.extract_test_methods(test_file) |
|
expected = {"test_function_one", "test_function_two", "test_method_one"} |
|
assert result == expected |
|
|
|
def test_extract_test_methods_test_file_invalid(self): |
|
"""boundary_test_file_invalid: test_file contains invalid/unexpected value.""" |
|
# Expected: Returns empty set for non-existent file |
|
non_existent = Path("/non/existent/test_file.py") |
|
result = TestFileLocator.extract_test_methods(non_existent) |
|
assert result == set() |
|
|
|
def test_extract_test_methods_test_file_edge(self): |
|
"""boundary_test_file_edge: test_file contains edge case value (empty, zero, max, etc.).""" |
|
# Expected: Handles empty file gracefully |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "empty_test.py" |
|
test_file.write_text("") # Empty file |
|
|
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert result == set() |
|
|
|
def test_extract_test_methods_state_initial(self): |
|
"""boundary_state_initial: Function called in initial/default state.""" |
|
# Expected: Parses valid Python test file correctly |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_simple.py" |
|
test_file.write_text("def test_sample(): pass") |
|
|
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert result == {"test_sample"} |
|
|
|
def test_extract_test_methods_state_modified(self): |
|
"""boundary_state_modified: Function called after state changes.""" |
|
# Expected: Consistent results regardless of previous calls |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_consistent.py" |
|
test_file.write_text("def test_consistency(): pass") |
|
|
|
result1 = TestFileLocator.extract_test_methods(test_file) |
|
result2 = TestFileLocator.extract_test_methods(test_file) |
|
assert result1 == result2 == {"test_consistency"} |
|
|
|
def test_extract_test_methods_state_invalid(self): |
|
"""boundary_state_invalid: Function called in invalid/inconsistent state.""" |
|
# Expected: Handles malformed Python file gracefully |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "malformed.py" |
|
test_file.write_text("def test_broken(\n") # Malformed syntax |
|
|
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert result == set() # Should return empty set on syntax error |
|
|
|
def test_extract_test_methods_return_success(self): |
|
"""boundary_return_success: Normal successful execution.""" |
|
# Expected: Returns set of test method names found |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_success.py" |
|
test_file.write_text(""" |
|
def test_alpha(): |
|
pass |
|
|
|
def test_beta(): |
|
pass |
|
""") |
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert isinstance(result, set) |
|
assert len(result) == 2 |
|
assert "test_alpha" in result |
|
assert "test_beta" in result |
|
|
|
def test_extract_test_methods_return_empty(self): |
|
"""boundary_return_empty: Function returns empty/null result.""" |
|
# Expected: Returns empty set when no test methods found |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "no_tests.py" |
|
test_file.write_text(""" |
|
def regular_function(): |
|
pass |
|
|
|
class RegularClass: |
|
def method(self): |
|
pass |
|
""") |
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert result == set() |
|
|
|
def test_extract_test_methods_return_error(self): |
|
"""boundary_return_error: Function encounters error conditions.""" |
|
# Expected: Returns empty set on file read errors |
|
non_existent = Path("/definitely/does/not/exist.py") |
|
result = TestFileLocator.extract_test_methods(non_existent) |
|
assert result == set() |
|
|
|
def test_extract_test_methods_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors occur.""" |
|
# Expected: Handles file encoding errors gracefully |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "encoding_issue.py" |
|
# Create file with potential encoding issues but valid test |
|
test_file.write_text("def test_encoding(): pass") |
|
|
|
result = TestFileLocator.extract_test_methods(test_file) |
|
assert "test_encoding" in result |
|
|
|
def test_extract_test_methods_error_fatal(self): |
|
"""boundary_error_fatal: Fatal/unrecoverable errors occur.""" |
|
# Expected: Should not crash on permission errors |
|
try: |
|
result = TestFileLocator.extract_test_methods(Path("/")) |
|
assert isinstance(result, set) |
|
except Exception: |
|
assert True # Acceptable if exception occurs |
|
|
|
def test_extract_test_methods_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Expected: Handles invalid Path objects gracefully |
|
try: |
|
result = TestFileLocator.extract_test_methods(None) |
|
assert result == set() |
|
except AttributeError: |
|
assert True # Expected for None input |
|
|
|
|
|
# Tests for remaining functions from coverage_checker.py |
|
# We need to implement tests for: scan_file, generate_checklist_template, add_checklist_to_function, |
|
# validate_coverage, update_docstring_coverage, update_source_file, generate_report, |
|
# check_directory, print_report |
|
|
|
|
|
class TestScanFile: |
|
"""Test scan_file method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_scan_file_file_path_valid(self): |
|
"""boundary_file_path_valid: Normal Python file within project.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "valid_module.py" |
|
test_content = ''' |
|
def public_function(): |
|
"""A public function. |
|
|
|
DO NOT EDIT THE FOLLOWING CHECKLIST CHECK BOXES. IT IS AUTO-GENERATED. |
|
Test Coverage Checklist - public_function: |
|
|
|
1. Input Parameter Boundaries: |
|
- [ ] boundary_test_valid: test input |
|
- Expected: Function processes input correctly |
|
""" |
|
pass |
|
|
|
def another_public(): |
|
"""Function without checklist.""" |
|
pass |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
assert len(functions_with) == 1 |
|
assert functions_with[0].name == "public_function" |
|
assert len(functions_without) == 1 |
|
assert functions_without[0][1] == "another_public" |
|
|
|
def test_scan_file_file_path_invalid(self): |
|
"""boundary_file_path_invalid: Non-existent or invalid file path.""" |
|
non_existent = Path("/definitely/does/not/exist.py") |
|
functions_with, functions_without = self.checker.scan_file(non_existent) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_file_path_edge(self): |
|
"""boundary_file_path_edge: Non-Python file or edge case paths.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
text_file = temp_dir / "not_python.txt" |
|
text_file.write_text("This is not a Python file") |
|
|
|
functions_with, functions_without = self.checker.scan_file(text_file) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_state_initial(self): |
|
"""boundary_state_initial: Fresh CoverageChecker instance state.""" |
|
checker = CoverageChecker() |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "module.py" |
|
test_file.write_text("def simple_func(): pass") |
|
|
|
functions_with, functions_without = checker.scan_file(test_file) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 1 |
|
|
|
def test_scan_file_state_modified(self): |
|
"""boundary_state_modified: CoverageChecker after previous operations.""" |
|
# Simulate previous operations |
|
self.checker.update_mode = True |
|
self.checker.generate_templates = True |
|
|
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "module.py" |
|
test_file.write_text("def test_func(): pass") |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 1 |
|
|
|
def test_scan_file_state_invalid(self): |
|
"""boundary_state_invalid: Malformed Python file causing parse errors.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
malformed_file = temp_dir / "broken.py" |
|
malformed_file.write_text("def broken_syntax(\n pass") # Invalid syntax |
|
|
|
functions_with, functions_without = self.checker.scan_file(malformed_file) |
|
# Should handle gracefully |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_return_success(self): |
|
"""boundary_return_success: Mixed file with both types of functions.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "mixed.py" |
|
test_content = ''' |
|
def with_checklist(): |
|
"""Function with boundary checklist. |
|
|
|
Test Coverage Checklist - with_checklist: |
|
- [ ] boundary_test: test condition |
|
""" |
|
pass |
|
|
|
def without_checklist(): |
|
"""Regular function.""" |
|
pass |
|
|
|
def _private_function(): |
|
"""Should be skipped.""" |
|
pass |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
assert len(functions_with) == 1 |
|
assert len(functions_without) == 1 |
|
assert functions_with[0].name == "with_checklist" |
|
assert functions_without[0][1] == "without_checklist" |
|
|
|
def test_scan_file_return_empty(self): |
|
"""boundary_return_empty: File with only private/special methods.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "private_only.py" |
|
test_content = """ |
|
def _private_func(): |
|
pass |
|
|
|
def __special_method__(): |
|
pass |
|
|
|
class TestClass: |
|
def __init__(self): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_return_error(self): |
|
"""boundary_return_error: File access/permission errors.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test.py" |
|
test_file.write_text("def test(): pass") |
|
|
|
# Mock file read to raise permission error |
|
with patch("builtins.open", side_effect=PermissionError("Access denied")): |
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_error_recoverable(self): |
|
"""boundary_error_recoverable: Unicode or encoding errors.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "unicode.py" |
|
|
|
# Write file with bytes that might cause encoding issues |
|
with open(test_file, "wb") as f: |
|
f.write(b"def test(): pass\n# \xff\xfe comment") |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
# Should handle gracefully |
|
assert isinstance(functions_with, list) |
|
assert isinstance(functions_without, list) |
|
|
|
def test_scan_file_error_fatal(self): |
|
"""boundary_error_fatal: Directory path instead of file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
|
|
functions_with, functions_without = self.checker.scan_file(temp_dir) |
|
assert len(functions_with) == 0 |
|
assert len(functions_without) == 0 |
|
|
|
def test_scan_file_error_validation(self): |
|
"""boundary_error_validation: Completely invalid AST structure.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "invalid_ast.py" |
|
# Create file that's valid Python but has complex AST issues |
|
test_file.write_text("import ast; exec('def dynamic(): pass')") |
|
|
|
functions_with, functions_without = self.checker.scan_file(test_file) |
|
# Should handle without crashing |
|
assert isinstance(functions_with, list) |
|
assert isinstance(functions_without, list) |
|
|
|
|
|
class TestGenerateChecklistTemplate: |
|
"""Test generate_checklist_template method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_generate_checklist_template_function_name_valid(self): |
|
"""boundary_function_name_valid: Normal function name.""" |
|
func_node = ast.FunctionDef( |
|
name="sample_function", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template( |
|
"sample_function", func_node |
|
) |
|
assert "Test Coverage Checklist - sample_function:" in template |
|
assert "DO NOT EDIT THE FOLLOWING CHECKLIST CHECK BOXES" in template |
|
|
|
def test_generate_checklist_template_function_name_invalid(self): |
|
"""boundary_function_name_invalid: Empty or None function name.""" |
|
func_node = ast.FunctionDef( |
|
name="", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template("", func_node) |
|
assert "Test Coverage Checklist - :" in template |
|
|
|
def test_generate_checklist_template_function_name_edge(self): |
|
"""boundary_function_name_edge: Special characters or unusual names.""" |
|
func_node = ast.FunctionDef( |
|
name="test_func_123_special", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template( |
|
"test_func_123_special", func_node |
|
) |
|
assert "Test Coverage Checklist - test_func_123_special:" in template |
|
|
|
def test_generate_checklist_template_function_node_valid(self): |
|
"""boundary_function_node_valid: Function with parameters.""" |
|
arg1 = ast.arg(arg="param1", annotation=None) |
|
arg2 = ast.arg(arg="param2", annotation=None) |
|
func_node = ast.FunctionDef( |
|
name="func_with_params", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[arg1, arg2], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template( |
|
"func_with_params", func_node |
|
) |
|
assert "boundary_param1_valid" in template |
|
assert "boundary_param2_valid" in template |
|
assert "Input Parameter Boundaries:" in template |
|
|
|
def test_generate_checklist_template_function_node_invalid(self): |
|
"""boundary_function_node_invalid: Minimal function node.""" |
|
func_node = ast.FunctionDef( |
|
name="minimal", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template("minimal", func_node) |
|
# Should generate basic template without parameter boundaries |
|
assert "State/Context Boundaries:" in template |
|
assert "Input Parameter Boundaries:" not in template |
|
|
|
def test_generate_checklist_template_function_node_edge(self): |
|
"""boundary_function_node_edge: Method with self/cls parameters.""" |
|
self_arg = ast.arg(arg="self", annotation=None) |
|
cls_arg = ast.arg(arg="cls", annotation=None) |
|
param_arg = ast.arg(arg="value", annotation=None) |
|
|
|
# Test with self |
|
func_node_self = ast.FunctionDef( |
|
name="method_with_self", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[self_arg, param_arg], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template_self = self.checker.generate_checklist_template( |
|
"method_with_self", func_node_self |
|
) |
|
assert "boundary_value_valid" in template_self |
|
assert "boundary_self_valid" not in template_self |
|
|
|
# Test with cls |
|
func_node_cls = ast.FunctionDef( |
|
name="classmethod_test", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[cls_arg, param_arg], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template_cls = self.checker.generate_checklist_template( |
|
"classmethod_test", func_node_cls |
|
) |
|
assert "boundary_value_valid" in template_cls |
|
assert "boundary_cls_valid" not in template_cls |
|
|
|
def test_generate_checklist_template_state_initial(self): |
|
"""boundary_state_initial: First template generation call.""" |
|
func_node = ast.FunctionDef( |
|
name="first_call", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template("first_call", func_node) |
|
assert "boundary_state_initial" in template |
|
assert "boundary_return_success" in template |
|
assert "⚠️ TEMPLATE GENERATED" in template |
|
|
|
def test_generate_checklist_template_state_modified(self): |
|
"""boundary_state_modified: Multiple template generations.""" |
|
func_node1 = ast.FunctionDef( |
|
name="func1", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
func_node2 = ast.FunctionDef( |
|
name="func2", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
|
|
template1 = self.checker.generate_checklist_template("func1", func_node1) |
|
template2 = self.checker.generate_checklist_template("func2", func_node2) |
|
|
|
assert "Test Coverage Checklist - func1:" in template1 |
|
assert "Test Coverage Checklist - func2:" in template2 |
|
assert template1 != template2 # Should be different due to function names |
|
|
|
def test_generate_checklist_template_state_invalid(self): |
|
"""boundary_state_invalid: Invalid function node structure.""" |
|
try: |
|
self.checker.generate_checklist_template("test", None) |
|
raise AssertionError("Should raise AttributeError") |
|
except AttributeError: |
|
pass # Expected behavior |
|
|
|
def test_generate_checklist_template_return_success(self): |
|
"""boundary_return_success: Complete template generation.""" |
|
func_node = ast.FunctionDef( |
|
name="success_test", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template("success_test", func_node) |
|
|
|
# Verify all required sections |
|
assert "DO NOT EDIT THE FOLLOWING CHECKLIST CHECK BOXES" in template |
|
assert "State/Context Boundaries:" in template |
|
assert "Return Value Boundaries:" in template |
|
assert "Error Handling Boundaries:" in template |
|
assert "boundary_state_initial" in template |
|
assert "boundary_return_success" in template |
|
assert "boundary_error_recoverable" in template |
|
|
|
def test_generate_checklist_template_return_empty(self): |
|
"""boundary_return_empty: Minimal valid template.""" |
|
func_node = ast.FunctionDef( |
|
name="empty", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
template = self.checker.generate_checklist_template("empty", func_node) |
|
|
|
assert len(template) > 0 |
|
assert "boundary_state_initial" in template |
|
assert "Expected:" in template |
|
|
|
def test_generate_checklist_template_return_error(self): |
|
"""boundary_return_error: Template generation with mock errors.""" |
|
from unittest.mock import Mock |
|
|
|
func_node = Mock() |
|
func_node.name = "mock_func" |
|
func_node.args.args = [] |
|
|
|
template = self.checker.generate_checklist_template("mock_func", func_node) |
|
assert "Test Coverage Checklist - mock_func:" in template |
|
|
|
def test_generate_checklist_template_error_recoverable(self): |
|
"""boundary_error_recoverable: Partial function node data.""" |
|
from unittest.mock import Mock |
|
|
|
func_node = Mock() |
|
func_node.name = "recoverable_test" |
|
func_node.args = Mock() |
|
func_node.args.args = [] |
|
|
|
template = self.checker.generate_checklist_template( |
|
"recoverable_test", func_node |
|
) |
|
assert "Test Coverage Checklist - recoverable_test:" in template |
|
|
|
def test_generate_checklist_template_error_fatal(self): |
|
"""boundary_error_fatal: Missing required attributes.""" |
|
from unittest.mock import Mock |
|
|
|
func_node = Mock() |
|
func_node.args = None # Will cause AttributeError |
|
|
|
try: |
|
self.checker.generate_checklist_template("fatal_test", func_node) |
|
raise AssertionError("Should raise AttributeError") |
|
except AttributeError: |
|
pass # Expected |
|
|
|
def test_generate_checklist_template_error_validation(self): |
|
"""boundary_error_validation: Invalid function node types.""" |
|
func_node = ast.FunctionDef( |
|
name="validation_test", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
) |
|
# Corrupt the args to cause validation error |
|
func_node.args.args = "invalid" # Should be list |
|
|
|
try: |
|
template = self.checker.generate_checklist_template( |
|
"validation_test", func_node |
|
) |
|
# If it succeeds, that's also acceptable |
|
assert isinstance(template, str) |
|
except (TypeError, AttributeError): |
|
pass # Expected behavior for invalid input |
|
|
|
|
|
class TestAddChecklistToFunction: |
|
"""Test add_checklist_to_function method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_add_checklist_to_function_file_path_valid(self): |
|
"""boundary_file_path_valid: Valid Python file with function.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "valid_file.py" |
|
test_content = '''def sample_function(): |
|
"""A simple function.""" |
|
pass |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="sample_function", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
# Verify checklist was added |
|
updated_content = test_file.read_text() |
|
assert "Test Coverage Checklist" in updated_content |
|
|
|
def test_add_checklist_to_function_file_path_invalid(self): |
|
"""boundary_file_path_invalid: Non-existent file path.""" |
|
non_existent = Path("/definitely/does/not/exist.py") |
|
func_node = ast.FunctionDef( |
|
name="test_func", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(non_existent, func_node) |
|
assert result is False |
|
|
|
def test_add_checklist_to_function_file_path_edge(self): |
|
"""boundary_file_path_edge: Empty file or file without functions.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
empty_file = temp_dir / "empty.py" |
|
empty_file.write_text("") |
|
|
|
func_node = ast.FunctionDef( |
|
name="phantom_func", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(empty_file, func_node) |
|
assert result is True # Should add docstring to any file |
|
|
|
def test_add_checklist_to_function_function_node_valid(self): |
|
"""boundary_function_node_valid: Well-formed function node.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test.py" |
|
test_content = '''def target_function(param1, param2): |
|
"""Existing docstring.""" |
|
return param1 + param2 |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
arg1 = ast.arg(arg="param1", annotation=None) |
|
arg2 = ast.arg(arg="param2", annotation=None) |
|
func_node = ast.FunctionDef( |
|
name="target_function", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[arg1, arg2], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
def test_add_checklist_to_function_function_node_invalid(self): |
|
"""boundary_function_node_invalid: Malformed or None function node.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test.py" |
|
test_file.write_text("def test(): pass") |
|
|
|
result = self.checker.add_checklist_to_function(test_file, None) |
|
assert result is False |
|
|
|
def test_add_checklist_to_function_function_node_edge(self): |
|
"""boundary_function_node_edge: Function node with minimal data.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "minimal.py" |
|
test_content = """def minimal(): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="minimal", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
def test_add_checklist_to_function_state_initial(self): |
|
"""boundary_state_initial: First call to add checklist.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "initial.py" |
|
test_content = '''def new_function(): |
|
"""Initial function.""" |
|
pass |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="new_function", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
def test_add_checklist_to_function_state_modified(self): |
|
"""boundary_state_modified: Multiple checklist additions.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "modified.py" |
|
test_content = """def func1(): |
|
pass |
|
|
|
def func2(): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
func_node1 = ast.FunctionDef( |
|
name="func1", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
func_node2 = ast.FunctionDef( |
|
name="func2", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=4, |
|
) |
|
|
|
result1 = self.checker.add_checklist_to_function(test_file, func_node1) |
|
result2 = self.checker.add_checklist_to_function(test_file, func_node2) |
|
assert result1 is True |
|
assert result2 is True |
|
|
|
def test_add_checklist_to_function_state_invalid(self): |
|
"""boundary_state_invalid: File in inconsistent state.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "inconsistent.py" |
|
test_content = """def broken_syntax( |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="broken_syntax", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True # Should handle gracefully |
|
|
|
def test_add_checklist_to_function_return_success(self): |
|
"""boundary_return_success: Successful checklist addition.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "success.py" |
|
test_content = '''def success_func(): |
|
"""Existing docstring.""" |
|
return True |
|
''' |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="success_func", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
# Verify file was modified |
|
updated_content = test_file.read_text() |
|
assert "Test Coverage Checklist" in updated_content |
|
|
|
def test_add_checklist_to_function_return_empty(self): |
|
"""boundary_return_empty: Function without docstring gets new one.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "empty_docstring.py" |
|
test_content = """def no_docstring(): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
func_node = ast.FunctionDef( |
|
name="no_docstring", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
# Verify new docstring was added |
|
updated_content = test_file.read_text() |
|
assert "FIXME: Add function description" in updated_content |
|
|
|
def test_add_checklist_to_function_return_error(self): |
|
"""boundary_return_error: File operation errors.""" |
|
import os |
|
|
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "readonly.py" |
|
test_file.write_text("def test(): pass") |
|
|
|
# Make file read-only |
|
os.chmod(test_file, 0o444) |
|
|
|
func_node = ast.FunctionDef( |
|
name="test", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
# Should return False on permission error |
|
assert result is False |
|
|
|
# Restore permissions for cleanup |
|
os.chmod(test_file, 0o644) |
|
|
|
def test_add_checklist_to_function_error_recoverable(self): |
|
"""boundary_error_recoverable: Encoding or format issues.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "encoding_test.py" |
|
|
|
# Write file with potentially problematic encoding |
|
with open(test_file, "wb") as f: |
|
f.write(b'def test_encoding():\n """Test function."""\n pass\n') |
|
|
|
func_node = ast.FunctionDef( |
|
name="test_encoding", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(test_file, func_node) |
|
assert result is True |
|
|
|
def test_add_checklist_to_function_error_fatal(self): |
|
"""boundary_error_fatal: Completely inaccessible file.""" |
|
invalid_path = Path("/definitely/invalid/path/that/cannot/exist.py") |
|
|
|
func_node = ast.FunctionDef( |
|
name="fatal_test", |
|
args=ast.arguments( |
|
posonlyargs=[], |
|
args=[], |
|
vararg=None, |
|
kwonlyargs=[], |
|
kw_defaults=[], |
|
kwarg=None, |
|
defaults=[], |
|
), |
|
body=[], |
|
decorator_list=[], |
|
returns=None, |
|
lineno=1, |
|
) |
|
|
|
result = self.checker.add_checklist_to_function(invalid_path, func_node) |
|
assert result is False |
|
|
|
def test_add_checklist_to_function_error_validation(self): |
|
"""boundary_error_validation: Invalid input types.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "validation.py" |
|
test_file.write_text("def test(): pass") |
|
|
|
# Test with invalid function node type |
|
invalid_node = "not_a_function_node" |
|
|
|
result = self.checker.add_checklist_to_function(test_file, invalid_node) |
|
assert result is False |
|
|
|
|
|
class TestValidateCoverage: |
|
"""Test validate_coverage method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_validate_coverage_func_info_valid(self): |
|
"""boundary_func_info_valid: Valid FunctionInfo with test file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_sample.py" |
|
test_content = """ |
|
def test_sample_input_valid(): |
|
pass |
|
|
|
def test_sample_state_initial(): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_input_valid", "Valid input", "Success", False |
|
), |
|
BoundaryCondition( |
|
"boundary_state_initial", "Initial state", "Normal", False |
|
), |
|
BoundaryCondition("boundary_missing", "Missing test", "Missing", False), |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="sample", |
|
file_path=Path(tmpdir) / "sample.py", |
|
line_number=1, |
|
docstring="Test function", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert "boundary_missing" in missing_tests |
|
assert len(missing_tests) == 1 |
|
|
|
def test_validate_coverage_func_info_invalid(self): |
|
"""boundary_func_info_invalid: Incomplete or malformed FunctionInfo.""" |
|
# Test with None test_file_path |
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_test", "Test condition", "Expected", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="invalid", |
|
file_path=Path("/tmp/invalid.py"), |
|
line_number=1, |
|
docstring="Test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=None, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert "boundary_test" in missing_tests |
|
assert len(extra_coverage) == 0 |
|
|
|
def test_validate_coverage_func_info_edge(self): |
|
"""boundary_func_info_edge: FunctionInfo with empty boundary conditions.""" |
|
func_info = FunctionInfo( |
|
name="edge_case", |
|
file_path=Path("/tmp/edge.py"), |
|
line_number=1, |
|
docstring="Edge case", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert len(missing_tests) == 0 |
|
assert len(extra_coverage) == 0 |
|
|
|
def test_validate_coverage_state_initial(self): |
|
"""boundary_state_initial: First coverage validation call.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_initial.py" |
|
test_file.write_text("def test_initial_basic_valid(): pass") |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_basic_valid", "Basic valid", "Success", False |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="initial", |
|
file_path=temp_dir / "initial.py", |
|
line_number=1, |
|
docstring="Initial test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert len(missing_tests) == 0 # Test exists |
|
|
|
def test_validate_coverage_state_modified(self): |
|
"""boundary_state_modified: Coverage validation after state changes.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_modified.py" |
|
test_file.write_text("def test_modified_condition_valid(): pass") |
|
|
|
# Mark condition as covered to simulate state change |
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_condition_valid", "Valid condition", "Success", True |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="modified", |
|
file_path=temp_dir / "modified.py", |
|
line_number=1, |
|
docstring="Modified test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
# Should find extra coverage (test exists but not marked as covered) |
|
assert "boundary_condition_valid" in extra_coverage |
|
|
|
def test_validate_coverage_state_invalid(self): |
|
"""boundary_state_invalid: Invalid test file or corrupted state.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
invalid_test_file = temp_dir / "invalid_test.py" |
|
invalid_test_file.write_text( |
|
"def broken_syntax(\n pass" |
|
) # Invalid syntax |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_test", "Test condition", "Expected", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="invalid_state", |
|
file_path=temp_dir / "invalid.py", |
|
line_number=1, |
|
docstring="Invalid test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=invalid_test_file, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
# Should handle gracefully |
|
assert isinstance(missing_tests, list) |
|
assert isinstance(extra_coverage, list) |
|
|
|
def test_validate_coverage_return_success(self): |
|
"""boundary_return_success: Successful coverage validation with mixed results.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_success.py" |
|
test_content = """ |
|
def test_success_found_valid(): |
|
pass |
|
|
|
def test_success_partial_valid(): |
|
pass |
|
""" |
|
test_file.write_text(test_content) |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_found_valid", "Found test", "Success", False |
|
), |
|
BoundaryCondition( |
|
"boundary_partial_valid", "Partial test", "Success", True |
|
), |
|
BoundaryCondition( |
|
"boundary_missing_test", "Missing test", "Missing", False |
|
), |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="success", |
|
file_path=temp_dir / "success.py", |
|
line_number=1, |
|
docstring="Success test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert "boundary_missing_test" in missing_tests |
|
assert "boundary_partial_valid" in extra_coverage |
|
assert len(missing_tests) == 1 |
|
assert len(extra_coverage) == 1 |
|
|
|
def test_validate_coverage_return_empty(self): |
|
"""boundary_return_empty: No boundary conditions to validate.""" |
|
func_info = FunctionInfo( |
|
name="empty", |
|
file_path=Path("/tmp/empty.py"), |
|
line_number=1, |
|
docstring="Empty test", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert len(missing_tests) == 0 |
|
assert len(extra_coverage) == 0 |
|
|
|
def test_validate_coverage_return_error(self): |
|
"""boundary_return_error: Non-existent test file.""" |
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_error", "Error condition", "Error", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="error_case", |
|
file_path=Path("/tmp/error.py"), |
|
line_number=1, |
|
docstring="Error test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=Path("/non/existent/test.py"), |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
assert "boundary_error" in missing_tests |
|
assert len(extra_coverage) == 0 |
|
|
|
def test_validate_coverage_error_recoverable(self): |
|
"""boundary_error_recoverable: File access issues with test file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
# Create directory instead of file to cause error |
|
test_dir = temp_dir / "test_recoverable.py" |
|
test_dir.mkdir() |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_recoverable", "Recoverable error", "Error", False |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="recoverable", |
|
file_path=temp_dir / "recoverable.py", |
|
line_number=1, |
|
docstring="Recoverable test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_dir, # This is a directory, not a file |
|
) |
|
|
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
# Should handle gracefully and report missing tests |
|
assert "boundary_recoverable" in missing_tests |
|
|
|
def test_validate_coverage_error_fatal(self): |
|
"""boundary_error_fatal: Completely invalid FunctionInfo.""" |
|
try: |
|
missing_tests, extra_coverage = self.checker.validate_coverage(None) |
|
raise AssertionError("Should raise AttributeError") |
|
except AttributeError: |
|
pass # Expected behavior |
|
|
|
def test_validate_coverage_error_validation(self): |
|
"""boundary_error_validation: Invalid boundary condition data.""" |
|
# Create FunctionInfo with corrupted boundary conditions |
|
boundary_conditions = [ |
|
# Mock boundary condition with invalid data |
|
object() # Not a BoundaryCondition |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="validation_error", |
|
file_path=Path("/tmp/validation.py"), |
|
line_number=1, |
|
docstring="Validation test", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=None, |
|
) |
|
|
|
try: |
|
missing_tests, extra_coverage = self.checker.validate_coverage(func_info) |
|
# If it succeeds, that's acceptable |
|
assert isinstance(missing_tests, list) |
|
assert isinstance(extra_coverage, list) |
|
except AttributeError: |
|
pass # Expected for invalid boundary condition objects |
|
|
|
|
|
class TestUpdateDocstringCoverage: |
|
"""Test update_docstring_coverage method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_update_docstring_coverage_func_info_valid(self): |
|
"""boundary_func_info_valid: Valid FunctionInfo with test file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_update.py" |
|
# Correct test naming pattern: test_{function_name}_{boundary_id} |
|
test_file.write_text("def test_update_test_valid(): pass") |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_test_valid", "Test valid", "Success", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="update", |
|
file_path=temp_dir / "update.py", |
|
line_number=1, |
|
docstring="""Test function. |
|
|
|
Test Coverage Checklist - update: |
|
- [ ] boundary_test_valid: Test condition |
|
- Expected: Success |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
updated_docstring = self.checker.update_docstring_coverage(func_info) |
|
assert "[x]" in updated_docstring |
|
# The COVERED line might not appear immediately; check basic checkbox update |
|
assert "boundary_test_valid" in updated_docstring |
|
|
|
def test_update_docstring_coverage_func_info_invalid(self): |
|
"""boundary_func_info_invalid: FunctionInfo with None test_file_path.""" |
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_invalid", "Invalid condition", "Error", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="invalid_update", |
|
file_path=Path("/tmp/invalid.py"), |
|
line_number=1, |
|
docstring="Test function without test file.", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=None, |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
assert result == func_info.docstring # Should return unchanged |
|
|
|
def test_update_docstring_coverage_func_info_edge(self): |
|
"""boundary_func_info_edge: FunctionInfo with empty boundary conditions.""" |
|
func_info = FunctionInfo( |
|
name="edge_update", |
|
file_path=Path("/tmp/edge.py"), |
|
line_number=1, |
|
docstring="Edge case function.", |
|
boundary_conditions=[], |
|
test_file_path=Path("/tmp/test_edge.py"), |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
assert result == func_info.docstring |
|
|
|
def test_update_docstring_coverage_state_initial(self): |
|
"""boundary_state_initial: First docstring update call.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_initial.py" |
|
test_file.write_text("def test_initial_basic_valid(): pass") |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_basic_valid", "Basic valid", "Success", False |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="initial", |
|
file_path=temp_dir / "initial.py", |
|
line_number=1, |
|
docstring="""Initial function. |
|
|
|
Test Coverage Checklist - initial: |
|
- [ ] boundary_basic_valid: Basic condition |
|
- Expected: Success |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
updated_docstring = self.checker.update_docstring_coverage(func_info) |
|
assert "[x]" in updated_docstring |
|
|
|
def test_update_docstring_coverage_state_modified(self): |
|
"""boundary_state_modified: Multiple docstring updates.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_modified.py" |
|
test_file.write_text(""" |
|
def test_modified_first_valid(): |
|
pass |
|
|
|
def test_modified_second_valid(): |
|
pass |
|
""") |
|
|
|
boundary_conditions1 = [ |
|
BoundaryCondition( |
|
"boundary_first_valid", "First valid", "Success", False |
|
) |
|
] |
|
|
|
boundary_conditions2 = [ |
|
BoundaryCondition( |
|
"boundary_second_valid", "Second valid", "Success", False |
|
) |
|
] |
|
|
|
func_info1 = FunctionInfo( |
|
name="modified", |
|
file_path=temp_dir / "modified.py", |
|
line_number=1, |
|
docstring="""Modified function 1. |
|
|
|
Test Coverage Checklist - modified: |
|
- [ ] boundary_first_valid: First condition |
|
- Expected: Success |
|
""", |
|
boundary_conditions=boundary_conditions1, |
|
test_file_path=test_file, |
|
) |
|
|
|
func_info2 = FunctionInfo( |
|
name="modified", |
|
file_path=temp_dir / "modified.py", |
|
line_number=1, |
|
docstring="""Modified function 2. |
|
|
|
Test Coverage Checklist - modified: |
|
- [ ] boundary_second_valid: Second condition |
|
- Expected: Success |
|
""", |
|
boundary_conditions=boundary_conditions2, |
|
test_file_path=test_file, |
|
) |
|
|
|
result1 = self.checker.update_docstring_coverage(func_info1) |
|
result2 = self.checker.update_docstring_coverage(func_info2) |
|
|
|
assert "[x]" in result1 |
|
assert "[x]" in result2 |
|
|
|
def test_update_docstring_coverage_state_invalid(self): |
|
"""boundary_state_invalid: Invalid test file state.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
invalid_test_file = temp_dir / "invalid.py" |
|
invalid_test_file.write_text("def broken_syntax(\n pass") |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_invalid", "Invalid test", "Error", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="invalid_state", |
|
file_path=temp_dir / "invalid.py", |
|
line_number=1, |
|
docstring="""Invalid function. |
|
|
|
Test Coverage Checklist - invalid_state: |
|
- [ ] boundary_invalid: Invalid condition |
|
- Expected: Error |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=invalid_test_file, |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
# Should handle gracefully |
|
assert isinstance(result, str) |
|
|
|
def test_update_docstring_coverage_return_success(self): |
|
"""boundary_return_success: Successful docstring update.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
test_file = temp_dir / "test_success.py" |
|
test_file.write_text("def test_success_condition_valid(): pass") |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_condition_valid", "Valid condition", "Success", False |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="success", |
|
file_path=temp_dir / "success.py", |
|
line_number=1, |
|
docstring="""Success function. |
|
|
|
Test Coverage Checklist - success: |
|
- [ ] boundary_condition_valid: Test condition |
|
- Expected: Success |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_file, |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
assert "[x]" in result |
|
assert "✅ COVERED:" in result |
|
assert "test_success_condition_valid()" in result |
|
|
|
def test_update_docstring_coverage_return_empty(self): |
|
"""boundary_return_empty: No changes needed.""" |
|
func_info = FunctionInfo( |
|
name="empty_update", |
|
file_path=Path("/tmp/empty.py"), |
|
line_number=1, |
|
docstring="Simple function with no checklist.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
assert result == func_info.docstring |
|
|
|
def test_update_docstring_coverage_return_error(self): |
|
"""boundary_return_error: Non-existent test file.""" |
|
boundary_conditions = [ |
|
BoundaryCondition("boundary_error", "Error condition", "Error", False) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="error_update", |
|
file_path=Path("/tmp/error.py"), |
|
line_number=1, |
|
docstring="""Error function. |
|
|
|
Test Coverage Checklist - error_update: |
|
- [ ] boundary_error: Error condition |
|
- Expected: Error |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=Path("/non/existent/test.py"), |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
# Should remain unchecked since test file doesn't exist |
|
assert "[ ]" in result |
|
|
|
def test_update_docstring_coverage_error_recoverable(self): |
|
"""boundary_error_recoverable: Test file access issues.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
# Create directory instead of file |
|
test_dir = temp_dir / "test_recoverable.py" |
|
test_dir.mkdir() |
|
|
|
boundary_conditions = [ |
|
BoundaryCondition( |
|
"boundary_recoverable", "Recoverable error", "Error", False |
|
) |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="recoverable", |
|
file_path=temp_dir / "recoverable.py", |
|
line_number=1, |
|
docstring="""Recoverable function. |
|
|
|
Test Coverage Checklist - recoverable: |
|
- [ ] boundary_recoverable: Recoverable condition |
|
- Expected: Error |
|
""", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=test_dir, |
|
) |
|
|
|
result = self.checker.update_docstring_coverage(func_info) |
|
# Should handle gracefully |
|
assert isinstance(result, str) |
|
|
|
def test_update_docstring_coverage_error_fatal(self): |
|
"""boundary_error_fatal: Completely invalid FunctionInfo.""" |
|
try: |
|
self.checker.update_docstring_coverage(None) |
|
raise AssertionError("Should raise AttributeError") |
|
except AttributeError: |
|
pass # Expected behavior |
|
|
|
def test_update_docstring_coverage_error_validation(self): |
|
"""boundary_error_validation: Invalid boundary condition data.""" |
|
# Create FunctionInfo with corrupted boundary conditions |
|
boundary_conditions = [ |
|
object() # Not a BoundaryCondition |
|
] |
|
|
|
func_info = FunctionInfo( |
|
name="validation_error", |
|
file_path=Path("/tmp/validation.py"), |
|
line_number=1, |
|
docstring="Validation function.", |
|
boundary_conditions=boundary_conditions, |
|
test_file_path=None, |
|
) |
|
|
|
try: |
|
result = self.checker.update_docstring_coverage(func_info) |
|
# If it succeeds, that's acceptable |
|
assert isinstance(result, str) |
|
except AttributeError: |
|
pass # Expected for invalid boundary condition objects |
|
|
|
|
|
class TestUpdateSourceFile: |
|
"""Test update_source_file method boundary conditions.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_update_source_file_func_info_valid(self): |
|
"""boundary_func_info_valid: Valid FunctionInfo with existing file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "source.py" |
|
source_content = '''def test_function(): |
|
"""Original docstring.""" |
|
pass |
|
''' |
|
source_file.write_text(source_content) |
|
|
|
func_info = FunctionInfo( |
|
name="test_function", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Original docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Updated docstring with new content." |
|
|
|
# This should not raise an error |
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True # If we get here, the function handled it gracefully |
|
|
|
def test_update_source_file_func_info_invalid(self): |
|
"""boundary_func_info_invalid: None or invalid FunctionInfo.""" |
|
updated_docstring = "Some updated content." |
|
|
|
# Should handle None gracefully |
|
try: |
|
self.checker.update_source_file(None, updated_docstring) |
|
except AttributeError: |
|
pass # Expected behavior |
|
|
|
def test_update_source_file_func_info_edge(self): |
|
"""boundary_func_info_edge: FunctionInfo with non-existent file.""" |
|
func_info = FunctionInfo( |
|
name="edge_function", |
|
file_path=Path("/non/existent/file.py"), |
|
line_number=1, |
|
docstring="Edge case.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Updated edge case docstring." |
|
|
|
# Should handle gracefully |
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_updated_docstring_valid(self): |
|
"""boundary_updated_docstring_valid: Valid updated docstring content.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "valid.py" |
|
source_file.write_text( |
|
'def valid_func():\n """Old docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="valid_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Old docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "New valid docstring with proper content." |
|
|
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_updated_docstring_invalid(self): |
|
"""boundary_updated_docstring_invalid: None or empty updated docstring.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "invalid.py" |
|
source_file.write_text( |
|
'def invalid_func():\n """Old docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="invalid_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Old docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
# Test with None |
|
self.checker.update_source_file(func_info, None) |
|
|
|
# Test with empty string |
|
self.checker.update_source_file(func_info, "") |
|
|
|
assert True # Should handle gracefully |
|
|
|
def test_update_source_file_updated_docstring_edge(self): |
|
"""boundary_updated_docstring_edge: Very long or special character docstring.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "edge.py" |
|
source_file.write_text( |
|
'def edge_func():\n """Old docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="edge_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Old docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
# Very long docstring |
|
long_docstring = ( |
|
"A" * 10000 + "\nWith newlines and special chars: 特殊文字 @#$%^&*()" |
|
) |
|
|
|
self.checker.update_source_file(func_info, long_docstring) |
|
assert True |
|
|
|
def test_update_source_file_state_initial(self): |
|
"""boundary_state_initial: First source file update call.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "initial.py" |
|
source_file.write_text( |
|
'def initial_func():\n """Initial docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="initial_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Initial docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "First update to this file." |
|
|
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_state_modified(self): |
|
"""boundary_state_modified: Multiple source file updates.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "modified.py" |
|
source_file.write_text( |
|
'def modified_func():\n """Original docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="modified_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Original docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
# First update |
|
self.checker.update_source_file(func_info, "First update.") |
|
|
|
# Second update |
|
self.checker.update_source_file(func_info, "Second update.") |
|
|
|
assert True |
|
|
|
def test_update_source_file_state_invalid(self): |
|
"""boundary_state_invalid: Corrupted file or invalid Python syntax.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
corrupt_file = temp_dir / "corrupt.py" |
|
corrupt_file.write_text("def broken_syntax(\n pass") # Invalid syntax |
|
|
|
func_info = FunctionInfo( |
|
name="broken_syntax", |
|
file_path=corrupt_file, |
|
line_number=1, |
|
docstring="Some docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Updated despite corruption." |
|
|
|
# Should handle gracefully |
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_return_success(self): |
|
"""boundary_return_success: Successful file update.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "success.py" |
|
source_file.write_text( |
|
'def success_func():\n """Success docstring."""\n return True\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="success_func", |
|
file_path=source_file, |
|
line_number=1, |
|
docstring="Success docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Successfully updated docstring." |
|
|
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_return_empty(self): |
|
"""boundary_return_empty: No matching function found in file.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
source_file = temp_dir / "empty.py" |
|
source_file.write_text( |
|
'def different_func():\n """Different function."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="non_existent_func", # Function doesn't exist in file |
|
file_path=source_file, |
|
line_number=99, # Wrong line number |
|
docstring="Non-existent docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "This won't be updated." |
|
|
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_return_error(self): |
|
"""boundary_return_error: File access errors.""" |
|
import os |
|
|
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
readonly_file = temp_dir / "readonly.py" |
|
readonly_file.write_text( |
|
'def readonly_func():\n """Readonly docstring."""\n pass\n' |
|
) |
|
|
|
# Make file read-only |
|
os.chmod(readonly_file, 0o444) |
|
|
|
func_info = FunctionInfo( |
|
name="readonly_func", |
|
file_path=readonly_file, |
|
line_number=1, |
|
docstring="Readonly docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Cannot update this." |
|
|
|
# Should handle permission error gracefully |
|
self.checker.update_source_file(func_info, updated_docstring) |
|
|
|
# Restore permissions for cleanup |
|
os.chmod(readonly_file, 0o644) |
|
assert True |
|
|
|
def test_update_source_file_error_recoverable(self): |
|
"""boundary_error_recoverable: Encoding or format issues.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
encoding_file = temp_dir / "encoding.py" |
|
|
|
# Write with potential encoding issues |
|
with open(encoding_file, "wb") as f: |
|
f.write( |
|
b'def encoding_func():\n """Encoding docstring."""\n pass\n' |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="encoding_func", |
|
file_path=encoding_file, |
|
line_number=1, |
|
docstring="Encoding docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Updated with encoding." |
|
|
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_error_fatal(self): |
|
"""boundary_error_fatal: Complete file system failure.""" |
|
func_info = FunctionInfo( |
|
name="fatal_func", |
|
file_path=Path("/definitely/invalid/path/file.py"), |
|
line_number=1, |
|
docstring="Fatal docstring.", |
|
boundary_conditions=[], |
|
test_file_path=None, |
|
) |
|
|
|
updated_docstring = "Fatal update attempt." |
|
|
|
# Should handle fatal errors gracefully |
|
self.checker.update_source_file(func_info, updated_docstring) |
|
assert True |
|
|
|
def test_update_source_file_error_validation(self): |
|
"""boundary_error_validation: Invalid parameter types.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
validation_file = temp_dir / "validation.py" |
|
validation_file.write_text( |
|
'def validation_func():\n """Validation docstring."""\n pass\n' |
|
) |
|
|
|
# Test with invalid func_info type |
|
invalid_func_info = "not_a_function_info" |
|
updated_docstring = "Validation test." |
|
|
|
try: |
|
self.checker.update_source_file(invalid_func_info, updated_docstring) |
|
except AttributeError: |
|
pass # Expected for invalid type |
|
|
|
assert True |
|
|
|
|
|
# Tests for generate_report function |
|
class TestGenerateReport: |
|
"""Test the generate_report method.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_generate_report_functions_with_checklists_valid(self): |
|
"""boundary_functions_with_checklists_valid: Valid list of functions with checklists.""" |
|
boundary_condition = BoundaryCondition( |
|
identifier="boundary_test", |
|
description="Test condition", |
|
expected="Test expected", |
|
is_covered=True, |
|
) |
|
|
|
func_info = FunctionInfo( |
|
name="test_func", |
|
file_path=Path("test.py"), |
|
line_number=1, |
|
docstring="Test docstring", |
|
boundary_conditions=[boundary_condition], |
|
) |
|
|
|
report = self.checker.generate_report([func_info], []) |
|
assert report.functions_with_checklists == 1 |
|
assert report.total_boundary_conditions == 1 |
|
assert report.covered_conditions == 1 |
|
|
|
def test_generate_report_functions_with_checklists_invalid(self): |
|
"""boundary_functions_with_checklists_invalid: Invalid or corrupted function data.""" |
|
# Test with corrupted function info |
|
invalid_func = FunctionInfo( |
|
name=None, |
|
file_path=None, |
|
line_number=-1, |
|
docstring=None, |
|
boundary_conditions=[], |
|
) |
|
|
|
report = self.checker.generate_report([invalid_func], []) |
|
assert report.functions_with_checklists == 1 |
|
assert report.total_boundary_conditions == 0 |
|
|
|
def test_generate_report_functions_with_checklists_edge(self): |
|
"""boundary_functions_with_checklists_edge: Empty list or edge cases.""" |
|
report = self.checker.generate_report([], []) |
|
assert report.functions_with_checklists == 0 |
|
assert report.total_boundary_conditions == 0 |
|
assert report.coverage_percentage == 0.0 |
|
|
|
def test_generate_report_functions_without_checklists_valid(self): |
|
"""boundary_functions_without_checklists_valid: Valid list of functions without checklists.""" |
|
func_tuple = ( |
|
"test.py", |
|
"test_func", |
|
ast.FunctionDef( |
|
name="test_func", args=None, body=[], decorator_list=[], returns=None |
|
), |
|
) |
|
|
|
report = self.checker.generate_report([], [func_tuple]) |
|
assert report.functions_without_checklists == 1 |
|
assert report.missing_checklists == [func_tuple] |
|
|
|
def test_generate_report_functions_without_checklists_invalid(self): |
|
"""boundary_functions_without_checklists_invalid: Invalid function data.""" |
|
invalid_tuple = (None, None, None) |
|
|
|
report = self.checker.generate_report([], [invalid_tuple]) |
|
assert report.functions_without_checklists == 1 |
|
|
|
def test_generate_report_functions_without_checklists_edge(self): |
|
"""boundary_functions_without_checklists_edge: Empty list edge case.""" |
|
report = self.checker.generate_report([], []) |
|
assert report.functions_without_checklists == 0 |
|
|
|
def test_generate_report_state_initial(self): |
|
"""boundary_state_initial: First report generation.""" |
|
report = self.checker.generate_report([], []) |
|
assert isinstance(report, CoverageReport) |
|
assert report.total_functions == 0 |
|
|
|
def test_generate_report_state_modified(self): |
|
"""boundary_state_modified: Report after processing multiple functions.""" |
|
boundary1 = BoundaryCondition("boundary_1", "desc1", "exp1", True) |
|
boundary2 = BoundaryCondition("boundary_2", "desc2", "exp2", False) |
|
|
|
func1 = FunctionInfo("func1", Path("test1.py"), 1, "doc1", [boundary1]) |
|
func2 = FunctionInfo("func2", Path("test2.py"), 1, "doc2", [boundary2]) |
|
|
|
report = self.checker.generate_report([func1, func2], []) |
|
assert report.functions_with_checklists == 2 |
|
assert report.covered_conditions == 1 |
|
assert report.coverage_percentage == 50.0 |
|
|
|
def test_generate_report_state_invalid(self): |
|
"""boundary_state_invalid: Report with inconsistent state.""" |
|
# Test with inconsistent data |
|
boundary = BoundaryCondition("boundary_test", "desc", "exp", True) |
|
func_info = FunctionInfo("test", Path("test.py"), 1, "doc", [boundary]) |
|
|
|
# Pass inconsistent data (should still work) |
|
report = self.checker.generate_report([func_info], [("test.py", "test", None)]) |
|
assert report.total_functions == 2 |
|
|
|
def test_generate_report_return_success(self): |
|
"""boundary_return_success: Successful report generation.""" |
|
boundary = BoundaryCondition("boundary_test", "desc", "exp", True) |
|
func_info = FunctionInfo("test", Path("test.py"), 1, "doc", [boundary]) |
|
|
|
report = self.checker.generate_report([func_info], []) |
|
assert isinstance(report, CoverageReport) |
|
assert report.coverage_percentage == 100.0 |
|
|
|
def test_generate_report_return_empty(self): |
|
"""boundary_return_empty: Empty result case.""" |
|
report = self.checker.generate_report([], []) |
|
assert report.total_functions == 0 |
|
assert report.total_boundary_conditions == 0 |
|
assert len(report.missing_tests) == 0 |
|
|
|
def test_generate_report_return_error(self): |
|
"""boundary_return_error: Error conditions in report generation.""" |
|
# Test with extreme edge case that might cause issues |
|
try: |
|
self.checker.generate_report(None, None) |
|
# If it doesn't crash, that's good enough |
|
assert True |
|
except: |
|
# Expected to handle gracefully |
|
assert True |
|
|
|
def test_generate_report_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable error handling.""" |
|
# Test with partially invalid data |
|
valid_boundary = BoundaryCondition("valid", "desc", "exp", True) |
|
invalid_boundary = BoundaryCondition("", "", "", None) |
|
|
|
func_info = FunctionInfo( |
|
"test", Path("test.py"), 1, "doc", [valid_boundary, invalid_boundary] |
|
) |
|
report = self.checker.generate_report([func_info], []) |
|
assert report.total_boundary_conditions == 2 |
|
|
|
def test_generate_report_error_fatal(self): |
|
"""boundary_error_fatal: Fatal error scenarios.""" |
|
# Test with extremely malformed data |
|
try: |
|
malformed_func = object() # Completely wrong type |
|
self.checker.generate_report([malformed_func], []) |
|
except: |
|
assert True # Expected to fail |
|
|
|
def test_generate_report_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Test with wrong types |
|
try: |
|
self.checker.generate_report("not a list", "also not a list") |
|
except: |
|
assert True # Expected validation failure |
|
|
|
|
|
# Tests for check_directory function |
|
class TestCheckDirectory: |
|
"""Test the check_directory method.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_check_directory_directory_valid(self): |
|
"""boundary_directory_valid: Valid directory path.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
py_file = temp_dir / "test.py" |
|
py_file.write_text('def test_func():\n """Test."""\n pass\n') |
|
|
|
report = self.checker.check_directory(temp_dir) |
|
assert isinstance(report, CoverageReport) |
|
|
|
def test_check_directory_directory_invalid(self): |
|
"""boundary_directory_invalid: Invalid directory path.""" |
|
invalid_path = Path("/absolutely/nonexistent/path") |
|
report = self.checker.check_directory(invalid_path) |
|
assert report.total_functions == 0 |
|
|
|
def test_check_directory_directory_edge(self): |
|
"""boundary_directory_edge: Edge cases like empty directory.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
# Empty directory |
|
report = self.checker.check_directory(temp_dir) |
|
assert report.total_functions == 0 |
|
|
|
def test_check_directory_state_initial(self): |
|
"""boundary_state_initial: First directory scan.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
report = self.checker.check_directory(temp_dir) |
|
assert isinstance(report, CoverageReport) |
|
|
|
def test_check_directory_state_modified(self): |
|
"""boundary_state_modified: Directory scan after modifications.""" |
|
self.checker.update_mode = True |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
py_file = temp_dir / "modified.py" |
|
py_file.write_text('def modified_func():\n """Modified."""\n pass\n') |
|
|
|
report = self.checker.check_directory(temp_dir) |
|
assert isinstance(report, CoverageReport) |
|
|
|
def test_check_directory_state_invalid(self): |
|
"""boundary_state_invalid: Directory scan in invalid state.""" |
|
# Test with invalid checker state |
|
self.checker.parser = None |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
try: |
|
self.checker.check_directory(temp_dir) |
|
except: |
|
assert True # Expected to handle gracefully |
|
|
|
def test_check_directory_return_success(self): |
|
"""boundary_return_success: Successful directory scan.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
py_file = temp_dir / "success.py" |
|
py_file.write_text('def success_func():\n """Success."""\n pass\n') |
|
|
|
report = self.checker.check_directory(temp_dir) |
|
assert report.total_functions >= 0 |
|
|
|
def test_check_directory_return_empty(self): |
|
"""boundary_return_empty: Empty directory scan result.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
report = self.checker.check_directory(temp_dir) |
|
assert report.total_functions == 0 |
|
|
|
def test_check_directory_return_error(self): |
|
"""boundary_return_error: Error conditions during scan.""" |
|
# Test with permission denied scenario |
|
invalid_path = Path("/root/forbidden") # Likely permission denied |
|
report = self.checker.check_directory(invalid_path) |
|
assert isinstance(report, CoverageReport) |
|
|
|
def test_check_directory_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors during scan.""" |
|
with tempfile.TemporaryDirectory() as tmpdir: |
|
temp_dir = Path(tmpdir) |
|
# Create a file with encoding issues |
|
bad_file = temp_dir / "bad_encoding.py" |
|
bad_file.write_bytes( |
|
b'def bad():\n """\xe9\x80\x9a\x8b\x97\x8b\x84."""\n pass\n' |
|
) |
|
|
|
report = self.checker.check_directory(temp_dir) |
|
assert isinstance(report, CoverageReport) |
|
|
|
def test_check_directory_error_fatal(self): |
|
"""boundary_error_fatal: Fatal errors during scan.""" |
|
# Test with system-level issues |
|
try: |
|
self.checker.check_directory(None) |
|
except: |
|
assert True # Expected to fail |
|
|
|
def test_check_directory_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Test with wrong input type |
|
try: |
|
self.checker.check_directory("not_a_path_object") |
|
except: |
|
assert True # Expected validation failure |
|
|
|
|
|
# Tests for print_report function |
|
class TestPrintReport: |
|
"""Test the print_report method.""" |
|
|
|
def setup_method(self): |
|
"""Set up test fixtures.""" |
|
self.checker = CoverageChecker() |
|
|
|
def test_print_report_report_valid(self): |
|
"""boundary_report_valid: Valid CoverageReport object.""" |
|
report = CoverageReport() |
|
report.total_functions = 5 |
|
report.coverage_percentage = 80.0 |
|
|
|
# Should not crash |
|
self.checker.print_report(report) |
|
assert True |
|
|
|
def test_print_report_report_invalid(self): |
|
"""boundary_report_invalid: Invalid or corrupted report data.""" |
|
invalid_report = object() # Wrong type |
|
|
|
try: |
|
self.checker.print_report(invalid_report) |
|
except: |
|
assert True # Expected to fail with wrong type |
|
|
|
def test_print_report_report_edge(self): |
|
"""boundary_report_edge: Edge cases like empty report.""" |
|
empty_report = CoverageReport() |
|
|
|
# Should handle empty report gracefully |
|
self.checker.print_report(empty_report) |
|
assert True |
|
|
|
def test_print_report_state_initial(self): |
|
"""boundary_state_initial: First report print.""" |
|
report = CoverageReport() |
|
|
|
self.checker.print_report(report) |
|
assert True |
|
|
|
def test_print_report_state_modified(self): |
|
"""boundary_state_modified: Report printing after modifications.""" |
|
report = CoverageReport() |
|
report.missing_tests = [("func1", "boundary_test", "test.py")] |
|
report.missing_checklists = [("test.py", "func2", None)] |
|
|
|
self.checker.print_report(report) |
|
assert True |
|
|
|
def test_print_report_state_invalid(self): |
|
"""boundary_state_invalid: Report printing in invalid state.""" |
|
report = CoverageReport() |
|
report.coverage_percentage = float("inf") # Invalid percentage |
|
|
|
try: |
|
self.checker.print_report(report) |
|
assert True |
|
except: |
|
assert True # Either works or fails gracefully |
|
|
|
def test_print_report_return_success(self): |
|
"""boundary_return_success: Successful report printing.""" |
|
report = CoverageReport() |
|
report.total_functions = 3 |
|
report.functions_with_checklists = 2 |
|
report.coverage_percentage = 75.0 |
|
|
|
# Should complete without issues |
|
self.checker.print_report(report) |
|
assert True |
|
|
|
def test_print_report_return_empty(self): |
|
"""boundary_return_empty: Empty report printing.""" |
|
empty_report = CoverageReport() |
|
|
|
self.checker.print_report(empty_report) |
|
assert True |
|
|
|
def test_print_report_return_error(self): |
|
"""boundary_return_error: Error conditions during printing.""" |
|
# Test with None report |
|
try: |
|
self.checker.print_report(None) |
|
except: |
|
assert True # Expected to fail |
|
|
|
def test_print_report_error_recoverable(self): |
|
"""boundary_error_recoverable: Recoverable errors during printing.""" |
|
report = CoverageReport() |
|
report.missing_tests = [("func", "boundary", None)] # None path |
|
|
|
try: |
|
self.checker.print_report(report) |
|
assert True |
|
except: |
|
assert True # Should handle gracefully |
|
|
|
def test_print_report_error_fatal(self): |
|
"""boundary_error_fatal: Fatal errors during printing.""" |
|
# Test with extremely malformed report |
|
malformed_report = CoverageReport() |
|
malformed_report.missing_tests = "not_a_list" |
|
|
|
try: |
|
self.checker.print_report(malformed_report) |
|
except: |
|
assert True # Expected to fail |
|
|
|
def test_print_report_error_validation(self): |
|
"""boundary_error_validation: Input validation failures.""" |
|
# Test with wrong type completely |
|
try: |
|
self.checker.print_report("not_a_report") |
|
except: |
|
assert True # Expected validation failure |