The conftest.py autouse fixture already resets _current_language before/after
each test, making per-test try/finally cleanup unnecessary.
Co-authored-by: Kevin Turcios <KRRT7@users.noreply.github.com>
test_parse_line_profile_results_non_python_java_json set Language.JAVA
but never reset it, causing test_java_diff_ignored_when_language_is_python
to fail when tests ran in this order.
Co-authored-by: Kevin Turcios <KRRT7@users.noreply.github.com>
- Fix bug: skip attrs classes with init=False (no __init__ to patch)
- Deduplicate attrs namespace/name sets into shared constants
- Fix _get_attrs_config to resolve import aliases properly
- Add test for init=False case with exact expected output
Instead of skipping attrs classes entirely (previous approach), emit a
module-level patch block immediately after the class definition:
_codeflash_orig_ClassName_init = ClassName.__init__
def _codeflash_patched_ClassName_init(self, *args, **kwargs):
return _codeflash_orig_ClassName_init(self, *args, **kwargs)
ClassName.__init__ = codeflash_capture(...)(_codeflash_patched_ClassName_init)
This sidesteps the __class__ cell TypeError that attrs(slots=True) triggers
when a synthetic super().__init__() body is injected into the original class,
because the patched wrapper is a plain module-level function with no __class__
cell.
Changes:
- InitDecorator.__init__: add _attrs_classes_to_patch dict
- visit_ClassDef: for attrs classes, record (name -> decorator) instead of
returning immediately; set inserted_decorator=True
- visit_Module: splice patch block statements after each attrs ClassDef
- _build_attrs_patch_block: new helper that builds the 3-statement AST block
- Tests: rename *_no_init_skipped -> *_patched_via_module_wrapper and update
expected strings to assert the exact generated patch block
Co-Authored-By: Oz <oz-agent@warp.dev>
- instrument_codeflash_capture: detect @attrs.define / @attr.s / etc. in the
'no explicit __init__' branch and return early, same as dataclass/NamedTuple.
Prevents a TypeError caused by attrs(slots=True) creating a new class whose
__class__ cell no longer matches the injected super().__init__ wrapper.
- code_context_extractor: add _get_attrs_config() helper; update
_collect_synthetic_constructor_type_names, _build_synthetic_init_stub, and
_extract_synthetic_init_parameters to handle attrs field conventions
(factory= keyword, init=False, kw_only).
- tests: add 3 exact-output tests for instrumentation skip behaviour and
3 exact-output tests for attrs stub generation.
Co-Authored-By: Oz <oz-agent@warp.dev>
When codeflash runs with --subagent (e.g., via the Claude Code plugin),
exit_with_message() now outputs <codeflash-error> XML to stdout instead
of Rich panel text. This lets the calling agent parse errors
programmatically rather than receiving unstructured text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
get_git_diff() hardcoded `.py` as the only valid file extension, causing
the auto-detect flow (no --file flag) to return 0 functions for Java,
JavaScript, and TypeScript projects. This broke the Claude Code plugin
integration where the hook runs `codeflash --subagent` without --file.
Now uses current_language_support().file_extensions to filter by the
active language's extensions dynamically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers setup_test_config symlinking node_modules from original repo
to worktree, including edge cases (no worktree, missing node_modules,
already existing node_modules).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The function was removed in the dead code cleanup but the test file still
imported it and had a TestCreatePyprojectToml class, causing ImportError.
Co-authored-by: Kevin Turcios <undefined@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runtime annotations in PR descriptions were broken in two ways:
1. add_runtime_comments() ignored class/method prefixes in keys, causing
annotations from unrelated test classes to leak across files and sum
incorrectly at the same line number. Now filters by class names found
in each test source file.
2. Test functions were removed before annotations were added, shifting
line numbers so annotations landed on wrong lines. Swapped ordering
so annotations are applied first, then function removal carries them
along correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build test_count_cache once before ranking instead of calling
existing_unit_test_count O(2N) times. Guard for None function_to_tests
and add debug logging when effort is escalated from medium to high.
Parse each file once instead of up to 16 times by:
- Making remove_unused_definitions_by_function_names accept/return cst.Module
- Making parse_code_and_prune_cst and add_needed_imports_from_module accept cst.Module
- Threading the parsed Module through process_file_context
- Adding extract_all_contexts_from_files that processes all 4 context types
(READ_WRITABLE, READ_ONLY, HASHING, TESTGEN) in a single per-file pass
review_generated_tests and repair_generated_tests called add_language_metadata
without language_version, sending python_version=None to the API which rejects
with "Python version is required". Now falls back to current_language_support().
- Add existing_unit_test_count() with parametrized test deduplication
- Stable-sort ranked functions so tested ones come first
- Enable reference graph resolver (was disabled) for non-CI runs
- Add per-function logging with ref count and test count
- Auto-upgrade top N functions to high effort when user hasn't set --effort
- Add CallGraph model with traversal (BFS, topological sort, subgraph)
- Add get_call_graph() to DependencyResolver protocol and ReferenceGraph
- Refactor get_callees() to delegate through get_call_graph()
CF-1660
Cover all detection paths: Java (pom.xml, build.gradle, build.gradle.kts),
TypeScript, JavaScript, Python, empty directory fallback, and priority
resolution when multiple build system markers coexist.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When optimized JS/TS code introduces new global declarations (const, Set, etc.),
add_global_declarations inserts them into the original source, shifting the target
function's line numbers. The stale starting_line from function_to_optimize then
causes _replace_function_body to fail with "Could not find function X at line Y".
This affected ~666 function replacements in the Strapi optimization run, including
bytesToHumanReadable, isSelectable, getFileIconComponent, and many others.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update TestJestRootsConfiguration to match the new runtime config
approach: verify no --roots/config when tests are inside the project
root, and verify runtime config creation when tests are outside it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added functions to install the Codeflash runtime and manage its dependency in the Maven POM file.
- Implemented JaCoCo plugin addition and configuration for test coverage.
- Enhanced XML parsing for POM files to support both namespaced and non-namespaced formats.
- Updated test cases to reflect changes in dependency management and plugin configuration.
- Removed obsolete runtime jar finding logic and consolidated module detection for both Maven and Gradle projects.
- Improved input validation for test run commands.
- Updated tests in `test_java_multimodule_deps_install.py` to utilize `MavenStrategy` for installing multi-module dependencies.
- Changed function calls from `ensure_multi_module_deps_installed` to `MavenStrategy.install_multi_module_deps`.
- Added a fixture for `MavenStrategy` to streamline test setup.
- Modified assertions and mock setups to align with the new strategy implementation.
- Refactored tests in `test_java_test_filter_validation.py` to replace `_run_maven_tests` with `MavenStrategy.run_tests_via_build_tool`.
- Adjusted test cases to ensure proper handling of empty and valid test filters.
- Updated mock setups for Maven executable and command execution to reflect changes in the strategy.
Node.js subprocess pipe behavior causes the test to hang on Windows
(returncode=1 but stdout reader thread blocks beyond 10s timeout).
Co-authored-by: Aseem Saxena <aseembits93@users.noreply.github.com>
_expr_name now recurses into ast.Attribute to produce the full dotted
path (e.g. "dataclasses.dataclass", "typing.NamedTuple"). Callers use
.endswith() so both bare and module-qualified forms are matched. Adds
test for typing.NamedTuple base class.
NamedTuples have a synthesized __init__ that cannot be overwritten.
The instrumentation was missing a skip check (like the existing one
for dataclasses), causing "Cannot overwrite NamedTuple attribute
__init__" errors that crashed the test subprocess and produced 0%
coverage.
Also removes duplicate docstring in make_ai_service_request.
- Extract CODEFLASH_RUNTIME_VERSION and CODEFLASH_RUNTIME_JAR_NAME constants
in build_tools.py, replacing 15+ hardcoded "1.0.0" references across
test_runner.py, comparator.py, and line_profiler.py
- Cache _ensure_codeflash_runtime() results so it runs once per optimization
instead of 3 times (behavioral, benchmarking, line profiling phases)
- Add backup_pom/restore_pom/restore_all_pom_backups to build_tools.py so
pom.xml modifications (codeflash-runtime dependency, JaCoCo plugin) are
always reverted after optimization completes, even on crashes
- Call restore_all_pom_backups() in function_optimizer.py's finally block
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dataclass __init__ is auto-generated at class creation time and not
present in the AST. The instrumentor was injecting a synthetic __init__
with super().__init__(*args, **kwargs) which calls object.__init__()
and fails because dataclass fields are passed as kwargs.
Now only skips when the class is a @dataclass AND has no explicit
__init__. Dataclasses with custom __init__ are still instrumented.
Replace substring assertions (e.g. `"// 2.89ms ->" in lines[7]`) with
exact full-output comparisons for better regression detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The base class had duplicate _get_java_sources_root and _fix_java_test_paths
methods that were overridden by JavaFunctionOptimizer. The base class also
had an is_java() block in generate_and_instrument_tests that used undefined
variables (used_behavior_paths, is_java). Removed all dead code since
JavaFunctionOptimizer.fixup_generated_tests handles this properly.
Also updated JavaFunctionOptimizer._fix_java_test_paths to accept
display_source parameter and use whole-word rename for collision handling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Windows backslashes in paths embedded into JavaScript strings are
interpreted as escape sequences by Node.js, corrupting the module path.
Use .as_posix() to emit forward slashes which Node accepts on all platforms.
Co-authored-by: Kevin Turcios <KRRT7@users.noreply.github.com>
Initialize conn to None before try blocks and guard finally with
if conn is not None to prevent NameError if sqlite3.connect() raises.
Co-authored-by: Kevin Turcios <KRRT7@users.noreply.github.com>
Inner-class methods are intentionally skipped by Java discovery
(PR #1726) since instrumentation is name-only and not class-aware.
Update test to expect False from replacement.
Take omni-main-java's fix for E2E test runner path resolution —
uses os.path.relpath from __file__ instead of hardcoded relative path.
Also adds codeflash.toml detection for Java projects.
- Update test_inject_profiling_used_frameworks, test_async_run_and_parse,
test_pickle_patcher to use new inject_profiling_into_existing_test API
(test_string param removed)
- Add parse_line_profile_results function to parse_line_profile_test_output
module (imported by main's PythonFunctionOptimizer and test_instrument_tests)
Merges the omni-main-java branch which synced main into omni-java,
including JavaFunctionOptimizer, removal of is_java()/is_python() guards,
protocol dispatch for parse_test_xml, and deletion of concolic_testing.py.
Fix 10 failing tests: remove wrong assertions expecting import statements
inside extracted class code, use substring matching for UserDict class
signature, and rewrite click-dependent tests as project-local equivalents.
Add tests for resolve_instance_class_name, enhanced extract_init_stub_from_class,
and enrich_testgen_context instance resolution.
- Use instrumented class name in _cf_mod/_cf_cls markers to disambiguate
existing vs generated tests sharing the same original class name
- Encode line number in invocation IDs (L{line}_{counter}) for deterministic
call-site identification in inline runtime comments
- Rewrite add_runtime_comments() to annotate each call line with inline
performance data instead of a summary block at top
- Strip assertions before instrumenting so both modes share the same base source
- Update test expected strings for new marker format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts ed2594bf which added --pool=forks to Vitest commands and
changed capture.js to use process.stdout.write and Vitest worker API.
These changes broke JS E2E tests (CJS, ESM, TS class) by altering
how all JS tests run, not just Vitest benchmarking.
The AI backend generates vitest/jest-style imports for Mocha projects.
Our sanitize_mocha_imports() stripped ESM `import { ... } from 'vitest'`,
but process_generated_test_strings() runs BEFORE postprocessing and calls
ensure_module_system_compatibility() which converts these to CJS requires.
Result: `const { ... } = require('vitest')` survived sanitization.
Added regexes for the CJS variants of vitest and @jest/globals requires.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: Vitest performance tests reported "20.0 seconds over 1 loop"
(JUnit XML wall-clock fallback) instead of actual per-function nanosecond
timing. This was a chain of two issues:
1. **stdout interception**: Vitest's default `threads` pool intercepts
process.stdout.write() and console.log(), preventing timing markers
from flowing to the parent process. Fixed by adding `--pool=forks`
to all Vitest commands and config files. The `forks` pool uses child
processes where stdout flows directly to the parent.
2. **test name detection**: Even after markers flowed through (43,000+
found in stdout), the parser couldn't match them to JUnit XML
testcases because all markers had "unknown" as the test name. This
happened because Vitest doesn't inject `beforeEach` as a global
(unlike Jest), so capture.js's Jest-style hook to set
`currentTestName` never fired.
Fixed by adding Vitest-specific test name detection in capture.js:
- Primary: `expect.getState().currentTestName` (full describe path)
- Fallback: `__vitest_worker__.current.fullTestName`
- Defense-in-depth: parser fallback matches "unknown" markers to
the first testcase when no name match is found
Result: cheerio's `isHtml` went from "20.0s / 1 loop" to
"902μs / 20,853 loops" with proper speedup analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three related fixes for Mocha test generation in CommonJS projects:
1. inject_test_globals() now accepts module_system param — emits
`require('node:assert/strict')` for CJS instead of ESM import syntax
2. ensure_module_system_compatibility() now converts ESM→CJS even when
the source has mixed imports (was skipping when both ESM and CJS were
detected, leaving the ESM import from inject_test_globals unconverted)
3. New sanitize_mocha_imports() strips vitest/jest/@jest/globals imports
that the AI sometimes generates for Mocha projects — Mocha provides
describe/it/before*/after* as globals
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ship a zero-dependency jest-reporter.js inside the codeflash runtime package
instead of requiring the external jest-junit npm package. This ensures the
reporter is always available when codeflash is installed, fixing Jest-based
projects (Strapi, Moleculer) that failed because jest-junit wasn't installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nested functions are now skipped by FunctionVisitor, and
discover_functions no longer swallows parse/IO errors — callers
handle them. Update test expectations accordingly.
When testsRoot overlaps moduleRoot (common in JS/TS monorepos like Ghost
where both point to "src"), the directory-based filter incorrectly
excluded ALL source files. Switch to filename/directory pattern matching
(*.test.*, *.spec.*, __tests__/) when roots overlap, preserving the
existing directory-based filter for standard layouts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow init_js_project(), should_modify_package_json_config(), and
collect_js_setup_info() to run without interactive prompts when
skip_confirm=True. Uses auto-detected defaults instead of prompting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NotImplementedError guard in all 3 test dispatchers (behavioral,
benchmarking, line-profile) for frameworks other than jest and vitest.
Previously, mocha and other frameworks silently fell through to Jest,
causing confusing failures. Now users get a clear error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve `module.exports = varName` where varName is an object literal
containing methods. For patterns like `const utils = { match() {} };
module.exports = utils;`, the individual methods are now recognized as
exported. This fixes function discovery for CJS libraries like Moleculer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Post-process find_functions() to mark functions as exported when they appear
in named export clauses like `export { joinBy }`. This fixes discovery for
TypeScript codebases (e.g., Strapi) that define const arrow functions and
export them via a separate export statement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
parse_code_and_prune_cst now returns cst.Module instead of str.
add_needed_imports_from_module accepts cst.Module | str, skipping re-parse
when a Module is passed. This eliminates the string round-trip that caused
comments to migrate from statement leading_lines to Module.header,
resulting in comments appearing above imports instead of at their
original position.
Cache inspect.getmembers() results per module so repeated loop
iterations skip the expensive rescan. Add tests for get_runtime_from_stdout,
should_stop, _set_nodeid, _get_total_time, _timed_out, logreport, and
setup/teardown hooks.
Objects with __slots__ but no __dict__ (e.g. textual.cache.LRUCache)
fell through all comparator branches, logging "Unknown comparator input
type" and returning False — causing spurious test mismatches.
The comparator did not recognize `types.UnionType` (Python 3.10+ `X | Y`
syntax), causing it to fall through to "Unknown comparator input type".
Conditionally include it in the equality-checked types tuple.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handle itertools.cycle on Python 3.14 where __reduce__ was removed by
falling back to element-by-element sampling. Add version guards for
pairwise (3.10+) and batched (3.12+) tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a catch-all handler for itertools iterators (chain, islice, product,
permutations, combinations, starmap, accumulate, compress, dropwhile,
takewhile, filterfalse, zip_longest, groupby, pairwise, batched, tee).
Uses module check (type.__module__ == "itertools") so it automatically
covers any itertools type without version-specific enumeration. groupby
gets special handling to also materialize its group iterators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
itertools.repeat uses repr() comparison (same approach as count).
itertools.cycle uses __reduce__() to extract internal state (saved items,
remaining items, and first-pass flag) since repr() only shows a memory
address. The __reduce__ approach is deprecated in 3.14 but is the only
way to access cycle state without consuming elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The comparator had no handler for itertools.count (an infinite iterator),
causing it to fall through all type checks and return False even for
equal objects. Use repr() comparison which reliably reflects internal
state and avoids the __reduce__ deprecation coming in Python 3.14.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add class_name and qualified_name to /testgen API payload so the backend
has explicit access to computed FunctionToOptimize properties
- Add client-side _fix_java_test_class_name() to correct wrong class name
references in LLM-generated Java test code
- Remove per-test @Timeout annotation from Java instrumentation (causes
timing instability on CI runners; Maven Surefire handles timeouts)
- Remove redundant default_language_version, use language_version as canonical
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Multi-module Maven projects like Guava fail on sequential Maven invocations
because compiler plugin 3.15.0's JDK-8318913 workaround patches module-info.class
timestamps, triggering unnecessary recompilation with -am that fails on partial
reactor rebuilds. This pre-installs deps to .m2 once, then drops -am from all
subsequent test commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove redundant condition check in add_codeflash_dependency_to_pom
- Use lookahead-based regex to handle arbitrary XML element order in
system-scope dependency replacement
- Broaden class declaration pattern to match final/abstract modifiers
- Add 7 unit tests for add_codeflash_dependency_to_pom including
stale system-scope replacement and reordered XML elements
- Clarify comment about @SuppressWarnings in both modes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add @SuppressWarnings("CheckReturnValue") to all generated instrumented test
classes. Projects using Error Prone (e.g. Guava) enforce CheckReturnValue as a
compiler error, which rejects our performance-only tests that intentionally
discard return values after assertion stripping.
Also fix add_codeflash_dependency_to_pom to detect and replace stale
system-scope dependencies left by previous runs with the correct test scope.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test previously expected empty databases to return equivalent=True,
which was the exact bug being fixed. Updated to assert equivalent=False.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The type inference for assertEquals always used the first argument, but
JUnit 4's 3-arg overload is assertEquals(message, expected, actual).
When the first arg was a string message, the type was incorrectly inferred
as String instead of the actual expected value's type. Now detects the
message-first pattern and uses the second argument for type inference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update 41 test expectations in test_java_assertion_removal.py to match
the return type inference behavior introduced in commit 9e5880f0. Tests
now expect inferred types (int, boolean, String, double) instead of
Object for _cf_result variables.
Fix 2 ruff PLR1714 lint issues in remove_asserts.py by using set
membership tests instead of chained or comparisons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The behavior mode instrumentation test expected `Object _cf_result1`
but after the type inference fix, assertEquals(4, call()) now produces
`int _cf_result1 = (int)_cf_result1_1`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The assertion transformer always declared `Object _cf_resultN = call()` when
replacing assertions, losing the actual return type. This caused compilation
failures when the result was used in a context expecting a primitive type
(e.g., int, boolean).
Now infers the return type from assertion context:
- assertEquals(int_literal, call()) -> int
- assertTrue/assertFalse(call()) -> boolean
- assertEquals("string", call()) -> String
- Falls back to Object when type can't be determined
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The AI backend generates vitest/jest-style imports for Mocha projects.
Our sanitize_mocha_imports() stripped ESM `import { ... } from 'vitest'`,
but process_generated_test_strings() runs BEFORE postprocessing and calls
ensure_module_system_compatibility() which converts these to CJS requires.
Result: `const { ... } = require('vitest')` survived sanitization.
Added regexes for the CJS variants of vitest and @jest/globals requires.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: Vitest performance tests reported "20.0 seconds over 1 loop"
(JUnit XML wall-clock fallback) instead of actual per-function nanosecond
timing. This was a chain of two issues:
1. **stdout interception**: Vitest's default `threads` pool intercepts
process.stdout.write() and console.log(), preventing timing markers
from flowing to the parent process. Fixed by adding `--pool=forks`
to all Vitest commands and config files. The `forks` pool uses child
processes where stdout flows directly to the parent.
2. **test name detection**: Even after markers flowed through (43,000+
found in stdout), the parser couldn't match them to JUnit XML
testcases because all markers had "unknown" as the test name. This
happened because Vitest doesn't inject `beforeEach` as a global
(unlike Jest), so capture.js's Jest-style hook to set
`currentTestName` never fired.
Fixed by adding Vitest-specific test name detection in capture.js:
- Primary: `expect.getState().currentTestName` (full describe path)
- Fallback: `__vitest_worker__.current.fullTestName`
- Defense-in-depth: parser fallback matches "unknown" markers to
the first testcase when no name match is found
Result: cheerio's `isHtml` went from "20.0s / 1 loop" to
"902μs / 20,853 loops" with proper speedup analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three related fixes for Mocha test generation in CommonJS projects:
1. inject_test_globals() now accepts module_system param — emits
`require('node:assert/strict')` for CJS instead of ESM import syntax
2. ensure_module_system_compatibility() now converts ESM→CJS even when
the source has mixed imports (was skipping when both ESM and CJS were
detected, leaving the ESM import from inject_test_globals unconverted)
3. New sanitize_mocha_imports() strips vitest/jest/@jest/globals imports
that the AI sometimes generates for Mocha projects — Mocha provides
describe/it/before*/after* as globals
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When testsRoot overlaps moduleRoot (common in JS/TS monorepos like Ghost
where both point to "src"), the directory-based filter incorrectly
excluded ALL source files. Switch to filename/directory pattern matching
(*.test.*, *.spec.*, __tests__/) when roots overlap, preserving the
existing directory-based filter for standard layouts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace try/except/pass with contextlib.suppress() (ruff SIM105)
- Fix test_run_maven_tests_succeeds_with_valid_filter to mock
_run_cmd_kill_pg_on_timeout instead of subprocess.run; on Linux
the function uses Popen not run, so the old mock was never called
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add sys.platform == "win32" check in _run_cmd_kill_pg_on_timeout so
Windows machines fall back to plain subprocess.run() (Windows has no
POSIX process groups / killpg)
- Remove TestRunCmdKillPgOnTimeout test class (5 tests using sleep 60
commands were adding significant time to the test suite)
Follow-up to the SQLite-locked-error fix merged in #1728.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When running with --all on a Java project, codeflash was discovering .js
files inside apidocs/ and javadoc/ directories (generated Javadoc HTML)
and attempting to optimize them as JavaScript. This caused:
- "Invalid test framework for JavaScript/TypeScript" errors
- Wasted API calls for ~30+ functions from jquery-3.7.1.min.js
- Spurious "NO TESTS GENERATED" warnings for minified jQuery functions
Fix: add "apidocs" and "javadoc" to Java's dir_excludes. Because the
--all mode unions dir_excludes from all languages, these directories are
now skipped in both Java-specific and --all discovery modes.
Adds 5 tests verifying the exclusion works for Java mode and --all mode.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The root cause of 'database is locked' is orphaned Surefire JVM processes
after Maven timeout. The actual fix is killing the entire process group
(_run_cmd_kill_pg_on_timeout in test_runner.py).
The WAL mode / busy_timeout / sqlite3.connect(timeout=30) changes were
treating the symptom rather than the root cause. Revert them:
- codeflash/languages/java/instrumentation.py: remove PRAGMA journal_mode=WAL
and PRAGMA busy_timeout=30000 from inline SQLite write code
- codeflash/verification/parse_test_output.py: revert timeout=30 to default
- codeflash/languages/java/resources/CodeflashHelper.java: revert WAL/busy_timeout PRAGMAs
- codeflash-java-runtime/src/main/java/com/codeflash/Comparator.java: revert busy_timeout PRAGMA
- codeflash-java-runtime/src/main/java/com/codeflash/ResultWriter.java: revert WAL/busy_timeout PRAGMAs
- codeflash/languages/java/resources/codeflash-runtime-1.0.0.jar: restored to pre-change JAR
- tests/test_languages/test_java/test_instrumentation.py: remove TestSQLiteLockedFix
class and revert snapshot strings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause of 'database is locked' errors:
- When Maven times out, subprocess.run() only kills the Maven parent process
- On Linux, Maven's forked Surefire JVM children become orphaned (not killed)
- Orphaned JVMs keep the SQLite result file open, causing SQLITE_BUSY when
Python reads the file immediately after Maven is killed
Fix: Replace subprocess.run() with _run_cmd_kill_pg_on_timeout() which uses
start_new_session=True + os.killpg() to kill the entire process group on
timeout, ensuring no orphaned JVMs are left behind.
Applied to: _compile_tests, _get_test_classpath, _run_tests_direct,
and _run_maven_tests (the main one).
Also adds 5 unit tests verifying:
- Successful commands return correct output
- Failing commands propagate returncode
- Child processes are killed (not orphaned) on timeout
- returncode is -2 on timeout
- Timeout is described in stderr
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: The instrumented test JVM holds a SQLite connection open while
writing results. The Python reader and the Java Comparator were trying to
read the same file without a busy_timeout, causing immediate SQLITE_BUSY
failures (~126 occurrences in codeflash_all_3.log).
Fixes applied:
1. instrumentation.py (_generate_sqlite_write_code):
Emit PRAGMA journal_mode=WAL and PRAGMA busy_timeout=30000 right after
each inline connection open. WAL mode lets readers see the last committed
state while a writer is active; busy_timeout makes lock collisions retry
instead of immediately failing.
2. parse_test_output.py (parse_sqlite_test_results):
Add timeout=30 to sqlite3.connect() so Python waits up to 30 s for a
transient lock to clear (default was 5 s, which was too short for a busy
Maven/JVM process).
3. Comparator.java (readTestResults):
Execute PRAGMA busy_timeout=30000 on the same connection before running
the SELECT, so the Java Comparator also retries instead of failing with
[SQLITE_BUSY].
4. CodeflashHelper.java (initializeDatabase) and ResultWriter.java (constructor):
Same WAL + busy_timeout PRAGMAs added after the initial getConnection() call
for the long-lived database connections used by these helper classes.
5. Updated codeflash-runtime-1.0.0.jar (rebuilt after Comparator/ResultWriter fix).
tests: add TestSQLiteLockedFix with two assertions —
• _generate_sqlite_write_code emits PRAGMA journal_mode=WAL and
PRAGMA busy_timeout=30000 before CREATE TABLE
• parse_sqlite_test_results uses timeout= in sqlite3.connect()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix MockTestConfig missing tests_project_rootdir field
- Fix Python line profiler existence check on wrong path (no .lprof suffix)
- Add --release 11 to javac in Java line profiler tests for JDK compat
- Resolve merge conflicts with omni-java (replacement, tests)
- Add replace_function_definitions method to JavaSupport
- Guard against wrong method names in optimized code (standalone + class)
- Add tests for anonymous inner class method hoisting
- parser.py: add `is_class_nested` flag to `JavaMethodNode`; track
`class_depth` in `_walk_tree_for_methods` (incremented each time a
type declaration is entered) and set `is_class_nested = True` when
depth ≥ 2 (method lives inside a nested/inner class)
- discovery.py: add early-exit in `_should_include_method` when
`method.is_class_nested` is True — inner-class methods cannot be
reliably instrumented or tested in isolation, so we skip them up-front
rather than wasting LLM tokens on candidates that will always be
rejected later
- replacement.py: revert Bug-4 replacement-level workarounds that are
now obsolete:
* remove `target_class_name` parameter from `_parse_optimization_source`
* restore simple first-match `break` in target-method selection
* remove class_name filter that blocked helpers from "other" classes
- tests: update `TestNestedClasses`, `TestExtractCodeContextWithInnerClasses`
to reflect the new no-inner-class-discovery contract; remove
`TestInnerClassHelperFilter` (superseded by discovery filter);
add `TestInnerClassMethodFilter` in test_discovery.py with four
scenarios covering static nested, non-static inner, outer-only, and
deeply-nested classes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the LLM optimises a method by introducing a new final field (e.g.
caching Arrays.hashCode in Expression.hashCode, or caching map.values() in
LuaMap.valuesIterator), it also modifies the class constructors to initialise
the field. Previously codeflash:
1. Added the new field to the class ✓
2. Replaced the target method ✓
3. Did NOT update the constructors ✗
This caused "variable X might not have been initialized" compilation errors.
Changes:
- `JavaAnalyzer.find_constructors` (+ `_walk_tree_for_constructors`,
`_extract_constructor_info`): new parser methods to locate
`constructor_declaration` nodes via tree-sitter.
- `JavaMethodNode.formal_parameters_text`: captures the raw parameter list
text so constructors can be matched by signature.
- `ParsedOptimization.modified_constructors`: new field to carry constructor
source texts that need to be replaced.
- `_parse_optimization_source`: extract constructors from the same class as
the target method and store in `modified_constructors`.
- `_replace_constructors`: new helper that replaces constructors in the
original source by matching on formal parameter signature.
- `replace_function`: call `_replace_constructors` after the main method
replacement when `modified_constructors` is non-empty.
Fixes regressions observed in codeflash_all_3.log:
LuaMap.valuesIterator, Expression.hashCode, Bin.hashCode,
NettyTlsContext.createHandler, Pool.capacity.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the optimisation target lives in a static inner class (e.g.
ObjectUnpacker inside Unpacker<T>), the LLM-generated class often wraps the
inner class inside the full outer class. Previously, methods belonging to the
outer class were extracted as "helpers" and injected into the inner class,
causing compilation errors:
- "non-static type variable T cannot be referenced from a static context"
- "non-static variable offset cannot be referenced from a static context"
Two related fixes:
1. When _parse_optimization_source extracts helpers, it now skips any method
whose class_name differs from the target method's class_name.
2. The function now accepts an optional target_class_name parameter. When
there are multiple methods with the same name in the generated code (e.g.
an abstract outer-class method and the concrete inner-class override), the
method in the target class is preferred over outer-class methods.
Fixes the Unpacker.ObjectUnpacker.getString regression from codeflash_all_3.log.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace substring-based assertions with a single exact string
comparison in test_anonymous_iterator_methods_not_hoisted_to_class,
matching the convention used elsewhere in the test file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix language detection in code_replacer to use lang_support.language
(was None when function_to_optimize absent, blocking Java class member insertion)
- Update discover_functions calls in test_integration.py to pass source param
- Remove inner_iterations kwarg from test_run_and_parse.py (handled internally)
- Use os.path.relpath for main.py path in e2e tests
- Remove pass_fail_only kwarg from JS/Java function optimizers
- Fix Java e2e test to use JavaFunctionOptimizer for code context
- Detect codeflash.toml in e2e test runner (not just pyproject.toml)
- Use os.path.relpath for main.py path (works for any cwd depth)
- Remove pass_fail_only kwarg from JS/Java compare_test_results fallback
(main removed this parameter from equivalence.compare_test_results)
- Fix min/max_outer_loops → pytest_min/max_loops in Java test_run_and_parse
- Update test_replacement.py for new replace_function_definitions_for_language API
- Update JavaSupport.discover_functions signature to match protocol
- Migrate _get_java_sources_root/_fix_java_test_paths to JavaFunctionOptimizer
- Fix test_java_tests_project_rootdir to use set_current_language
Updates canary test to check JavaFunctionOptimizer instead of base
function_optimizer (comparison logic moved to subclass). Renames
min/max_outer_loops back to pytest_min/max_loops to match main's API.
Updates inject_profiling_into_existing_test calls to include test_string
parameter. Takes main's test refactoring for multi-file code replacement
and codeflash capture.
Allow init_js_project(), should_modify_package_json_config(), and
collect_js_setup_info() to run without interactive prompts when
skip_confirm=True. Uses auto-detected defaults instead of prompting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NotImplementedError guard in all 3 test dispatchers (behavioral,
benchmarking, line-profile) for frameworks other than jest and vitest.
Previously, mocha and other frameworks silently fell through to Jest,
causing confusing failures. Now users get a clear error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve `module.exports = varName` where varName is an object literal
containing methods. For patterns like `const utils = { match() {} };
module.exports = utils;`, the individual methods are now recognized as
exported. This fixes function discovery for CJS libraries like Moleculer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Post-process find_functions() to mark functions as exported when they appear
in named export clauses like `export { joinBy }`. This fixes discovery for
TypeScript codebases (e.g., Strapi) that define const arrow functions and
export them via a separate export statement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ship a zero-dependency jest-reporter.js inside the codeflash runtime package
instead of requiring the external jest-junit npm package. This ensures the
reporter is always available when codeflash is installed, fixing Jest-based
projects (Strapi, Moleculer) that failed because jest-junit wasn't installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update discover_functions calls to new (source, file_path) signature
- Use language-specific FunctionOptimizer subclasses in tests
- Add explicit utf-8 encoding to read_text()/write_text() for Windows
- Fix pytest fixture in TestTsJestSkipsConversion (was __init__)
- Update nonexistent file tests for source-based discover_functions
- Remove unused imports
Log "Discovered N existing unit test files" after counting tests, and
"Instrumented N existing unit test files" after injecting profiling.
Python E2E harness matches "Discovered", JS harness matches "Instrumented".
- Add clarifying comment on shared replace_function_definitions_in_module import
- Remove misleading alias in test_unused_helper_revert.py, use PythonFunctionOptimizer directly
- Align base line_profiler_step return type to dict[str, Any]
- Fix latent bug: handle non-empty TestResults in line_profiler_step
Two bugs in _parse_optimization_source (replacement.py) caused Maven compilation
failures when codeflash optimised aerospike-client-java:
Bug 1 – standalone method with wrong name replaces target
When the LLM generated a standalone method whose name did not match the
optimisation target (e.g. generated `unpackMap` for target `unpackObjectMap`,
or generated `sizeTxn` for target `estimateKeySize`), the function fell back to
using the entire generated snippet as `target_method_source`. This silently
replaced the target with the wrong method, producing:
• a duplicate definition of the wrong method
• removal of the target method (breaking all callers)
Fix: after parsing standalone (class-free) code, verify that at least one
discovered method matches the target name. If no match is found, set
`target_method_source` to the empty string and log a warning. A corresponding
guard in `replace_function` returns the original source unchanged when
`target_method_source` is empty.
The same guard is applied to the full-class path: if the generated class does
not contain the target method, the candidate is also rejected.
Bug 2 – anonymous inner-class methods hoisted as top-level helpers
When an optimised method returned an anonymous class (e.g. `keySetIterator`
returning `new Iterator<LuaValue>() { … }`), tree-sitter's recursive walk
found the anonymous class's `hasNext`, `next`, and `remove` method_declaration
nodes and classified them as helpers to be inserted at the outer-class level.
The inserted methods carried `@Override` annotations that matched nothing in the
outer class and referenced local variables (`it`) that were only in scope inside
the optimised method body, producing compilation errors.
Fix: when extracting helpers from the optimised class, skip any method whose
line range is entirely contained within the target method's line range. Such
methods belong to anonymous/nested classes inside the method body and must not
be hoisted out as standalone class members.
Tests added for both bugs in TestWrongMethodNameGeneration and
TestAnonymousInnerClassMethods.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Base class keeps the language-routing replacement logic (used by both
Python and JS); Python subclass adds unused-helper revert on top via super()
- Tests that exercise Python-specific replace+revert use PythonFunctionOptimizer
- Move `ast` to TYPE_CHECKING in optimizer.py (fixes prek)
Handle itertools.cycle on Python 3.14 where __reduce__ was removed by
falling back to element-by-element sampling. Add version guards for
pairwise (3.10+) and batched (3.12+) tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a catch-all handler for itertools iterators (chain, islice, product,
permutations, combinations, starmap, accumulate, compress, dropwhile,
takewhile, filterfalse, zip_longest, groupby, pairwise, batched, tee).
Uses module check (type.__module__ == "itertools") so it automatically
covers any itertools type without version-specific enumeration. groupby
gets special handling to also materialize its group iterators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
itertools.repeat uses repr() comparison (same approach as count).
itertools.cycle uses __reduce__() to extract internal state (saved items,
remaining items, and first-pass flag) since repr() only shows a memory
address. The __reduce__ approach is deprecated in 3.14 but is the only
way to access cycle state without consuming elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The comparator had no handler for itertools.count (an infinite iterator),
causing it to fall through all type checks and return False even for
equal objects. Use repr() comparison which reliably reflects internal
state and avoids the __reduce__ deprecation coming in Python 3.14.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nested functions are now skipped by FunctionVisitor, and
discover_functions no longer swallows parse/IO errors — callers
handle them. Update test expectations accordingly.
Extend extract_parameter_type_constructors to scan function bodies for
isinstance/type() patterns and collect base class names from enclosing
classes. Add one-level transitive stub extraction so the LLM also sees
constructor signatures for types referenced in __init__ parameters.
In enrich_testgen_context, branch on source: project classes get full
definitions, third-party (site-packages) classes get compact __init__
stubs to avoid blowing token limits.
Replace substring assertions with exact equality check against the full
expected output (EXPECTED_OUTPUT constant). Extract shared setup into a
run_replacement helper.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
detect_unused_helper_functions only walked ast.Call nodes, missing methods
referenced via attribute assignment (e.g., self._parse1 = self._parse_literal).
This caused optimized helper methods used as callbacks to be incorrectly
reverted to their original code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Objects with __slots__ but no __dict__ (e.g. textual.cache.LRUCache)
fell through all comparator branches, logging "Unknown comparator input
type" and returning False — causing spurious test mismatches.
Changed iteration_id in performance mode markers to properly encode
inner loop iterations for test case grouping:
- Single call: iteration_id = innerIteration (0, 1, 2...)
- Multiple calls: iteration_id = callId_innerIteration (1_0, 1_1, 2_0, 2_1...)
This allows test results to be properly grouped by InvocationId, where
each unique (call, inner_iteration) pair gets its own group for
calculating minimum runtimes across outer loops.
Fixed test expectations to match the new format.
All 43 Java performance tests passing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
parse_code_and_prune_cst now returns cst.Module instead of str.
add_needed_imports_from_module accepts cst.Module | str, skipping re-parse
when a Module is passed. This eliminates the string round-trip that caused
comments to migrate from statement leading_lines to Module.header,
resulting in comments appearing above imports instead of at their
original position.
Implemented CUDA-style loop ID calculation for performance mode:
- loopId = outerLoop * maxInnerIterations + innerIteration
- Behavior mode uses simple loop index (no inner iterations)
- Invocation ID simplified to call counter only
- Default CODEFLASH_INNER_ITERATIONS set to 10
Fixed critical bug in JavaAssertTransformer:
- Removed duplicate _special_re assignment that was missing parentheses
- Combined patterns into single regex: [\"'{}()]
- This fixes _find_balanced_parens and enables assertion transformation
Updated test expectations to match new marker format and loop ID calculation.
All 41 Java instrumentation tests passing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Cache inspect.getmembers() results per module so repeated loop
iterations skip the expensive rescan. Add tests for get_runtime_from_stdout,
should_stop, _set_nodeid, _get_total_time, _timed_out, logreport, and
setup/teardown hooks.
feat: extend testgen type context to include function body references
Extract types referenced in the function body (constructor calls, attribute
access, isinstance/issubclass args) in addition to parameter annotations.
Use full class extraction instead of init-stub-only, with instance resolution
fallback and project/site-packages filtering.
Java stdout markers now include the test method name in the class field
(e.g., "TestClass.testMethod") matching the Python marker format. The
parser extracts the test method name from this combined field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The instrumented Java test code was storing "{class_name}Test" as the
test_function_name in SQLite instead of the actual test method name
(e.g., "testAdd"). This fixes parity with Python instrumentation.
- Add _extract_test_method_name() with compiled regex patterns
- Inject _cf_test variable with actual method name in behavior code
- Fix setString(3, ...) to use _cf_test instead of hardcoded class name
- Optimize _byte_to_line_index() with bisect.bisect_right()
- Update all behavior mode test expectations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The comparator did not recognize `types.UnionType` (Python 3.10+ `X | Y`
syntax), causing it to fall through to "Unknown comparator input type".
Conditionally include it in the equality-checked types tuple.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase tolerance for individual timing measurements from ±2% to ±5%
to accommodate JIT warmup effects where first iterations run slower
than subsequent optimized runs. Maintain ±2% tolerance for
total_passed_runtime since it uses minimums that filter out cold starts.
- CV threshold: 0.02 → 0.05 (5%)
- Mean runtime: ±2% → ±5%
- total_passed_runtime: ±2% (unchanged, using filtered minimums)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Rename test class to TestLineProfilerInstrumentation for clarity.
- Add tests for instrumenting Java classes with and without package declarations.
- Enhance instrumentation tests to verify that source files remain unmodified.
- Implement checks for generated configuration files, ensuring correct content and structure.
- Introduce tests for deeply nested packages and verify line contents extraction.
- Add end-to-end tests for spin-timer profiling, validating timing accuracy and hit counts.
The `list[X] | None` union syntax (PEP 604) requires Python 3.10+ at
runtime. Adding the future annotations import defers evaluation and
fixes the import error on Python 3.9.
Co-authored-by: Saurabh Misra <misrasaurabh1@users.noreply.github.com>