codeflash/tests/test_file_to_no_of_tests.py

474 lines
18 KiB
Python
Raw Normal View History

2025-11-13 00:46:11 +00:00
"""Comprehensive unit tests for TestResults.file_to_no_of_tests method."""
from collections import Counter
2025-11-13 01:19:54 +00:00
from pathlib import Path
from codeflash.models.models import FunctionTestInvocation, InvocationId, TestResults, TestType
2025-11-13 00:46:11 +00:00
class TestFileToNoOfTests:
2025-11-13 01:19:54 +00:00
"""Test suite for TestResults.file_to_no_of_tests method."""
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_empty_test_results(self):
"""Test with empty test results."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
assert counter == Counter()
assert len(counter) == 0
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_empty_test_functions_to_remove(self):
"""Test with empty list of test functions to remove."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name="test_function",
function_getting_tested="target_func",
iteration_id="1",
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
assert counter == Counter({Path("/tmp/test_file.py"): 1})
def test_single_test_not_removed(self):
"""Test with a single test that should not be removed."""
test_results = TestResults()
2025-11-13 00:46:11 +00:00
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name="test_keep",
function_getting_tested="target_func",
iteration_id="1",
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests(["test_remove"])
assert counter == Counter({Path("/tmp/test_file.py"): 1})
def test_single_test_removed(self):
"""Test with a single test that should be removed."""
test_results = TestResults()
2025-11-13 00:46:11 +00:00
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name="test_remove",
function_getting_tested="target_func",
iteration_id="1",
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests(["test_remove"])
assert counter == Counter()
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_multiple_tests_same_file(self):
"""Test with multiple tests in the same file."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
for i in range(5):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=f"test_func_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
)
counter = test_results.file_to_no_of_tests([])
assert counter == Counter({Path("/tmp/test_file.py"): 5})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_multiple_tests_different_files(self):
"""Test with multiple tests in different files."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
files = [Path(f"/tmp/test_file_{i}.py") for i in range(3)]
for i, file_path in enumerate(files):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path=f"test.module{i}",
test_class_name="TestClass",
test_function_name=f"test_func_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=file_path,
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
2025-11-13 00:46:11 +00:00
)
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
expected = Counter({files[0]: 1, files[1]: 1, files[2]: 1})
assert counter == expected
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_mixed_test_types(self):
"""Test with different test types - only GENERATED_REGRESSION should be counted."""
test_results = TestResults()
test_types = [
TestType.EXISTING_UNIT_TEST,
TestType.INSPIRED_REGRESSION,
TestType.GENERATED_REGRESSION,
TestType.REPLAY_TEST,
TestType.CONCOLIC_COVERAGE_TEST,
TestType.INIT_STATE_TEST,
]
for i, test_type in enumerate(test_types):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=f"test_func_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=Path(f"/tmp/test_file_{i}.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=test_type,
return_value=None,
timed_out=False,
loop_index=1,
)
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
# Only the GENERATED_REGRESSION test should be counted
assert counter == Counter({Path("/tmp/test_file_2.py"): 1})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_partial_removal(self):
"""Test removing some but not all tests from a file."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
test_names = ["test_keep_1", "test_remove_1", "test_keep_2", "test_remove_2"]
for name in test_names:
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=name,
function_getting_tested="target_func",
iteration_id=name,
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests(["test_remove_1", "test_remove_2"])
assert counter == Counter({Path("/tmp/test_file.py"): 2}) # Only test_keep_1 and test_keep_2
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_none_test_function_name(self):
"""Test with None test_function_name."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=None,
function_getting_tested="target_func",
iteration_id="1",
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
# None should not match any string in test_functions_to_remove
counter = test_results.file_to_no_of_tests(["test_remove"])
assert counter == Counter({Path("/tmp/test_file.py"): 1})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_duplicate_file_paths(self):
"""Test counting with duplicate file paths across multiple tests."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
file_path = Path("/tmp/test_file.py")
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
# Add multiple tests with the same file path
for i in range(3):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=f"test_func_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=file_path,
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
assert counter == Counter({file_path: 3})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_complex_scenario(self):
"""Test complex scenario with mixed conditions."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
# File 1: Mix of test types
for i, test_type in enumerate([TestType.GENERATED_REGRESSION, TestType.EXISTING_UNIT_TEST]):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module1",
test_class_name="TestClass",
test_function_name=f"test_file1_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=Path("/tmp/file1.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=test_type,
return_value=None,
timed_out=False,
loop_index=1,
)
2025-11-13 00:46:11 +00:00
)
2025-11-13 01:19:54 +00:00
# File 2: Tests to be removed and kept
for name in ["test_keep", "test_remove"]:
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module2",
test_class_name="TestClass",
test_function_name=name,
function_getting_tested="target_func",
iteration_id=name,
),
file_name=Path("/tmp/file2.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
2025-11-13 00:46:11 +00:00
)
2025-11-13 01:19:54 +00:00
# File 3: All GENERATED_REGRESSION tests
for i in range(3):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module3",
test_class_name="TestClass",
test_function_name=f"test_file3_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=Path("/tmp/file3.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests(["test_remove"])
2026-01-29 09:39:48 +00:00
expected = Counter(
{
Path("/tmp/file1.py"): 1, # Only 1 GENERATED_REGRESSION test
Path("/tmp/file2.py"): 1, # Only test_keep (test_remove is excluded)
Path("/tmp/file3.py"): 3, # All 3 tests
}
)
2025-11-13 01:19:54 +00:00
assert counter == expected
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_case_sensitivity(self):
"""Test that function name matching is case-sensitive."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name="Test_Function",
function_getting_tested="target_func",
iteration_id="1",
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
# Should not remove because case doesn't match
counter = test_results.file_to_no_of_tests(["test_function"])
assert counter == Counter({Path("/tmp/test_file.py"): 1})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
# Should remove with correct case
counter = test_results.file_to_no_of_tests(["Test_Function"])
assert counter == Counter()
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_windows_paths(self):
"""Test with Windows-style paths."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
windows_path = Path("C:\\Users\\test\\test_file.py")
2025-11-13 00:46:11 +00:00
test_results.add(
2025-11-13 01:19:54 +00:00
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name="test_func",
function_getting_tested="target_func",
iteration_id="1",
),
file_name=windows_path,
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
)
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
assert counter == Counter({windows_path: 1})
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_relative_and_absolute_paths(self):
"""Test with both relative and absolute paths."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
paths = [
Path("/absolute/path/test.py"),
Path("relative/path/test.py"),
Path("./current/dir/test.py"),
Path("../parent/dir/test.py"),
]
for i, path in enumerate(paths):
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path=f"test.module{i}",
test_class_name="TestClass",
test_function_name=f"test_func_{i}",
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=path,
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
2025-11-13 00:46:11 +00:00
)
2025-11-13 01:19:54 +00:00
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests([])
2026-01-29 09:39:48 +00:00
expected = Counter(dict.fromkeys(paths, 1))
2025-11-13 01:19:54 +00:00
assert counter == expected
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
def test_large_removal_list(self):
"""Test with a large list of functions to remove."""
2025-11-13 00:46:11 +00:00
test_results = TestResults()
2025-11-13 01:19:54 +00:00
num_tests = 100
removal_list = [f"test_remove_{i}" for i in range(50)]
for i in range(num_tests):
test_name = f"test_remove_{i}" if i < 50 else f"test_keep_{i}"
test_results.add(
FunctionTestInvocation(
id=InvocationId(
test_module_path="test.module",
test_class_name="TestClass",
test_function_name=test_name,
function_getting_tested="target_func",
iteration_id=str(i),
),
file_name=Path("/tmp/test_file.py"),
did_pass=True,
runtime=100,
test_framework="pytest",
test_type=TestType.GENERATED_REGRESSION,
return_value=None,
timed_out=False,
loop_index=1,
)
)
2025-11-13 00:46:11 +00:00
2025-11-13 01:19:54 +00:00
counter = test_results.file_to_no_of_tests(removal_list)
2026-01-29 09:39:48 +00:00
assert counter == Counter({Path("/tmp/test_file.py"): 50}) # 50 kept, 50 removed