mirror of
https://github.com/codeflash-ai/codeflash.git
synced 2026-05-04 18:25:17 +00:00
ignore calls inside string litrals for instrumentation and fix e2e test
This commit is contained in:
parent
e07fd1d439
commit
6b77be56ef
4 changed files with 174 additions and 5 deletions
|
|
@ -8,7 +8,7 @@
|
|||
* @param {number} n - The index of the Fibonacci number to calculate
|
||||
* @returns {number} - The nth Fibonacci number
|
||||
*/
|
||||
export function fibonacci(n) {
|
||||
function fibonacci(n) {
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ export function fibonacci(n) {
|
|||
* @param {number} num - The number to check
|
||||
* @returns {boolean} - True if num is a Fibonacci number
|
||||
*/
|
||||
export function isFibonacci(num) {
|
||||
function isFibonacci(num) {
|
||||
// A number is Fibonacci if one of (5*n*n + 4) or (5*n*n - 4) is a perfect square
|
||||
const check1 = 5 * num * num + 4;
|
||||
const check2 = 5 * num * num - 4;
|
||||
|
|
@ -33,7 +33,7 @@ export function isFibonacci(num) {
|
|||
* @param {number} n - The number to check
|
||||
* @returns {boolean} - True if n is a perfect square
|
||||
*/
|
||||
export function isPerfectSquare(n) {
|
||||
function isPerfectSquare(n) {
|
||||
const sqrt = Math.sqrt(n);
|
||||
return sqrt === Math.floor(sqrt);
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ export function isPerfectSquare(n) {
|
|||
* @param {number} n - The number of Fibonacci numbers to generate
|
||||
* @returns {number[]} - Array of Fibonacci numbers
|
||||
*/
|
||||
export function fibonacciSequence(n) {
|
||||
function fibonacciSequence(n) {
|
||||
const result = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
result.push(fibonacci(i));
|
||||
|
|
|
|||
|
|
@ -56,6 +56,46 @@ codeflash_import_pattern = re.compile(
|
|||
)
|
||||
|
||||
|
||||
def is_inside_string(code: str, pos: int) -> bool:
|
||||
"""Check if a position in code is inside a string literal.
|
||||
|
||||
Handles single quotes, double quotes, and template literals (backticks).
|
||||
Properly handles escaped quotes.
|
||||
|
||||
Args:
|
||||
code: The source code.
|
||||
pos: The position to check.
|
||||
|
||||
Returns:
|
||||
True if the position is inside a string literal.
|
||||
|
||||
"""
|
||||
in_string = False
|
||||
string_char = None
|
||||
i = 0
|
||||
|
||||
while i < pos:
|
||||
char = code[i]
|
||||
|
||||
if in_string:
|
||||
# Check for escape sequence
|
||||
if char == "\\" and i + 1 < len(code):
|
||||
i += 2 # Skip escaped character
|
||||
continue
|
||||
# Check for end of string
|
||||
if char == string_char:
|
||||
in_string = False
|
||||
string_char = None
|
||||
# Check for start of string
|
||||
elif char in "\"'`":
|
||||
in_string = True
|
||||
string_char = char
|
||||
|
||||
i += 1
|
||||
|
||||
return in_string
|
||||
|
||||
|
||||
class StandaloneCallTransformer:
|
||||
"""Transforms standalone func(...) calls in JavaScript test code.
|
||||
|
||||
|
|
@ -150,6 +190,10 @@ class StandaloneCallTransformer:
|
|||
|
||||
def _should_skip_match(self, code: str, start: int, match: re.Match) -> bool:
|
||||
"""Check if the match should be skipped (inside expect, already transformed, etc.)."""
|
||||
# Skip if inside a string literal (e.g., test description)
|
||||
if is_inside_string(code, start):
|
||||
return True
|
||||
|
||||
# Look backwards to check context
|
||||
lookback_start = max(0, start - 200)
|
||||
lookback = code[lookback_start:start]
|
||||
|
|
@ -439,6 +483,12 @@ class ExpectCallTransformer:
|
|||
result.append(code[pos:])
|
||||
break
|
||||
|
||||
# Skip if inside a string literal (e.g., test description)
|
||||
if is_inside_string(code, match.start()):
|
||||
result.append(code[pos : match.end()])
|
||||
pos = match.end()
|
||||
continue
|
||||
|
||||
# Add everything before the match
|
||||
result.append(code[pos : match.start()])
|
||||
|
||||
|
|
|
|||
|
|
@ -803,6 +803,8 @@ def run_jest_behavioral_tests(
|
|||
wall_clock_ns = time.perf_counter_ns() - start_time_ns
|
||||
logger.debug(f"Jest behavioral tests completed in {wall_clock_ns / 1e9:.2f}s")
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
return result_file_path, result, coverage_json_path, None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -856,4 +856,121 @@ jest.doMock('../environment', () => ({ isTest: jest.fn() }));
|
|||
test_file = tests_dir / "test.ts"
|
||||
|
||||
assert fix_jest_mock_paths("", test_file, source_file, tests_dir) == ""
|
||||
assert fix_jest_mock_paths(" ", test_file, source_file, tests_dir) == " "
|
||||
assert fix_jest_mock_paths(" ", test_file, source_file, tests_dir) == " "
|
||||
|
||||
|
||||
class TestFunctionCallsInStrings:
|
||||
"""Tests for skipping function calls inside string literals."""
|
||||
|
||||
def test_skip_function_in_test_description_single_quotes(self):
|
||||
"""Test that function calls in single-quoted test descriptions are not transformed."""
|
||||
from codeflash.languages.javascript.instrument import transform_standalone_calls
|
||||
|
||||
func = make_func("fibonacci")
|
||||
code = """
|
||||
test('should compute fibonacci(20) and fibonacci(30) to known values', () => {
|
||||
const result = fibonacci(10);
|
||||
expect(result).toBe(55);
|
||||
});
|
||||
"""
|
||||
transformed, _counter = transform_standalone_calls(code, func, "capture")
|
||||
|
||||
# The function call in the test description should NOT be transformed
|
||||
assert "fibonacci(20)" in transformed
|
||||
assert "fibonacci(30)" in transformed
|
||||
# The actual call should be transformed
|
||||
assert "codeflash.capture('fibonacci'" in transformed
|
||||
|
||||
def test_skip_function_in_test_description_double_quotes(self):
|
||||
"""Test that function calls in double-quoted test descriptions are not transformed."""
|
||||
from codeflash.languages.javascript.instrument import transform_standalone_calls
|
||||
|
||||
func = make_func("fibonacci")
|
||||
code = '''
|
||||
test("should compute fibonacci(20) correctly", () => {
|
||||
const result = fibonacci(10);
|
||||
});
|
||||
'''
|
||||
transformed, _counter = transform_standalone_calls(code, func, "capture")
|
||||
|
||||
# The function call in the test description should NOT be transformed
|
||||
assert 'fibonacci(20)' in transformed
|
||||
# The actual call should be transformed
|
||||
assert "codeflash.capture('fibonacci'" in transformed
|
||||
|
||||
def test_skip_function_in_template_literal(self):
|
||||
"""Test that function calls in template literals are not transformed."""
|
||||
from codeflash.languages.javascript.instrument import transform_standalone_calls
|
||||
|
||||
func = make_func("fibonacci")
|
||||
code = """
|
||||
test(`should compute fibonacci(20) correctly`, () => {
|
||||
const result = fibonacci(10);
|
||||
});
|
||||
"""
|
||||
transformed, _counter = transform_standalone_calls(code, func, "capture")
|
||||
|
||||
# The function call in the template literal should NOT be transformed
|
||||
assert "fibonacci(20)" in transformed
|
||||
# The actual call should be transformed
|
||||
assert "codeflash.capture('fibonacci'" in transformed
|
||||
|
||||
def test_skip_expect_in_string_literal(self):
|
||||
"""Test that expect(func()) in string literals is not transformed."""
|
||||
from codeflash.languages.javascript.instrument import transform_expect_calls
|
||||
|
||||
func = make_func("fibonacci")
|
||||
code = """
|
||||
describe('testing expect(fibonacci(n)) patterns', () => {
|
||||
test('works', () => {
|
||||
expect(fibonacci(10)).toBe(55);
|
||||
});
|
||||
});
|
||||
"""
|
||||
transformed, _counter = transform_expect_calls(code, func, "capture")
|
||||
|
||||
# The expect in the describe string should NOT be transformed
|
||||
assert "expect(fibonacci(n))" in transformed
|
||||
# The actual expect call should be transformed
|
||||
assert "codeflash.capture('fibonacci'" in transformed
|
||||
|
||||
def test_handle_escaped_quotes_in_string(self):
|
||||
"""Test that escaped quotes in strings are handled correctly."""
|
||||
from codeflash.languages.javascript.instrument import transform_standalone_calls
|
||||
|
||||
func = make_func("fibonacci")
|
||||
code = """
|
||||
test('test \\'fibonacci(5)\\' escaping', () => {
|
||||
const result = fibonacci(10);
|
||||
});
|
||||
"""
|
||||
transformed, _counter = transform_standalone_calls(code, func, "capture")
|
||||
|
||||
# The function call in the escaped string should NOT be transformed
|
||||
assert "fibonacci(5)" in transformed
|
||||
# The actual call should be transformed
|
||||
assert "codeflash.capture('fibonacci'" in transformed
|
||||
|
||||
def test_is_inside_string_helper(self):
|
||||
"""Test the is_inside_string helper function directly."""
|
||||
from codeflash.languages.javascript.instrument import is_inside_string
|
||||
|
||||
# Position inside single-quoted string
|
||||
code1 = "test('fibonacci(5)', () => {})"
|
||||
assert is_inside_string(code1, 10) is True # Inside the string
|
||||
|
||||
# Position outside string
|
||||
assert is_inside_string(code1, 0) is False # Before string
|
||||
assert is_inside_string(code1, 25) is False # After string
|
||||
|
||||
# Double quotes
|
||||
code2 = 'test("fibonacci(5)", () => {})'
|
||||
assert is_inside_string(code2, 10) is True
|
||||
|
||||
# Template literal
|
||||
code3 = "test(`fibonacci(5)`, () => {})"
|
||||
assert is_inside_string(code3, 10) is True
|
||||
|
||||
# Escaped quote doesn't end string
|
||||
code4 = "test('fib\\'s result', () => {})"
|
||||
assert is_inside_string(code4, 15) is True # Still inside after escaped quote
|
||||
Loading…
Reference in a new issue