mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
265 lines
7.7 KiB
Python
265 lines
7.7 KiB
Python
|
|
"""Tests for JavaScript optimizer module.
|
||
|
|
|
||
|
|
Tests the code extraction and normalization functions without importing
|
||
|
|
the full optimizer module (to avoid LLM dependencies in tests).
|
||
|
|
"""
|
||
|
|
|
||
|
|
import re
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
|
||
|
|
# Pattern to extract code blocks from LLM response (copied from optimizer_javascript.py)
|
||
|
|
JS_CODE_PATTERN = re.compile(
|
||
|
|
r"```(?:javascript|js|typescript|ts)(?::[^\n]*)?\s*\n(.*?)```",
|
||
|
|
re.MULTILINE | re.DOTALL,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def extract_code_and_explanation(content: str) -> tuple[str, str]:
|
||
|
|
"""Extract code and explanation from LLM response."""
|
||
|
|
match = JS_CODE_PATTERN.search(content)
|
||
|
|
if match:
|
||
|
|
code = match.group(1).strip()
|
||
|
|
explanation_end = match.start()
|
||
|
|
explanation = content[:explanation_end].strip()
|
||
|
|
return code, explanation
|
||
|
|
return "", content
|
||
|
|
|
||
|
|
|
||
|
|
def _normalize_code(code: str) -> str:
|
||
|
|
"""Normalize code for comparison."""
|
||
|
|
# Remove single-line comments
|
||
|
|
code = re.sub(r"//.*$", "", code, flags=re.MULTILINE)
|
||
|
|
# Remove multi-line comments
|
||
|
|
code = re.sub(r"/\*.*?\*/", "", code, flags=re.DOTALL)
|
||
|
|
# Normalize whitespace
|
||
|
|
code = " ".join(code.split())
|
||
|
|
return code
|
||
|
|
|
||
|
|
|
||
|
|
class TestExtractCodeAndExplanation:
|
||
|
|
"""Tests for extracting code and explanation from LLM responses."""
|
||
|
|
|
||
|
|
def test_extract_javascript_code_block(self) -> None:
|
||
|
|
"""Test extracting code from a JavaScript code block."""
|
||
|
|
response = """**Optimization Explanation:**
|
||
|
|
I replaced the O(n²) nested loop with a more efficient Map-based lookup.
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
function findDuplicates(arr) {
|
||
|
|
const seen = new Map();
|
||
|
|
const duplicates = [];
|
||
|
|
for (const item of arr) {
|
||
|
|
if (seen.has(item)) {
|
||
|
|
duplicates.push(item);
|
||
|
|
}
|
||
|
|
seen.set(item, true);
|
||
|
|
}
|
||
|
|
return duplicates;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "function findDuplicates" in code
|
||
|
|
assert "new Map()" in code
|
||
|
|
assert "O(n²)" in explanation or "Map-based" in explanation
|
||
|
|
|
||
|
|
def test_extract_js_code_block(self) -> None:
|
||
|
|
"""Test extracting code from a ```js code block."""
|
||
|
|
response = """Here's the optimized version:
|
||
|
|
|
||
|
|
```js
|
||
|
|
const add = (a, b) => a + b;
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "const add" in code
|
||
|
|
assert "=>" in code
|
||
|
|
|
||
|
|
def test_extract_typescript_code_block(self) -> None:
|
||
|
|
"""Test extracting code from a TypeScript code block."""
|
||
|
|
response = """Optimized with types:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
function add(a: number, b: number): number {
|
||
|
|
return a + b;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "function add" in code
|
||
|
|
assert ": number" in code
|
||
|
|
|
||
|
|
def test_extract_ts_code_block(self) -> None:
|
||
|
|
"""Test extracting code from a ```ts code block."""
|
||
|
|
response = """```ts
|
||
|
|
const multiply = (a: number, b: number): number => a * b;
|
||
|
|
```"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "multiply" in code
|
||
|
|
assert ": number" in code
|
||
|
|
|
||
|
|
def test_extract_with_filename(self) -> None:
|
||
|
|
"""Test extracting code from a code block with filename."""
|
||
|
|
response = """Here's the optimized code:
|
||
|
|
|
||
|
|
```javascript:utils.js
|
||
|
|
export function fibonacci(n) {
|
||
|
|
if (n <= 1) return n;
|
||
|
|
let a = 0, b = 1;
|
||
|
|
for (let i = 2; i <= n; i++) {
|
||
|
|
[a, b] = [b, a + b];
|
||
|
|
}
|
||
|
|
return b;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "function fibonacci" in code
|
||
|
|
assert "export" in code
|
||
|
|
|
||
|
|
def test_no_code_block_returns_empty(self) -> None:
|
||
|
|
"""Test that missing code block returns empty code."""
|
||
|
|
response = "This response has no code block, just explanation."
|
||
|
|
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert code == ""
|
||
|
|
assert len(explanation) > 0
|
||
|
|
|
||
|
|
def test_multiple_code_blocks_takes_first(self) -> None:
|
||
|
|
"""Test that only the first code block is extracted."""
|
||
|
|
response = """First version:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
function first() { return 1; }
|
||
|
|
```
|
||
|
|
|
||
|
|
Alternative version:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
function second() { return 2; }
|
||
|
|
```
|
||
|
|
"""
|
||
|
|
code, explanation = extract_code_and_explanation(response)
|
||
|
|
|
||
|
|
assert "first" in code
|
||
|
|
assert "second" not in code
|
||
|
|
|
||
|
|
|
||
|
|
class TestNormalizeCode:
|
||
|
|
"""Tests for code normalization for comparison."""
|
||
|
|
|
||
|
|
def test_normalize_removes_single_line_comments(self) -> None:
|
||
|
|
"""Test that single-line comments are removed."""
|
||
|
|
code = """
|
||
|
|
function add(a, b) {
|
||
|
|
// This is a comment
|
||
|
|
return a + b; // inline comment
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
normalized = _normalize_code(code)
|
||
|
|
|
||
|
|
assert "//" not in normalized
|
||
|
|
assert "This is a comment" not in normalized
|
||
|
|
assert "inline comment" not in normalized
|
||
|
|
|
||
|
|
def test_normalize_removes_multiline_comments(self) -> None:
|
||
|
|
"""Test that multi-line comments are removed."""
|
||
|
|
code = """
|
||
|
|
/* This is a
|
||
|
|
multi-line comment */
|
||
|
|
function add(a, b) {
|
||
|
|
return a + b;
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
normalized = _normalize_code(code)
|
||
|
|
|
||
|
|
assert "/*" not in normalized
|
||
|
|
assert "*/" not in normalized
|
||
|
|
assert "multi-line" not in normalized
|
||
|
|
|
||
|
|
def test_normalize_whitespace(self) -> None:
|
||
|
|
"""Test that whitespace is normalized."""
|
||
|
|
code1 = """
|
||
|
|
function add(a, b) {
|
||
|
|
return a + b;
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
code2 = "function add(a, b) { return a + b; }"
|
||
|
|
|
||
|
|
assert _normalize_code(code1) == _normalize_code(code2)
|
||
|
|
|
||
|
|
def test_identical_code_normalizes_same(self) -> None:
|
||
|
|
"""Test that identical code normalizes to the same string."""
|
||
|
|
code1 = "function add(a, b) { return a + b; }"
|
||
|
|
code2 = "function add(a, b) { return a + b; }"
|
||
|
|
|
||
|
|
assert _normalize_code(code1) == _normalize_code(code2)
|
||
|
|
|
||
|
|
def test_different_code_normalizes_different(self) -> None:
|
||
|
|
"""Test that different code normalizes to different strings."""
|
||
|
|
code1 = "function add(a, b) { return a + b; }"
|
||
|
|
code2 = "function subtract(a, b) { return a - b; }"
|
||
|
|
|
||
|
|
assert _normalize_code(code1) != _normalize_code(code2)
|
||
|
|
|
||
|
|
def test_normalize_preserves_string_contents(self) -> None:
|
||
|
|
"""Test that string contents are preserved."""
|
||
|
|
code = 'const msg = "Hello // not a comment";'
|
||
|
|
normalized = _normalize_code(code)
|
||
|
|
|
||
|
|
# The string content should be preserved
|
||
|
|
# (though this is a simplified test - real implementation
|
||
|
|
# might handle this differently)
|
||
|
|
assert "Hello" in normalized
|
||
|
|
|
||
|
|
def test_normalize_empty_code(self) -> None:
|
||
|
|
"""Test that empty code normalizes to empty string."""
|
||
|
|
assert _normalize_code("") == ""
|
||
|
|
assert _normalize_code(" ") == ""
|
||
|
|
assert _normalize_code("\n\n\n") == ""
|
||
|
|
|
||
|
|
|
||
|
|
class TestCodeDeduplication:
|
||
|
|
"""Tests for code deduplication logic."""
|
||
|
|
|
||
|
|
def test_same_code_different_comments_equal(self) -> None:
|
||
|
|
"""Test that same code with different comments is considered equal."""
|
||
|
|
code1 = """
|
||
|
|
// Version 1
|
||
|
|
function add(a, b) {
|
||
|
|
return a + b;
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
code2 = """
|
||
|
|
// Version 2 - optimized
|
||
|
|
function add(a, b) {
|
||
|
|
return a + b; // sum
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
assert _normalize_code(code1) == _normalize_code(code2)
|
||
|
|
|
||
|
|
def test_same_code_different_whitespace_equal(self) -> None:
|
||
|
|
"""Test that same code with different whitespace is considered equal."""
|
||
|
|
code1 = "function add(a, b) { return a + b; }"
|
||
|
|
code2 = """
|
||
|
|
function add(a, b) {
|
||
|
|
return a + b;
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
assert _normalize_code(code1) == _normalize_code(code2)
|
||
|
|
|
||
|
|
def test_semantically_different_code_not_equal(self) -> None:
|
||
|
|
"""Test that semantically different code is not equal."""
|
||
|
|
code1 = "function add(a, b) { return a + b; }"
|
||
|
|
code2 = "function add(a, b) { return a - b; }" # Different operation
|
||
|
|
|
||
|
|
assert _normalize_code(code1) != _normalize_code(code2)
|