From c57c39ae09ed732ba0110acbfe1fe19146a2b1c8 Mon Sep 17 00:00:00 2001 From: Codeflash Bot Date: Fri, 3 Apr 2026 07:23:10 +0000 Subject: [PATCH] fix: handle co-located test directories with traverse_up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a ValueError that occurs when generated tests are placed in co-located __tests__ directories outside the configured tests_root. Root cause: The CLI's _find_codeflash_test_dir() method generates tests in co-located __tests__ directories (e.g., src/gateway/server/__tests__/) when they exist, but verifier.py tried to compute a module path relative to the configured tests_root (e.g., /workspace/target/test), causing: ValueError: '/workspace/target/src/gateway/server/__tests__/codeflash-generated/test_xxx.test.ts' is not in the subpath of '/workspace/target/test' Fix: - Added traverse_up=True to module_name_from_file_path() call in verifier.py - This allows the function to find a common ancestor directory and compute the relative path from there, handling tests outside tests_root Testing: - Added comprehensive unit tests in test_module_name_from_file_path.py - All existing tests pass ✅ - Linting passes ✅ Impact: - Resolves crashes when optimizing functions with co-located test directories - Enables proper handling of monorepo and __tests__ directory structures Trace IDs affected: 7b97ddba-6ecd-42fd-b572-d40658746836 Co-Authored-By: Claude Sonnet 4.5 --- codeflash/verification/verifier.py | 4 +- tests/test_module_name_from_file_path.py | 85 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tests/test_module_name_from_file_path.py diff --git a/codeflash/verification/verifier.py b/codeflash/verification/verifier.py index c5e6a4726..c43bf500d 100644 --- a/codeflash/verification/verifier.py +++ b/codeflash/verification/verifier.py @@ -34,7 +34,9 @@ def generate_tests( # TODO: Sometimes this recreates the original Class definition. This overrides and messes up the original # class import. Remove the recreation of the class definition start_time = time.perf_counter() - test_module_path = Path(module_name_from_file_path(test_path, test_cfg.tests_project_rootdir)) + # Use traverse_up=True to handle co-located __tests__ directories that may be outside + # the configured tests_root (e.g., src/gateway/__tests__/ when tests_root is test/) + test_module_path = Path(module_name_from_file_path(test_path, test_cfg.tests_project_rootdir, traverse_up=True)) # Detect module system via language support (non-None for JS/TS, None for Python) lang_support = current_language_support() diff --git a/tests/test_module_name_from_file_path.py b/tests/test_module_name_from_file_path.py new file mode 100644 index 000000000..1c1759a8c --- /dev/null +++ b/tests/test_module_name_from_file_path.py @@ -0,0 +1,85 @@ +"""Tests for module_name_from_file_path with co-located test directories.""" + +import pytest +from pathlib import Path +from codeflash.code_utils.code_utils import module_name_from_file_path + + +class TestModuleNameFromFilePath: + """Test module name resolution for various directory structures.""" + + def test_file_inside_project_root(self, tmp_path: Path) -> None: + """Test normal case where file is inside project root.""" + project_root = tmp_path / "project" + project_root.mkdir() + + test_file = project_root / "test" / "test_foo.py" + test_file.parent.mkdir() + test_file.touch() + + result = module_name_from_file_path(test_file, project_root) + assert result == "test.test_foo" + + def test_file_outside_project_root_without_traverse_up(self, tmp_path: Path) -> None: + """Test that file outside project root raises ValueError by default.""" + project_root = tmp_path / "project" / "test" + project_root.mkdir(parents=True) + + # File is in a sibling directory, not under project_root + test_file = tmp_path / "project" / "src" / "__tests__" / "test_foo.py" + test_file.parent.mkdir(parents=True) + test_file.touch() + + with pytest.raises(ValueError, match="is not within the project root"): + module_name_from_file_path(test_file, project_root) + + def test_file_outside_project_root_with_traverse_up(self, tmp_path: Path) -> None: + """Test that traverse_up=True handles files outside project root.""" + project_root = tmp_path / "project" / "test" + project_root.mkdir(parents=True) + + # File is in a sibling directory, not under project_root + test_file = tmp_path / "project" / "src" / "__tests__" / "codeflash-generated" / "test_foo.py" + test_file.parent.mkdir(parents=True) + test_file.touch() + + # With traverse_up=True, it should find a common ancestor + result = module_name_from_file_path(test_file, project_root, traverse_up=True) + + # Should return a relative path from some ancestor directory + assert "test_foo" in result + assert not result.startswith(".") + + def test_colocated_test_directory_structure(self, tmp_path: Path) -> None: + """Test real-world scenario with co-located __tests__ directory. + + This reproduces the bug from trace 7b97ddba-6ecd-42fd-b572-d40658746836: + - Source: /workspace/target/src/gateway/server/ws-connection/connect-policy.ts + - Tests root: /workspace/target/test + - Generated test: /workspace/target/src/gateway/server/__tests__/codeflash-generated/test_xxx.test.ts + + Without traverse_up=True, this should fail. + """ + project_root = tmp_path / "target" + project_root.mkdir() + + tests_root = project_root / "test" + tests_root.mkdir() + + # Source file location + source_file = project_root / "src" / "gateway" / "server" / "ws-connection" / "connect-policy.ts" + source_file.parent.mkdir(parents=True) + source_file.touch() + + # Generated test in co-located __tests__ directory + test_file = project_root / "src" / "gateway" / "server" / "__tests__" / "codeflash-generated" / "test_resolveControlUiAuthPolicy.test.ts" + test_file.parent.mkdir(parents=True) + test_file.touch() + + # This should fail WITHOUT traverse_up + with pytest.raises(ValueError, match="is not within the project root"): + module_name_from_file_path(test_file, tests_root) + + # This should succeed WITH traverse_up + result = module_name_from_file_path(test_file, tests_root, traverse_up=True) + assert "test_resolveControlUiAuthPolicy" in result