← vibesdk
worker/agents/output-formats/diff-formats/udiff.test.ts
7.3 KB
Download file
import { describe, it, expect } from 'vitest';
import { applyDiff } from './udiff';
describe('applyUnifiedDiff', () => {
const applyUnifiedDiff = applyDiff; // Alias for compatibility
it('should apply a simple addition', () => {
const original = `line 1
line 2
line 3`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,4 @@
line 1
line 2
+inserted line
line 3`;
const expected = `line 1
line 2
inserted line
line 3`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should apply a simple deletion', () => {
const original = `line 1
line 2
line 3
line 4`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -1,4 +1,3 @@
line 1
-line 2
line 3
line 4`;
const expected = `line 1
line 3
line 4`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should apply a modification', () => {
const original = `function hello() {
console.log('Hello');
}`;
const diff = `--- a/file.js
+++ b/file.js
@@ -1,3 +1,3 @@
function hello() {
- console.log('Hello');
+ console.log('Hello World');
}`;
const expected = `function hello() {
console.log('Hello World');
}`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should apply multiple hunks', () => {
const original = `function a() {
return 1;
}
function b() {
return 2;
}
function c() {
return 3;
}`;
const diff = `--- a/file.js
+++ b/file.js
@@ -1,3 +1,3 @@
function a() {
- return 1;
+ return 10;
}
@@ -7,3 +7,3 @@
function c() {
- return 3;
+ return 30;
}`;
const expected = `function a() {
return 10;
}
function b() {
return 2;
}
function c() {
return 30;
}`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it.skip('should handle additions at the beginning', () => {
const original = `first line
second line`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -0,0 +1,2 @@
+new first line
+new second line
@@ -1,2 +3,2 @@
first line
second line`;
const expected = `new first line
new second line
first line
second line`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should handle additions at the end', () => {
const original = `first line
second line`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -1,2 +1,4 @@
first line
second line
+third line
+fourth line`;
const expected = `first line
second line
third line
fourth line`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should handle empty original file', () => {
const original = '';
const diff = `--- a/file.txt
+++ b/file.txt
@@ -0,0 +1,3 @@
+line 1
+line 2
+line 3`;
// Note: Implementation adds a leading newline for empty files
const expected = `
line 1
line 2
line 3`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should handle complete file replacement', () => {
const original = `old content
that will be
completely replaced`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,2 @@
-old content
-that will be
-completely replaced
+brand new content
+with different structure`;
const expected = `brand new content
with different structure`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should preserve whitespace and indentation', () => {
const original = `def function():
if True:
print("indented")
return None`;
const diff = `--- a/file.py
+++ b/file.py
@@ -1,4 +1,5 @@
def function():
if True:
print("indented")
+ print("another indented line")
return None`;
const expected = `def function():
if True:
print("indented")
print("another indented line")
return None`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should handle Windows line endings', () => {
const original = 'line 1\r\nline 2\r\nline 3';
const diff = `--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,3 @@
line 1
-line 2
+modified line 2
line 3`;
const expected = 'line 1\r\nmodified line 2\r\nline 3';
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should handle context lines correctly', () => {
const original = `a
b
c
d
e
f
g`;
const diff = `--- a/file.txt
+++ b/file.txt
@@ -2,5 +2,5 @@ a
b
c
-d
+D modified
e
f`;
const expected = `a
b
c
D modified
e
f
g`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('should throw error for invalid diff format', () => {
const original = 'some content';
const invalidDiff = 'this is not a valid diff';
// Resilient parser returns original content for invalid diffs
// Note: Implementation adds a trailing newline (standard file convention)
const result = applyUnifiedDiff(original, invalidDiff);
expect(result).toBe(original + '\n');
});
it('should handle diffs with no changes', () => {
const original = `unchanged content
stays the same`;
const diff = `--- a/file.txt
+++ b/file.txt`;
// Note: Implementation adds a trailing newline
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(original + '\n');
});
it('should apply complex real-world diff', () => {
const original = `export class MyClass {
constructor() {
this.value = 0;
}
increment() {
this.value++;
}
getValue() {
return this.value;
}
}`;
const diff = `--- a/myclass.js
+++ b/myclass.js
@@ -1,8 +1,12 @@
export class MyClass {
- constructor() {
- this.value = 0;
+ constructor(initialValue = 0) {
+ this.value = initialValue;
+ this.history = [initialValue];
}
increment() {
this.value++;
+ this.history.push(this.value);
}
getValue() {
@@ -10,3 +14,7 @@ export class MyClass {
return this.value;
}
+
+ getHistory() {
+ return [...this.history];
+ }
}`;
const expected = `export class MyClass {
constructor(initialValue = 0) {
this.value = initialValue;
this.history = [initialValue];
}
increment() {
this.value++;
this.history.push(this.value);
}
getValue() {
return this.value;
}
getHistory() {
return [...this.history];
}
}`;
const result = applyUnifiedDiff(original, diff);
expect(result).toBe(expected);
});
it('inserts $-sequences in replacement content literally ($&)', () => {
const original = `const a = 1;\nconst label = old;\nconst b = 2;`;
const diff = `@@ ... @@\n const a = 1;\n-const label = old;\n+const label = text.replace(/x/g, '[$&]');\n const b = 2;`;
const expected = `const a = 1;\nconst label = text.replace(/x/g, '[$&]');\nconst b = 2;`;
expect(applyUnifiedDiff(original, diff)).toBe(expected);
});
it('does not collapse $$ in replacement content', () => {
const original = `line1\nTODO\nline3`;
const diff = `@@ ... @@\n line1\n-TODO\n+const price = "$$5";\n line3`;
const expected = `line1\nconst price = "$$5";\nline3`;
expect(applyUnifiedDiff(original, diff)).toBe(expected);
});
});