diff --git a/codeflash/languages/java/config.py b/codeflash/languages/java/config.py index 408dcecaf..788c93c50 100644 --- a/codeflash/languages/java/config.py +++ b/codeflash/languages/java/config.py @@ -152,16 +152,20 @@ def _detect_test_framework(project_root: Path, build_tool: BuildTool) -> tuple[s except Exception: pass - # Determine primary framework (prefer JUnit 5) + # Determine primary framework (prefer JUnit 5 if explicitly found) if has_junit5: + logger.debug("Selected JUnit 5 as test framework") return "junit5", has_junit5, has_junit4, has_testng if has_junit4: + logger.debug("Selected JUnit 4 as test framework") return "junit4", has_junit5, has_junit4, has_testng if has_testng: + logger.debug("Selected TestNG as test framework") return "testng", has_junit5, has_junit4, has_testng - # Default to JUnit 5 if nothing detected - return "junit5", has_junit5, has_junit4, has_testng + # Default to JUnit 4 if nothing detected (more common in legacy projects) + logger.debug("No test framework detected, defaulting to JUnit 4") + return "junit4", has_junit5, has_junit4, has_testng def _detect_test_deps_from_pom(project_root: Path) -> tuple[bool, bool, bool]: @@ -179,6 +183,36 @@ def _detect_test_deps_from_pom(project_root: Path) -> tuple[bool, bool, bool]: has_junit4 = False has_testng = False + def check_dependencies(deps_element: ET.Element | None, ns: dict[str, str]) -> None: + """Check dependencies element for test frameworks.""" + nonlocal has_junit5, has_junit4, has_testng + + if deps_element is None: + return + + for dep_path in ["dependency", "m:dependency"]: + deps_list = deps_element.findall(dep_path, ns) if "m:" in dep_path else deps_element.findall(dep_path) + for dep in deps_list: + artifact_id = None + group_id = None + + for child in dep: + tag = child.tag.replace("{http://maven.apache.org/POM/4.0.0}", "") + if tag == "artifactId": + artifact_id = child.text + elif tag == "groupId": + group_id = child.text + + if group_id == "org.junit.jupiter" or (artifact_id and "junit-jupiter" in artifact_id): + has_junit5 = True + logger.debug("Found JUnit 5 dependency: %s:%s", group_id, artifact_id) + elif group_id == "junit" and artifact_id == "junit": + has_junit4 = True + logger.debug("Found JUnit 4 dependency: %s:%s", group_id, artifact_id) + elif group_id == "org.testng": + has_testng = True + logger.debug("Found TestNG dependency: %s:%s", group_id, artifact_id) + try: tree = ET.parse(pom_path) root = tree.getroot() @@ -186,35 +220,44 @@ def _detect_test_deps_from_pom(project_root: Path) -> tuple[bool, bool, bool]: # Handle namespace ns = {"m": "http://maven.apache.org/POM/4.0.0"} - # Search for dependencies + logger.debug("Checking pom.xml at %s", pom_path) + + # Search for direct dependencies for deps_path in ["dependencies", "m:dependencies"]: deps = root.find(deps_path, ns) if "m:" in deps_path else root.find(deps_path) - if deps is None: - continue - - for dep_path in ["dependency", "m:dependency"]: - deps_list = deps.findall(dep_path, ns) if "m:" in dep_path else deps.findall(dep_path) - for dep in deps_list: - artifact_id = None - group_id = None - - for child in dep: - tag = child.tag.replace("{http://maven.apache.org/POM/4.0.0}", "") - if tag == "artifactId": - artifact_id = child.text - elif tag == "groupId": - group_id = child.text - - if group_id == "org.junit.jupiter" or (artifact_id and "junit-jupiter" in artifact_id): - has_junit5 = True - elif group_id == "junit" and artifact_id == "junit": - has_junit4 = True - elif group_id == "org.testng": - has_testng = True + if deps is not None: + logger.debug("Found dependencies section in %s", pom_path) + check_dependencies(deps, ns) + + # Also check dependencyManagement section (for multi-module projects) + for dep_mgmt_path in ["dependencyManagement", "m:dependencyManagement"]: + dep_mgmt = root.find(dep_mgmt_path, ns) if "m:" in dep_mgmt_path else root.find(dep_mgmt_path) + if dep_mgmt is not None: + logger.debug("Found dependencyManagement section in %s", pom_path) + for deps_path in ["dependencies", "m:dependencies"]: + deps = dep_mgmt.find(deps_path, ns) if "m:" in deps_path else dep_mgmt.find(deps_path) + if deps is not None: + check_dependencies(deps, ns) except ET.ParseError: - pass - + logger.debug("Failed to parse pom.xml at %s", pom_path) + + # For multi-module projects, also check submodule pom.xml files + if not (has_junit5 or has_junit4 or has_testng): + logger.debug("No test deps in root pom, checking submodules") + # Check common submodule locations + for submodule_name in ["test", "tests", "src/test", "testing"]: + submodule_pom = project_root / submodule_name / "pom.xml" + if submodule_pom.exists(): + logger.debug("Checking submodule pom at %s", submodule_pom) + sub_junit5, sub_junit4, sub_testng = _detect_test_deps_from_pom(project_root / submodule_name) + has_junit5 = has_junit5 or sub_junit5 + has_junit4 = has_junit4 or sub_junit4 + has_testng = has_testng or sub_testng + if has_junit5 or has_junit4 or has_testng: + break + + logger.debug("Test framework detection result: junit5=%s, junit4=%s, testng=%s", has_junit5, has_junit4, has_testng) return has_junit5, has_junit4, has_testng diff --git a/codeflash/languages/java/instrumentation.py b/codeflash/languages/java/instrumentation.py index 6f2725b9b..1cacbef5b 100644 --- a/codeflash/languages/java/instrumentation.py +++ b/codeflash/languages/java/instrumentation.py @@ -6,8 +6,8 @@ Timing instrumentation adds System.nanoTime() calls around the function being tested and prints timing markers in a format compatible with Python/JS implementations: - Start: !$######testModule:testClass:funcName:loopIndex:iterationId######$! - End: !######testModule:testClass:funcName:loopIndex:iterationId:durationNs######! + Start: !$######testModule:testClass.testMethod:funcName:loopIndex:iterationId######$! + End: !######testModule:testClass.testMethod:funcName:loopIndex:iterationId:durationNs######! This allows codeflash to extract timing data from stdout for accurate benchmarking. """ @@ -35,13 +35,31 @@ def _get_function_name(func: Any) -> str: """Get the function name from FunctionToOptimize.""" if hasattr(func, "function_name"): - return func.function_name + return str(func.function_name) if hasattr(func, "name"): - return func.name + return str(func.name) msg = f"Cannot get function name from {type(func)}" raise AttributeError(msg) +_METHOD_SIG_PATTERN = re.compile( + r"\b(?:public|private|protected)?\s*(?:static)?\s*(?:final)?\s*" + r"(?:void|String|int|long|boolean|double|float|char|byte|short|\w+(?:\[\])?)\s+(\w+)\s*\(" +) +_FALLBACK_METHOD_PATTERN = re.compile(r"\b(\w+)\s*\(") + + +def _extract_test_method_name(method_lines: list[str]) -> str: + method_sig = " ".join(method_lines).strip() + match = _METHOD_SIG_PATTERN.search(method_sig) + if match: + return match.group(1) + fallback_match = _FALLBACK_METHOD_PATTERN.search(method_sig) + if fallback_match: + return fallback_match.group(1) + return "unknown" + + # Pattern to detect primitive array types in assertions _PRIMITIVE_ARRAY_PATTERN = re.compile(r"new\s+(int|long|double|float|short|byte|char|boolean)\s*\[\s*\]") @@ -61,17 +79,65 @@ def _is_test_annotation(stripped_line: str) -> bool: @TestFactory @TestTemplate """ - return bool(_TEST_ANNOTATION_RE.match(stripped_line)) + if not stripped_line.startswith("@Test"): + return False + if len(stripped_line) == 5: + return True + next_char = stripped_line[5] + return next_char in {" ", "("} -def _is_inside_lambda(node) -> bool: +def _is_inside_lambda(node: Any) -> bool: """Check if a tree-sitter node is inside a lambda_expression.""" current = node.parent while current is not None: - if current.type == "lambda_expression": + t = current.type + if t == "lambda_expression": return True - if current.type == "method_declaration": + if t == "method_declaration": + return False + current = current.parent + return False + + +def _is_inside_complex_expression(node: Any) -> bool: + """Check if a tree-sitter node is inside a complex expression that shouldn't be instrumented directly. + + This includes: + - Cast expressions: (Long)list.get(2) + - Ternary expressions: condition ? func() : other + - Array access: arr[func()] + - Binary operations: func() + 1 + + Returns True if the node should not be directly instrumented. + """ + current = node.parent + while current is not None: + # Stop at statement boundaries + if current.type in { + "method_declaration", + "block", + "if_statement", + "for_statement", + "while_statement", + "try_statement", + "expression_statement", + }: return False + + # These are complex expressions that shouldn't have instrumentation inserted in the middle + if current.type in { + "cast_expression", + "ternary_expression", + "array_access", + "binary_expression", + "unary_expression", + "parenthesized_expression", + "instanceof_expression", + }: + logger.debug("Found complex expression parent: %s", current.type) + return True + current = current.parent return False @@ -94,8 +160,11 @@ def wrap_target_calls_with_treesitter( """ from codeflash.languages.java.parser import get_java_analyzer - analyzer = get_java_analyzer() body_text = "\n".join(body_lines) + if func_name not in body_text: + return list(body_lines), 0 + + analyzer = get_java_analyzer() body_bytes = body_text.encode("utf8") prefix_len = len(_TS_BODY_PREFIX_BYTES) @@ -103,7 +172,7 @@ def wrap_target_calls_with_treesitter( tree = analyzer.parse(wrapper_bytes) # Collect all matching calls with their metadata - calls = [] + calls: list[dict[str, Any]] = [] _collect_calls(tree.root_node, wrapper_bytes, body_bytes, prefix_len, func_name, analyzer, calls) if not calls: @@ -116,10 +185,11 @@ def wrap_target_calls_with_treesitter( line_byte_starts.append(offset) offset += len(line.encode("utf8")) + 1 # +1 for \n from join - # Group non-lambda calls by their line index - calls_by_line: dict[int, list] = {} + # Group non-lambda and non-complex-expression calls by their line index + calls_by_line: dict[int, list[dict[str, Any]]] = {} for call in calls: - if call["in_lambda"]: + if call["in_lambda"] or call.get("in_complex", False): + logger.debug("Skipping behavior instrumentation for call in lambda or complex expression") continue line_idx = _byte_to_line_index(call["start_byte"], line_byte_starts) calls_by_line.setdefault(line_idx, []).append(call) @@ -202,7 +272,15 @@ def wrap_target_calls_with_treesitter( return wrapped, call_counter -def _collect_calls(node, wrapper_bytes, body_bytes, prefix_len, func_name, analyzer, out): +def _collect_calls( + node: Any, + wrapper_bytes: bytes, + body_bytes: bytes, + prefix_len: int, + func_name: str, + analyzer: JavaAnalyzer, + out: list[dict[str, Any]], +) -> None: """Recursively collect method_invocation nodes matching func_name.""" node_type = node.type if node_type == "method_invocation": @@ -225,6 +303,7 @@ def _collect_calls(node, wrapper_bytes, body_bytes, prefix_len, func_name, analy "full_call": analyzer.get_node_text(node, wrapper_bytes), "parent_type": parent_type, "in_lambda": _is_inside_lambda(node), + "in_complex": _is_inside_complex_expression(node), "es_start_byte": es_start, "es_end_byte": es_end, } @@ -236,7 +315,7 @@ def _collect_calls(node, wrapper_bytes, body_bytes, prefix_len, func_name, analy def _byte_to_line_index(byte_offset: int, line_byte_starts: list[int]) -> int: """Map a byte offset in body_text to a body_lines index.""" idx = bisect.bisect_right(line_byte_starts, byte_offset) - 1 - return max(0, idx) + return max(idx, 0) def _infer_array_cast_type(line: str) -> str | None: @@ -269,7 +348,7 @@ def _infer_array_cast_type(line: str) -> str | None: def _get_qualified_name(func: Any) -> str: """Get the qualified name from FunctionToOptimize.""" if hasattr(func, "qualified_name"): - return func.qualified_name + return str(func.qualified_name) # Build qualified name from function_name and parents if hasattr(func, "function_name"): parts = [] @@ -497,6 +576,9 @@ def _add_behavior_instrumentation(source: str, class_name: str, func_name: str) result.append(ml) i += 1 + # Extract the test method name from the method signature + test_method_name = _extract_test_method_name(method_lines) + # We're now inside the method body iteration_counter += 1 iter_id = iteration_counter @@ -542,7 +624,8 @@ def _add_behavior_instrumentation(source: str, class_name: str, func_name: str) f'{indent}String _cf_outputFile{iter_id} = System.getenv("CODEFLASH_OUTPUT_FILE");', f'{indent}String _cf_testIteration{iter_id} = System.getenv("CODEFLASH_TEST_ITERATION");', f'{indent}if (_cf_testIteration{iter_id} == null) _cf_testIteration{iter_id} = "0";', - f'{indent}System.out.println("!$######" + _cf_mod{iter_id} + ":" + _cf_cls{iter_id} + ":" + _cf_fn{iter_id} + ":" + _cf_loop{iter_id} + ":" + _cf_iter{iter_id} + "######$!");', + f'{indent}String _cf_test{iter_id} = "{test_method_name}";', + f'{indent}System.out.println("!$######" + _cf_mod{iter_id} + ":" + _cf_cls{iter_id} + "." + _cf_test{iter_id} + ":" + _cf_fn{iter_id} + ":" + _cf_loop{iter_id} + ":" + _cf_iter{iter_id} + "######$!");', f"{indent}byte[] _cf_serializedResult{iter_id} = null;", f"{indent}long _cf_end{iter_id} = -1;", f"{indent}long _cf_start{iter_id} = 0;", @@ -563,7 +646,7 @@ def _add_behavior_instrumentation(source: str, class_name: str, func_name: str) f"{indent}}} finally {{", f"{indent} long _cf_end{iter_id}_finally = System.nanoTime();", f"{indent} long _cf_dur{iter_id} = (_cf_end{iter_id} != -1 ? _cf_end{iter_id} : _cf_end{iter_id}_finally) - _cf_start{iter_id};", - f'{indent} System.out.println("!######" + _cf_mod{iter_id} + ":" + _cf_cls{iter_id} + ":" + _cf_fn{iter_id} + ":" + _cf_loop{iter_id} + ":" + _cf_iter{iter_id} + ":" + _cf_dur{iter_id} + "######!");', + f'{indent} System.out.println("!######" + _cf_mod{iter_id} + ":" + _cf_cls{iter_id} + "." + _cf_test{iter_id} + ":" + _cf_fn{iter_id} + ":" + _cf_loop{iter_id} + ":" + _cf_iter{iter_id} + ":" + _cf_dur{iter_id} + "######!");', f"{indent} // Write to SQLite if output file is set", f"{indent} if (_cf_outputFile{iter_id} != null && !_cf_outputFile{iter_id}.isEmpty()) {{", f"{indent} try {{", @@ -579,7 +662,7 @@ def _add_behavior_instrumentation(source: str, class_name: str, func_name: str) f"{indent} try (PreparedStatement _cf_pstmt{iter_id} = _cf_conn{iter_id}.prepareStatement(_cf_sql{iter_id})) {{", f"{indent} _cf_pstmt{iter_id}.setString(1, _cf_mod{iter_id});", f"{indent} _cf_pstmt{iter_id}.setString(2, _cf_cls{iter_id});", - f'{indent} _cf_pstmt{iter_id}.setString(3, "{class_name}Test");', + f"{indent} _cf_pstmt{iter_id}.setString(3, _cf_test{iter_id});", f"{indent} _cf_pstmt{iter_id}.setString(4, _cf_fn{iter_id});", f"{indent} _cf_pstmt{iter_id}.setInt(5, _cf_loop{iter_id});", f'{indent} _cf_pstmt{iter_id}.setString(6, _cf_iter{iter_id} + "_" + _cf_testIteration{iter_id});', @@ -636,7 +719,7 @@ def _add_timing_instrumentation(source: str, class_name: str, func_name: str) -> analyzer = get_java_analyzer() tree = analyzer.parse(source_bytes) - def has_test_annotation(method_node) -> bool: + def has_test_annotation(method_node: Any) -> bool: modifiers = None for child in method_node.children: if child.type == "modifiers": @@ -655,21 +738,31 @@ def has_test_annotation(method_node) -> bool: return True return False - def collect_test_methods(node, out) -> None: - if node.type == "method_declaration" and has_test_annotation(node): - body_node = node.child_by_field_name("body") - if body_node is not None: - out.append((node, body_node)) - for child in node.children: - collect_test_methods(child, out) - - def collect_target_calls(node, wrapper_bytes: bytes, func: str, out) -> None: - if node.type == "method_invocation": - name_node = node.child_by_field_name("name") - if name_node and analyzer.get_node_text(name_node, wrapper_bytes) == func and not _is_inside_lambda(node): - out.append(node) - for child in node.children: - collect_target_calls(child, wrapper_bytes, func, out) + def collect_test_methods(node: Any, out: list[tuple[Any, Any]]) -> None: + stack = [node] + while stack: + current = stack.pop() + if current.type == "method_declaration" and has_test_annotation(current): + body_node = current.child_by_field_name("body") + if body_node is not None: + out.append((current, body_node)) + continue + if current.children: + stack.extend(reversed(current.children)) + + def collect_target_calls(node: Any, wrapper_bytes: bytes, func: str, out: list[Any]) -> None: + stack = [node] + while stack: + current = stack.pop() + if current.type == "method_invocation": + name_node = current.child_by_field_name("name") + if name_node and analyzer.get_node_text(name_node, wrapper_bytes) == func: + if not _is_inside_lambda(current) and not _is_inside_complex_expression(current): + out.append(current) + else: + logger.debug("Skipping instrumentation of %s inside lambda or complex expression", func) + if current.children: + stack.extend(reversed(current.children)) def reindent_block(text: str, target_indent: str) -> str: lines = text.splitlines() @@ -686,13 +779,13 @@ def reindent_block(text: str, target_indent: str) -> str: reindented.append(f"{target_indent}{line[min_leading:]}") return "\n".join(reindented) - def find_top_level_statement(node, body_node): + def find_top_level_statement(node: Any, body_node: Any) -> Any: current = node while current is not None and current.parent is not None and current.parent != body_node: current = current.parent return current if current is not None and current.parent == body_node else None - def split_var_declaration(stmt_node, source_bytes_ref: bytes) -> tuple[str, str] | None: + def split_var_declaration(stmt_node: Any, source_bytes_ref: bytes) -> tuple[str, str] | None: """Split a local_variable_declaration into a hoisted declaration and an assignment. When a target call is inside a variable declaration like: @@ -747,7 +840,9 @@ def split_var_declaration(stmt_node, source_bytes_ref: bytes) -> tuple[str, str] assignment = f"{name_text} = {value_text};" return hoisted, assignment - def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: str) -> tuple[str, int]: + def build_instrumented_body( + body_text: str, next_wrapper_id: int, base_indent: str, test_method_name: str = "unknown" + ) -> tuple[str, int]: body_bytes = body_text.encode("utf8") wrapper_bytes = _TS_BODY_PREFIX_BYTES + body_bytes + _TS_BODY_SUFFIX.encode("utf8") wrapper_tree = analyzer.parse(wrapper_bytes) @@ -764,7 +859,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s wrapped_body = wrapped_method.child_by_field_name("body") if wrapped_body is None: return body_text, next_wrapper_id - calls = [] + calls: list[Any] = [] collect_target_calls(wrapped_body, wrapper_bytes, func_name, calls) indent = base_indent @@ -816,6 +911,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s f'{indent}int _cf_innerIterations{current_id} = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100"));', f'{indent}String _cf_mod{current_id} = "{class_name}";', f'{indent}String _cf_cls{current_id} = "{class_name}";', + f'{indent}String _cf_test{current_id} = "{test_method_name}";', f'{indent}String _cf_fn{current_id} = "{func_name}";', "", ] @@ -832,7 +928,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s stmt_in_try = reindent_block(target_stmt, inner_body_indent) timing_lines = [ f"{indent}for (int _cf_i{current_id} = 0; _cf_i{current_id} < _cf_innerIterations{current_id}; _cf_i{current_id}++) {{", - f'{inner_indent}System.out.println("!$######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + _cf_i{current_id} + "######$!");', + f'{inner_indent}System.out.println("!$######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + "." + _cf_test{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + _cf_i{current_id} + "######$!");', f"{inner_indent}long _cf_end{current_id} = -1;", f"{inner_indent}long _cf_start{current_id} = 0;", f"{inner_indent}try {{", @@ -842,7 +938,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s f"{inner_indent}}} finally {{", f"{inner_body_indent}long _cf_end{current_id}_finally = System.nanoTime();", f"{inner_body_indent}long _cf_dur{current_id} = (_cf_end{current_id} != -1 ? _cf_end{current_id} : _cf_end{current_id}_finally) - _cf_start{current_id};", - f'{inner_body_indent}System.out.println("!######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + _cf_i{current_id} + ":" + _cf_dur{current_id} + "######!");', + f'{inner_body_indent}System.out.println("!######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + "." + _cf_test{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + _cf_i{current_id} + ":" + _cf_dur{current_id} + "######!");', f"{inner_indent}}}", f"{indent}}}", ] @@ -863,14 +959,14 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s result_parts.append(suffix) return "".join(result_parts), current_id - result_parts: list[str] = [] + multi_result_parts: list[str] = [] cursor = 0 wrapper_id = next_wrapper_id for stmt_start, stmt_end, stmt_ast_node in unique_ranges: prefix = body_text[cursor:stmt_start] target_stmt = body_text[stmt_start:stmt_end] - result_parts.append(prefix.rstrip(" \t")) + multi_result_parts.append(prefix.rstrip(" \t")) wrapper_id += 1 current_id = wrapper_id @@ -881,6 +977,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s f'{indent}int _cf_innerIterations{current_id} = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100"));', f'{indent}String _cf_mod{current_id} = "{class_name}";', f'{indent}String _cf_cls{current_id} = "{class_name}";', + f'{indent}String _cf_test{current_id} = "{test_method_name}";', f'{indent}String _cf_fn{current_id} = "{func_name}";', "", ] @@ -897,7 +994,7 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s timing_lines = [ f"{indent}for (int _cf_i{current_id} = 0; _cf_i{current_id} < _cf_innerIterations{current_id}; _cf_i{current_id}++) {{", - f'{inner_indent}System.out.println("!$######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + {iteration_id_expr} + "######$!");', + f'{inner_indent}System.out.println("!$######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + "." + _cf_test{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + {iteration_id_expr} + "######$!");', f"{inner_indent}long _cf_end{current_id} = -1;", f"{inner_indent}long _cf_start{current_id} = 0;", f"{inner_indent}try {{", @@ -907,19 +1004,19 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s f"{inner_indent}}} finally {{", f"{inner_body_indent}long _cf_end{current_id}_finally = System.nanoTime();", f"{inner_body_indent}long _cf_dur{current_id} = (_cf_end{current_id} != -1 ? _cf_end{current_id} : _cf_end{current_id}_finally) - _cf_start{current_id};", - f'{inner_body_indent}System.out.println("!######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + {iteration_id_expr} + ":" + _cf_dur{current_id} + "######!");', + f'{inner_body_indent}System.out.println("!######" + _cf_mod{current_id} + ":" + _cf_cls{current_id} + "." + _cf_test{current_id} + ":" + _cf_fn{current_id} + ":" + _cf_loop{current_id} + ":" + {iteration_id_expr} + ":" + _cf_dur{current_id} + "######!");', f"{inner_indent}}}", f"{indent}}}", ] - result_parts.append("\n" + "\n".join(setup_lines)) - result_parts.append("\n".join(timing_lines)) + multi_result_parts.append("\n" + "\n".join(setup_lines)) + multi_result_parts.append("\n".join(timing_lines)) cursor = stmt_end - result_parts.append(body_text[cursor:]) - return "".join(result_parts), wrapper_id + multi_result_parts.append(body_text[cursor:]) + return "".join(multi_result_parts), wrapper_id - test_methods = [] + test_methods: list[tuple[Any, Any]] = [] collect_test_methods(tree.root_node, test_methods) if not test_methods: return source @@ -931,8 +1028,11 @@ def build_instrumented_body(body_text: str, next_wrapper_id: int, base_indent: s body_end = body_node.end_byte - 1 # skip '}' body_text = source_bytes[body_start:body_end].decode("utf8") base_indent = " " * (method_node.start_point[1] + 4) + # Extract test method name from AST + name_node = method_node.child_by_field_name("name") + test_method_name = analyzer.get_node_text(name_node, source_bytes) if name_node else "unknown" next_wrapper_id = max(wrapper_id, method_ordinal - 1) - new_body, new_wrapper_id = build_instrumented_body(body_text, next_wrapper_id, base_indent) + new_body, new_wrapper_id = build_instrumented_body(body_text, next_wrapper_id, base_indent, test_method_name) # Reserve one id slot per @Test method even when no instrumentation is added, # matching existing deterministic numbering expected by tests. wrapper_id = method_ordinal if new_wrapper_id == next_wrapper_id else new_wrapper_id @@ -1067,12 +1167,13 @@ def instrument_generated_java_test( function_name, ) elif mode == "behavior": - _, modified_code = instrument_existing_test( + _, behavior_code = instrument_existing_test( test_string=test_code, mode=mode, function_to_optimize=function_to_optimize, test_class_name=original_class_name, ) + modified_code = behavior_code or test_code else: modified_code = test_code diff --git a/codeflash/languages/java/support.py b/codeflash/languages/java/support.py index d3f8d0db3..f56a0dab5 100644 --- a/codeflash/languages/java/support.py +++ b/codeflash/languages/java/support.py @@ -40,7 +40,7 @@ from codeflash.discovery.functions_to_optimize import FunctionToOptimize from codeflash.languages.base import CodeContext, FunctionFilterCriteria, HelperFunction, TestInfo, TestResult from codeflash.languages.java.concurrency_analyzer import ConcurrencyInfo - from codeflash.models.models import GeneratedTestsList + from codeflash.models.models import GeneratedTestsList, InvocationId logger = logging.getLogger(__name__) @@ -199,6 +199,75 @@ def remove_test_functions(self, test_source: str, functions_to_remove: list[str] """Remove specific test functions from test source code.""" return remove_test_functions(test_source, functions_to_remove, self._analyzer) + def remove_test_functions_from_generated_tests( + self, generated_tests: GeneratedTestsList, functions_to_remove: list[str] + ) -> GeneratedTestsList: + from codeflash.models.models import GeneratedTests, GeneratedTestsList + + updated_tests: list[GeneratedTests] = [] + for test in generated_tests.generated_tests: + updated_tests.append( + GeneratedTests( + generated_original_test_source=self.remove_test_functions( + test.generated_original_test_source, functions_to_remove + ), + instrumented_behavior_test_source=test.instrumented_behavior_test_source, + instrumented_perf_test_source=test.instrumented_perf_test_source, + behavior_file_path=test.behavior_file_path, + perf_file_path=test.perf_file_path, + ) + ) + return GeneratedTestsList(generated_tests=updated_tests) + + def add_runtime_comments_to_generated_tests( + self, + generated_tests: GeneratedTestsList, + original_runtimes: dict[InvocationId, list[int]], + optimized_runtimes: dict[InvocationId, list[int]], + tests_project_rootdir: Path | None = None, + ) -> GeneratedTestsList: + from codeflash.models.models import GeneratedTests, GeneratedTestsList + + original_runtimes_dict = self._build_runtime_map(original_runtimes) + optimized_runtimes_dict = self._build_runtime_map(optimized_runtimes) + + modified_tests: list[GeneratedTests] = [] + for test in generated_tests.generated_tests: + modified_source = self.add_runtime_comments( + test.generated_original_test_source, original_runtimes_dict, optimized_runtimes_dict + ) + modified_tests.append( + GeneratedTests( + generated_original_test_source=modified_source, + instrumented_behavior_test_source=test.instrumented_behavior_test_source, + instrumented_perf_test_source=test.instrumented_perf_test_source, + behavior_file_path=test.behavior_file_path, + perf_file_path=test.perf_file_path, + ) + ) + return GeneratedTestsList(generated_tests=modified_tests) + + def _build_runtime_map(self, inv_id_runtimes: dict[InvocationId, list[int]]) -> dict[str, int]: + unique_inv_ids: dict[str, int] = {} + for inv_id, runtimes in inv_id_runtimes.items(): + test_qualified_name = ( + inv_id.test_class_name + "." + inv_id.test_function_name + if inv_id.test_class_name + else inv_id.test_function_name + ) + if not test_qualified_name: + continue + + key = test_qualified_name + if inv_id.iteration_id: + parts = inv_id.iteration_id.split("_") + cur_invid = parts[0] if len(parts) < 3 else "_".join(parts[:-1]) + key = key + "#" + cur_invid + if key not in unique_inv_ids: + unique_inv_ids[key] = 0 + unique_inv_ids[key] += min(runtimes) + return unique_inv_ids + # === Test Result Comparison === def compare_test_results( diff --git a/codeflash/languages/java/test_runner.py b/codeflash/languages/java/test_runner.py index 5ca2f2f8f..1ebc2bc8f 100644 --- a/codeflash/languages/java/test_runner.py +++ b/codeflash/languages/java/test_runner.py @@ -6,6 +6,7 @@ from __future__ import annotations +import contextlib import logging import os import re @@ -562,6 +563,26 @@ def _get_test_classpath( if main_classes.exists(): cp_parts.append(str(main_classes)) + # For multi-module projects, also include target/classes from all modules + # This is needed because the test module may depend on other modules + if test_module: + # Find all target/classes directories in sibling modules + for module_dir in project_root.iterdir(): + if module_dir.is_dir() and module_dir.name != test_module: + module_classes = module_dir / "target" / "classes" + if module_classes.exists(): + logger.debug("Adding multi-module classpath: %s", module_classes) + cp_parts.append(str(module_classes)) + + # Add JUnit Platform Console Standalone JAR if not already on classpath. + # This is required for direct JVM execution with ConsoleLauncher, + # which is NOT included in the standard junit-jupiter dependency tree. + if "console-standalone" not in classpath and "ConsoleLauncher" not in classpath: + console_jar = _find_junit_console_standalone() + if console_jar: + logger.debug("Adding JUnit Console Standalone to classpath: %s", console_jar) + cp_parts.append(str(console_jar)) + return os.pathsep.join(cp_parts) except subprocess.TimeoutExpired: @@ -576,6 +597,56 @@ def _get_test_classpath( cp_file.unlink() +def _find_junit_console_standalone() -> Path | None: + """Find the JUnit Platform Console Standalone JAR in the local Maven repository. + + This JAR contains ConsoleLauncher which is required for direct JVM test execution + with JUnit 5. It is NOT included in the standard junit-jupiter dependency tree. + + Returns: + Path to the console standalone JAR, or None if not found. + + """ + m2_base = Path.home() / ".m2" / "repository" / "org" / "junit" / "platform" / "junit-platform-console-standalone" + if not m2_base.exists(): + # Try to download it via Maven + mvn = find_maven_executable() + if mvn: + logger.debug("Console standalone not found in cache, downloading via Maven") + with contextlib.suppress(subprocess.TimeoutExpired, Exception): + subprocess.run( + [ + mvn, + "dependency:get", + "-Dartifact=org.junit.platform:junit-platform-console-standalone:1.10.0", + "-q", + "-B", + ], + check=False, + capture_output=True, + text=True, + timeout=30, + ) + if not m2_base.exists(): + return None + + # Find the latest version available + try: + versions = sorted( + [d for d in m2_base.iterdir() if d.is_dir()], + key=lambda d: tuple(int(x) for x in d.name.split(".") if x.isdigit()), + reverse=True, + ) + for version_dir in versions: + jar = version_dir / f"junit-platform-console-standalone-{version_dir.name}.jar" + if jar.exists(): + return jar + except Exception: + pass + + return None + + def _run_tests_direct( classpath: str, test_classes: list[str], @@ -605,49 +676,103 @@ def _run_tests_direct( java = _find_java_executable() or "java" - # Build command using JUnit Platform Console Launcher - # The launcher is included in junit-platform-console-standalone or junit-jupiter - cmd = [ - str(java), - # Java 16+ module system: Kryo needs reflective access to internal JDK classes - "--add-opens", - "java.base/java.util=ALL-UNNAMED", - "--add-opens", - "java.base/java.lang=ALL-UNNAMED", - "--add-opens", - "java.base/java.lang.reflect=ALL-UNNAMED", - "--add-opens", - "java.base/java.io=ALL-UNNAMED", - "--add-opens", - "java.base/java.math=ALL-UNNAMED", - "--add-opens", - "java.base/java.net=ALL-UNNAMED", - "--add-opens", - "java.base/java.util.zip=ALL-UNNAMED", - "-cp", - classpath, - "org.junit.platform.console.ConsoleLauncher", - "--disable-banner", - "--disable-ansi-colors", - # Use 'none' details to avoid duplicate output - # Timing markers are captured in XML via stdout capture config - "--details=none", - # Enable stdout/stderr capture in XML reports - # This ensures timing markers are included in the XML system-out element - "--config=junit.platform.output.capture.stdout=true", - "--config=junit.platform.output.capture.stderr=true", - ] - - # Add reports directory if specified (for XML output) - if reports_dir: - reports_dir.mkdir(parents=True, exist_ok=True) - cmd.extend(["--reports-dir", str(reports_dir)]) - - # Add test classes to select - for test_class in test_classes: - cmd.extend(["--select-class", test_class]) - - logger.debug("Running tests directly: java -cp ... ConsoleLauncher --select-class %s", test_classes) + # Detect JUnit version from the classpath string. + # We check for junit-jupiter (the JUnit 5 test API) as the indicator of JUnit 5 tests. + # Note: console-standalone and junit-platform are NOT reliable indicators because + # we inject console-standalone ourselves in _get_test_classpath(), so it's always present. + # ConsoleLauncher can run both JUnit 5 and JUnit 4 tests (via vintage engine), + # so we prefer it when available and only fall back to JUnitCore for pure JUnit 4 + # projects without ConsoleLauncher on the classpath. + has_junit5_tests = "junit-jupiter" in classpath + has_console_launcher = "console-standalone" in classpath or "ConsoleLauncher" in classpath + # Use ConsoleLauncher if available (works for both JUnit 4 via vintage and JUnit 5). + # Only use JUnitCore when ConsoleLauncher is not on the classpath at all. + is_junit4 = not has_console_launcher + if is_junit4: + logger.debug("JUnit 4 project, no ConsoleLauncher available, using JUnitCore") + elif has_junit5_tests: + logger.debug("JUnit 5 project, using ConsoleLauncher") + else: + logger.debug("JUnit 4 project, using ConsoleLauncher (via vintage engine)") + + if is_junit4: + if reports_dir: + logger.debug( + "JUnitCore does not support XML report generation; reports_dir=%s ignored. " + "XML reports require ConsoleLauncher.", + reports_dir, + ) + # Use JUnit 4's JUnitCore runner + cmd = [ + str(java), + # Java 16+ module system: Kryo needs reflective access to internal JDK classes + "--add-opens", + "java.base/java.util=ALL-UNNAMED", + "--add-opens", + "java.base/java.lang=ALL-UNNAMED", + "--add-opens", + "java.base/java.lang.reflect=ALL-UNNAMED", + "--add-opens", + "java.base/java.io=ALL-UNNAMED", + "--add-opens", + "java.base/java.math=ALL-UNNAMED", + "--add-opens", + "java.base/java.net=ALL-UNNAMED", + "--add-opens", + "java.base/java.util.zip=ALL-UNNAMED", + "-cp", + classpath, + "org.junit.runner.JUnitCore", + ] + # Add test classes + cmd.extend(test_classes) + else: + # Build command using JUnit Platform Console Launcher (JUnit 5) + # The launcher is included in junit-platform-console-standalone or junit-jupiter + cmd = [ + str(java), + # Java 16+ module system: Kryo needs reflective access to internal JDK classes + "--add-opens", + "java.base/java.util=ALL-UNNAMED", + "--add-opens", + "java.base/java.lang=ALL-UNNAMED", + "--add-opens", + "java.base/java.lang.reflect=ALL-UNNAMED", + "--add-opens", + "java.base/java.io=ALL-UNNAMED", + "--add-opens", + "java.base/java.math=ALL-UNNAMED", + "--add-opens", + "java.base/java.net=ALL-UNNAMED", + "--add-opens", + "java.base/java.util.zip=ALL-UNNAMED", + "-cp", + classpath, + "org.junit.platform.console.ConsoleLauncher", + "--disable-banner", + "--disable-ansi-colors", + # Use 'none' details to avoid duplicate output + # Timing markers are captured in XML via stdout capture config + "--details=none", + # Enable stdout/stderr capture in XML reports + # This ensures timing markers are included in the XML system-out element + "--config=junit.platform.output.capture.stdout=true", + "--config=junit.platform.output.capture.stderr=true", + ] + + # Add reports directory if specified (for XML output) + if reports_dir: + reports_dir.mkdir(parents=True, exist_ok=True) + cmd.extend(["--reports-dir", str(reports_dir)]) + + # Add test classes to select + for test_class in test_classes: + cmd.extend(["--select-class", test_class]) + + if is_junit4: + logger.debug("Running tests directly: java -cp ... JUnitCore %s", test_classes) + else: + logger.debug("Running tests directly: java -cp ... ConsoleLauncher --select-class %s", test_classes) try: return subprocess.run( @@ -982,6 +1107,10 @@ def run_benchmarking_tests( logger.debug("Loop %d completed in %.2fs (returncode=%d)", loop_idx, loop_time, result.returncode) + # Log stderr if direct JVM execution failed (for debugging) + if result.returncode != 0 and result.stderr: + logger.debug("Direct JVM stderr: %s", result.stderr[:500]) + # Check if direct JVM execution failed on the first loop. # Fall back to Maven-based execution for: # - JUnit 4 projects (ConsoleLauncher not on classpath or no tests discovered) diff --git a/codeflash/models/models.py b/codeflash/models/models.py index 9baa8f83e..70267c067 100644 --- a/codeflash/models/models.py +++ b/codeflash/models/models.py @@ -664,7 +664,7 @@ def log_coverage(self) -> None: from rich.tree import Tree tree = Tree("Test Coverage Results") - tree.add(f"Main Function: {self.main_func_coverage.name}: {self.coverage:.2f}%") + tree.add(f"Main Function: {self.main_func_coverage.name}: {self.main_func_coverage.coverage:.2f}%") if self.dependent_func_coverage: tree.add( f"Dependent Function: {self.dependent_func_coverage.name}: {self.dependent_func_coverage.coverage:.2f}%" diff --git a/codeflash/optimization/optimizer.py b/codeflash/optimization/optimizer.py index 63afaa566..ed99e8083 100644 --- a/codeflash/optimization/optimizer.py +++ b/codeflash/optimization/optimizer.py @@ -33,6 +33,7 @@ from codeflash.languages import current_language_support, is_java, is_javascript, set_current_language from codeflash.models.models import ValidCode from codeflash.telemetry.posthog_cf import ph +from codeflash.verification.parse_test_output import clear_test_file_path_cache from codeflash.verification.verification_utils import TestConfig if TYPE_CHECKING: @@ -689,6 +690,7 @@ def run(self) -> None: if function_optimizer is not None: function_optimizer.executor.shutdown(wait=True) function_optimizer.cleanup_generated_files() + clear_test_file_path_cache() ph("cli-optimize-run-finished", {"optimizations_found": optimizations_found}) if len(self.patch_files) > 0: diff --git a/codeflash/verification/coverage_utils.py b/codeflash/verification/coverage_utils.py index f5a41a737..1b2341680 100644 --- a/codeflash/verification/coverage_utils.py +++ b/codeflash/verification/coverage_utils.py @@ -327,7 +327,8 @@ def load_from_jacoco_xml( bare_name = method.get("name") if bare_name: all_methods[bare_name] = (method, method_line) - if bare_name == function_name: + # Match against bare name or qualified name (e.g., "computeDigest" or "Crypto.computeDigest") + if bare_name == function_name or function_name.endswith("." + bare_name): method_elem = method method_start_line = method_line diff --git a/codeflash/verification/parse_test_output.py b/codeflash/verification/parse_test_output.py index e00c3a827..deb7d3a4b 100644 --- a/codeflash/verification/parse_test_output.py +++ b/codeflash/verification/parse_test_output.py @@ -143,6 +143,14 @@ def parse_concurrency_metrics(test_results: TestResults, function_name: str) -> ) +# Cache for resolved test file paths to avoid repeated rglob calls +_test_file_path_cache: dict[tuple[str, Path], Path | None] = {} + + +def clear_test_file_path_cache() -> None: + _test_file_path_cache.clear() + + def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> Path | None: """Resolve test file path from pytest's test class path or Java class path. @@ -164,6 +172,13 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P >>> # Should find: /path/to/tests/unittest/test_file.py """ + # Check cache first + cache_key = (test_class_path, base_dir) + if cache_key in _test_file_path_cache: + cached_result = _test_file_path_cache[cache_key] + logger.debug(f"[RESOLVE] Cache hit for {test_class_path}: {cached_result}") + return cached_result + # Handle Java class paths (convert dots to path and add .java extension) # Java class paths look like "com.example.TestClass" and should map to # src/test/java/com/example/TestClass.java @@ -178,6 +193,7 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P logger.debug(f"[RESOLVE] Attempt 1: checking {potential_path}") if potential_path.exists(): logger.debug(f"[RESOLVE] Attempt 1 SUCCESS: found {potential_path}") + _test_file_path_cache[cache_key] = potential_path return potential_path # 2. Under src/test/java relative to project root @@ -189,6 +205,7 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P logger.debug(f"[RESOLVE] Attempt 2: checking {potential_path} (project_root={project_root})") if potential_path.exists(): logger.debug(f"[RESOLVE] Attempt 2 SUCCESS: found {potential_path}") + _test_file_path_cache[cache_key] = potential_path return potential_path # 3. Search for the file in base_dir and its subdirectories @@ -196,9 +213,11 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P logger.debug(f"[RESOLVE] Attempt 3: rglob for {file_name} in {base_dir}") for java_file in base_dir.rglob(file_name): logger.debug(f"[RESOLVE] Attempt 3 SUCCESS: rglob found {java_file}") + _test_file_path_cache[cache_key] = java_file return java_file logger.warning(f"[RESOLVE] FAILED to resolve {test_class_path} in base_dir {base_dir}") + _test_file_path_cache[cache_key] = None # Cache negative results too return None # Handle file paths (contain slashes and extensions like .js/.ts) @@ -207,6 +226,7 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P # Try the path as-is if it's absolute potential_path = Path(test_class_path) if potential_path.is_absolute() and potential_path.exists(): + _test_file_path_cache[cache_key] = potential_path return potential_path # Try to resolve relative to base_dir's parent (project root) @@ -216,6 +236,7 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P try: potential_path = potential_path.resolve() if potential_path.exists(): + _test_file_path_cache[cache_key] = potential_path return potential_path except (OSError, RuntimeError): pass @@ -225,10 +246,12 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P try: potential_path = potential_path.resolve() if potential_path.exists(): + _test_file_path_cache[cache_key] = potential_path return potential_path except (OSError, RuntimeError): pass + _test_file_path_cache[cache_key] = None # Cache negative results return None # First try the full path (Python module path) @@ -259,6 +282,8 @@ def resolve_test_file_from_class_path(test_class_path: str, base_dir: Path) -> P if test_file_path: break + # Cache the result (could be None) + _test_file_path_cache[cache_key] = test_file_path return test_file_path @@ -795,14 +820,14 @@ def parse_test_xml( sys_stdout = testcase.system_out or "" # Use different patterns for Java (5-field start, 6-field end) vs Python (6-field both) - # Java format: !$######module:class:func:loop:iter######$! (start) - # !######module:class:func:loop:iter:duration######! (end) + # Java format: !$######module:class.test:func:loop:iter######$! (start) + # !######module:class.test:func:loop:iter:duration######! (end) if is_java(): begin_matches = list(start_pattern.finditer(sys_stdout)) end_matches = {} for match in end_pattern.finditer(sys_stdout): groups = match.groups() - # Key is first 5 groups (module, class, func, loop, iter) + # Key is first 5 groups (module, class.test, func, loop, iter) end_matches[groups[:5]] = match # For Java: fallback to pre-parsed subprocess stdout when XML system-out has no timing markers @@ -863,17 +888,22 @@ def parse_test_xml( groups = match.groups() # Java and Python have different marker formats: - # Java: 5 groups - (module, class, func, loop_index, iteration_id) + # Java: 5 groups - (module, class.test, func, loop_index, iteration_id) # Python: 6 groups - (module, class.test, _, func, loop_index, iteration_id) if is_java(): - # Java format: !$######module:class:func:loop:iter######$! + # Java format: !$######module:class.test:func:loop:iter######$! end_key = groups[:5] # Use all 5 groups as key end_match = end_matches.get(end_key) iteration_id = groups[4] # iter is at index 4 loop_idx = int(groups[3]) # loop is at index 3 test_module = groups[0] # module - test_class_str = groups[1] # class - test_func = test_function # Use the testcase name from XML + # groups[1] is "class.testMethod" — extract class and test name + class_test_field = groups[1] + if "." in class_test_field: + test_class_str, test_func = class_test_field.rsplit(".", 1) + else: + test_class_str = class_test_field + test_func = test_function # Fallback to testcase name from XML func_getting_tested = groups[2] # func being tested runtime = None @@ -1228,6 +1258,21 @@ def parse_test_results( results = merge_test_results(test_results_xml, test_results_data, test_config.test_framework) + # Bug #10 Fix: For Java performance tests, preserve subprocess stdout containing timing markers + # This is needed for calculate_function_throughput_from_test_results to work correctly + if is_java() and testing_type == TestingMode.PERFORMANCE and run_result is not None: + try: + # Extract stdout from subprocess result containing timing markers + if isinstance(run_result.stdout, bytes): + results.perf_stdout = run_result.stdout.decode("utf-8", errors="replace") + elif isinstance(run_result.stdout, str): + results.perf_stdout = run_result.stdout + logger.debug( + f"Bug #10 Fix: Set perf_stdout for Java performance tests ({len(results.perf_stdout or '')} chars)" + ) + except Exception as e: + logger.debug(f"Bug #10 Fix: Failed to set perf_stdout: {e}") + all_args = False coverage = None if coverage_database_file and source_file and code_context and function_name: diff --git a/codeflash/verification/verification_utils.py b/codeflash/verification/verification_utils.py index c6650ef99..0a613c1fe 100644 --- a/codeflash/verification/verification_utils.py +++ b/codeflash/verification/verification_utils.py @@ -179,6 +179,7 @@ class TestConfig: use_cache: bool = True _language: Optional[str] = None # Language identifier for multi-language support js_project_root: Optional[Path] = None # JavaScript project root (directory containing package.json) + _test_framework: Optional[str] = None # Cached test framework detection result def __post_init__(self) -> None: self.tests_root = self.tests_root.resolve() @@ -191,14 +192,19 @@ def test_framework(self) -> str: For JavaScript/TypeScript: uses the configured framework (vitest, jest, or mocha). For Python: uses pytest as default. + Result is cached after first detection to avoid repeated pom.xml parsing. """ + if self._test_framework is not None: + return self._test_framework if is_javascript(): from codeflash.languages.test_framework import get_js_test_framework_or_default - return get_js_test_framework_or_default() - if is_java(): - return self._detect_java_test_framework() - return "pytest" + self._test_framework = get_js_test_framework_or_default() + elif is_java(): + self._test_framework = self._detect_java_test_framework() + else: + self._test_framework = "pytest" + return self._test_framework def _detect_java_test_framework(self) -> str: """Detect the Java test framework from the project configuration. @@ -232,7 +238,7 @@ def _detect_java_test_framework(self) -> str: return config.test_framework except Exception: pass - return "junit5" # Default fallback + return "junit4" # Default fallback (JUnit 4 is more common in legacy projects) def set_language(self, language: str) -> None: """Set the language for this test config. diff --git a/tests/test_languages/test_java/test_instrumentation.py b/tests/test_languages/test_java/test_instrumentation.py index a5452f094..588f803a3 100644 --- a/tests/test_languages/test_java/test_instrumentation.py +++ b/tests/test_languages/test_java/test_instrumentation.py @@ -145,7 +145,8 @@ def test_instrument_behavior_mode_simple(self, tmp_path: Path): String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testAdd"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -159,7 +160,7 @@ def test_instrument_behavior_mode_simple(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -175,7 +176,7 @@ def test_instrument_behavior_mode_simple(self, tmp_path: Path): try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "CalculatorTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -256,7 +257,8 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testNegativeInput_ThrowsIllegalArgumentException"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -265,7 +267,7 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -281,7 +283,7 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "FibonacciTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -309,7 +311,8 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path String _cf_outputFile2 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration2 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration2 == null) _cf_testIteration2 = "0"; - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + "######$!"); + String _cf_test2 = "testZeroInput_ReturnsZero"; + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + "######$!"); byte[] _cf_serializedResult2 = null; long _cf_end2 = -1; long _cf_start2 = 0; @@ -322,7 +325,7 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + ":" + _cf_dur2 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile2 != null && !_cf_outputFile2.isEmpty()) { try { @@ -338,7 +341,7 @@ def test_instrument_behavior_mode_assert_throws_expression_lambda(self, tmp_path try (PreparedStatement _cf_pstmt2 = _cf_conn2.prepareStatement(_cf_sql2)) { _cf_pstmt2.setString(1, _cf_mod2); _cf_pstmt2.setString(2, _cf_cls2); - _cf_pstmt2.setString(3, "FibonacciTestTest"); + _cf_pstmt2.setString(3, _cf_test2); _cf_pstmt2.setString(4, _cf_fn2); _cf_pstmt2.setInt(5, _cf_loop2); _cf_pstmt2.setString(6, _cf_iter2 + "_" + _cf_testIteration2); @@ -420,7 +423,8 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testNegativeInput_ThrowsIllegalArgumentException"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -431,7 +435,7 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -447,7 +451,7 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "FibonacciTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -475,7 +479,8 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat String _cf_outputFile2 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration2 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration2 == null) _cf_testIteration2 = "0"; - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + "######$!"); + String _cf_test2 = "testZeroInput_ReturnsZero"; + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + "######$!"); byte[] _cf_serializedResult2 = null; long _cf_end2 = -1; long _cf_start2 = 0; @@ -488,7 +493,7 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_iter2 + ":" + _cf_dur2 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile2 != null && !_cf_outputFile2.isEmpty()) { try { @@ -504,7 +509,7 @@ def test_instrument_behavior_mode_assert_throws_block_lambda(self, tmp_path: Pat try (PreparedStatement _cf_pstmt2 = _cf_conn2.prepareStatement(_cf_sql2)) { _cf_pstmt2.setString(1, _cf_mod2); _cf_pstmt2.setString(2, _cf_cls2); - _cf_pstmt2.setString(3, "FibonacciTestTest"); + _cf_pstmt2.setString(3, _cf_test2); _cf_pstmt2.setString(4, _cf_fn2); _cf_pstmt2.setInt(5, _cf_loop2); _cf_pstmt2.setString(6, _cf_iter2 + "_" + _cf_testIteration2); @@ -567,11 +572,12 @@ def test_instrument_performance_mode_simple(self, tmp_path: Path): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "CalculatorTest"; String _cf_cls1 = "CalculatorTest"; + String _cf_test1 = "testAdd"; String _cf_fn1 = "add"; Calculator calc = new Calculator(); for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -581,7 +587,7 @@ def test_instrument_performance_mode_simple(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -636,10 +642,11 @@ def test_instrument_performance_mode_multiple_tests(self, tmp_path: Path): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "MathTest"; String _cf_cls1 = "MathTest"; + String _cf_test1 = "testAdd"; String _cf_fn1 = "add"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -649,7 +656,7 @@ def test_instrument_performance_mode_multiple_tests(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -661,10 +668,11 @@ def test_instrument_performance_mode_multiple_tests(self, tmp_path: Path): int _cf_innerIterations2 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod2 = "MathTest"; String _cf_cls2 = "MathTest"; + String _cf_test2 = "testSubtract"; String _cf_fn2 = "add"; for (int _cf_i2 = 0; _cf_i2 < _cf_innerIterations2; _cf_i2++) { - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); long _cf_end2 = -1; long _cf_start2 = 0; try { @@ -674,7 +682,7 @@ def test_instrument_performance_mode_multiple_tests(self, tmp_path: Path): } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); } } } @@ -736,10 +744,11 @@ def test_instrument_preserves_annotations(self, tmp_path: Path): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "ServiceTest"; String _cf_cls1 = "ServiceTest"; + String _cf_test1 = "testService"; String _cf_fn1 = "call"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -749,7 +758,7 @@ def test_instrument_preserves_annotations(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -816,7 +825,8 @@ class TestKryoSerializerUsage: String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testFoo"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -828,7 +838,7 @@ class TestKryoSerializerUsage: } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -844,7 +854,7 @@ class TestKryoSerializerUsage: try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "MyTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -873,10 +883,11 @@ class TestKryoSerializerUsage: int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "MyTest"; String _cf_cls1 = "MyTest"; + String _cf_test1 = "testFoo"; String _cf_fn1 = "foo"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -886,7 +897,7 @@ class TestKryoSerializerUsage: } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -946,10 +957,11 @@ def test_single_test_method(self): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "SimpleTest"; String _cf_cls1 = "SimpleTest"; + String _cf_test1 = "testSomething"; String _cf_fn1 = "doSomething"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -959,7 +971,7 @@ def test_single_test_method(self): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -992,10 +1004,11 @@ def test_multiple_test_methods(self): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "MultiTest"; String _cf_cls1 = "MultiTest"; + String _cf_test1 = "testFirst"; String _cf_fn1 = "func"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -1005,7 +1018,7 @@ def test_multiple_test_methods(self): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -1017,11 +1030,12 @@ def test_multiple_test_methods(self): int _cf_innerIterations2 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod2 = "MultiTest"; String _cf_cls2 = "MultiTest"; + String _cf_test2 = "testSecond"; String _cf_fn2 = "func"; second(); for (int _cf_i2 = 0; _cf_i2 < _cf_innerIterations2; _cf_i2++) { - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); long _cf_end2 = -1; long _cf_start2 = 0; try { @@ -1031,7 +1045,7 @@ def test_multiple_test_methods(self): } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); } } } @@ -1078,9 +1092,10 @@ def test_multiple_target_calls_in_single_test_method(self): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "RepeatTest"; String _cf_cls1 = "RepeatTest"; + String _cf_test1 = "testRepeat"; String _cf_fn1 = "target"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + "1_" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + "1_" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -1090,7 +1105,7 @@ def test_multiple_target_calls_in_single_test_method(self): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + "1_" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + "1_" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } helper(); @@ -1100,9 +1115,10 @@ def test_multiple_target_calls_in_single_test_method(self): int _cf_innerIterations2 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod2 = "RepeatTest"; String _cf_cls2 = "RepeatTest"; + String _cf_test2 = "testRepeat"; String _cf_fn2 = "target"; for (int _cf_i2 = 0; _cf_i2 < _cf_innerIterations2; _cf_i2++) { - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + "2_" + _cf_i2 + "######$!"); + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + "2_" + _cf_i2 + "######$!"); long _cf_end2 = -1; long _cf_start2 = 0; try { @@ -1112,7 +1128,7 @@ def test_multiple_target_calls_in_single_test_method(self): } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + "2_" + _cf_i2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + "2_" + _cf_i2 + ":" + _cf_dur2 + "######!"); } } teardown(); @@ -1317,7 +1333,8 @@ def test_instrument_generated_test_behavior_mode(self): String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testAdd"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -1330,7 +1347,7 @@ def test_instrument_generated_test_behavior_mode(self): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -1346,7 +1363,7 @@ def test_instrument_generated_test_behavior_mode(self): try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "CalculatorTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -1404,10 +1421,11 @@ def test_instrument_generated_test_performance_mode(self): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "GeneratedTest"; String _cf_cls1 = "GeneratedTest"; + String _cf_test1 = "testMethod"; String _cf_fn1 = "method"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -1417,7 +1435,7 @@ def test_instrument_generated_test_performance_mode(self): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -1433,9 +1451,9 @@ def test_timing_markers_can_be_parsed(self): """Test that generated timing markers can be parsed with the standard regex.""" # Simulate stdout from instrumented test stdout = """ -!$######TestModule:TestClass:targetFunc:1:1######$! +!$######TestModule:TestClass.testMethod:targetFunc:1:1######$! Running test... -!######TestModule:TestClass:targetFunc:1:1:12345678######! +!######TestModule:TestClass.testMethod:targetFunc:1:1:12345678######! """ # Use the same regex patterns from parse_test_output.py start_pattern = re.compile(r"!\$######([^:]*):([^:]*):([^:]*):([^:]*):([^:]+)######\$!") @@ -1450,14 +1468,14 @@ def test_timing_markers_can_be_parsed(self): # Verify parsed values start = start_matches[0] assert start[0] == "TestModule" - assert start[1] == "TestClass" + assert start[1] == "TestClass.testMethod" assert start[2] == "targetFunc" assert start[3] == "1" assert start[4] == "1" end = end_matches[0] assert end[0] == "TestModule" - assert end[1] == "TestClass" + assert end[1] == "TestClass.testMethod" assert end[2] == "targetFunc" assert end[3] == "1" assert end[4] == "1" @@ -1466,15 +1484,15 @@ def test_timing_markers_can_be_parsed(self): def test_multiple_timing_markers(self): """Test parsing multiple timing markers.""" stdout = """ -!$######Module:Class:func:1:1######$! +!$######Module:Class.testMethod:func:1:1######$! test 1 -!######Module:Class:func:1:1:100000######! -!$######Module:Class:func:2:1######$! +!######Module:Class.testMethod:func:1:1:100000######! +!$######Module:Class.testMethod:func:2:1######$! test 2 -!######Module:Class:func:2:1:200000######! -!$######Module:Class:func:3:1######$! +!######Module:Class.testMethod:func:2:1:200000######! +!$######Module:Class.testMethod:func:3:1######$! test 3 -!######Module:Class:func:3:1:150000######! +!######Module:Class.testMethod:func:3:1:150000######! """ end_pattern = re.compile(r"!######([^:]*):([^:]*):([^:]*):([^:]*):([^:]+):([^:]+)######!") end_matches = end_pattern.findall(stdout) @@ -1492,15 +1510,15 @@ def test_inner_loop_timing_markers(self): """ # Simulate stdout from 3 inner iterations (inner_iterations=3) stdout = """ -!$######Module:Class:func:1:0######$! +!$######Module:Class.testMethod:func:1:0######$! iteration 0 -!######Module:Class:func:1:0:150000######! -!$######Module:Class:func:1:1######$! +!######Module:Class.testMethod:func:1:0:150000######! +!$######Module:Class.testMethod:func:1:1######$! iteration 1 -!######Module:Class:func:1:1:50000######! -!$######Module:Class:func:1:2######$! +!######Module:Class.testMethod:func:1:1:50000######! +!$######Module:Class.testMethod:func:1:2######$! iteration 2 -!######Module:Class:func:1:2:45000######! +!######Module:Class.testMethod:func:1:2:45000######! """ start_pattern = re.compile(r"!\$######([^:]*):([^:]*):([^:]*):([^:]*):([^:]+)######\$!") end_pattern = re.compile(r"!######([^:]*):([^:]*):([^:]*):([^:]*):([^:]+):([^:]+)######!") @@ -1588,10 +1606,11 @@ def test_instrumented_code_has_balanced_braces(self, tmp_path: Path): int _cf_innerIterations2 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod2 = "BraceTest"; String _cf_cls2 = "BraceTest"; + String _cf_test2 = "testTwo"; String _cf_fn2 = "process"; for (int _cf_i2 = 0; _cf_i2 < _cf_innerIterations2; _cf_i2++) { - System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); + System.out.println("!$######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + "######$!"); long _cf_end2 = -1; long _cf_start2 = 0; try { @@ -1603,7 +1622,7 @@ def test_instrumented_code_has_balanced_braces(self, tmp_path: Path): } finally { long _cf_end2_finally = System.nanoTime(); long _cf_dur2 = (_cf_end2 != -1 ? _cf_end2 : _cf_end2_finally) - _cf_start2; - System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); + System.out.println("!######" + _cf_mod2 + ":" + _cf_cls2 + "." + _cf_test2 + ":" + _cf_fn2 + ":" + _cf_loop2 + ":" + _cf_i2 + ":" + _cf_dur2 + "######!"); } } } @@ -1664,11 +1683,12 @@ def test_instrumented_code_preserves_imports(self, tmp_path: Path): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "ImportTest"; String _cf_cls1 = "ImportTest"; + String _cf_test1 = "testCollections"; String _cf_fn1 = "size"; List list = new ArrayList<>(); for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -1678,7 +1698,7 @@ def test_instrumented_code_preserves_imports(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -1779,10 +1799,11 @@ def test_test_with_nested_braces(self, tmp_path: Path): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "NestedTest"; String _cf_cls1 = "NestedTest"; + String _cf_test1 = "testNested"; String _cf_fn1 = "process"; for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -1798,7 +1819,7 @@ def test_test_with_nested_braces(self, tmp_path: Path): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -2140,11 +2161,12 @@ def test_run_and_parse_performance_mode(self, java_project): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "MathUtilsTest"; String _cf_cls1 = "MathUtilsTest"; + String _cf_test1 = "testMultiply"; String _cf_fn1 = "multiply"; MathUtils math = new MathUtils(); for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -2154,7 +2176,7 @@ def test_run_and_parse_performance_mode(self, java_project): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } } @@ -2522,7 +2544,8 @@ def test_behavior_mode_writes_to_sqlite(self, java_project): String _cf_outputFile1 = System.getenv("CODEFLASH_OUTPUT_FILE"); String _cf_testIteration1 = System.getenv("CODEFLASH_TEST_ITERATION"); if (_cf_testIteration1 == null) _cf_testIteration1 = "0"; - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); + String _cf_test1 = "testIncrement"; + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + "######$!"); byte[] _cf_serializedResult1 = null; long _cf_end1 = -1; long _cf_start1 = 0; @@ -2536,7 +2559,7 @@ def test_behavior_mode_writes_to_sqlite(self, java_project): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_iter1 + ":" + _cf_dur1 + "######!"); // Write to SQLite if output file is set if (_cf_outputFile1 != null && !_cf_outputFile1.isEmpty()) { try { @@ -2552,7 +2575,7 @@ def test_behavior_mode_writes_to_sqlite(self, java_project): try (PreparedStatement _cf_pstmt1 = _cf_conn1.prepareStatement(_cf_sql1)) { _cf_pstmt1.setString(1, _cf_mod1); _cf_pstmt1.setString(2, _cf_cls1); - _cf_pstmt1.setString(3, "CounterTestTest"); + _cf_pstmt1.setString(3, _cf_test1); _cf_pstmt1.setString(4, _cf_fn1); _cf_pstmt1.setInt(5, _cf_loop1); _cf_pstmt1.setString(6, _cf_iter1 + "_" + _cf_testIteration1); @@ -2737,11 +2760,12 @@ def test_performance_mode_inner_loop_timing_markers(self, java_project): int _cf_innerIterations1 = Integer.parseInt(System.getenv().getOrDefault("CODEFLASH_INNER_ITERATIONS", "100")); String _cf_mod1 = "FibonacciTest"; String _cf_cls1 = "FibonacciTest"; + String _cf_test1 = "testFib"; String _cf_fn1 = "fib"; Fibonacci fib = new Fibonacci(); for (int _cf_i1 = 0; _cf_i1 < _cf_innerIterations1; _cf_i1++) { - System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); + System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + "######$!"); long _cf_end1 = -1; long _cf_start1 = 0; try { @@ -2751,7 +2775,7 @@ def test_performance_mode_inner_loop_timing_markers(self, java_project): } finally { long _cf_end1_finally = System.nanoTime(); long _cf_dur1 = (_cf_end1 != -1 ? _cf_end1 : _cf_end1_finally) - _cf_start1; - System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); + System.out.println("!######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":" + _cf_i1 + ":" + _cf_dur1 + "######!"); } } }