259 lines
8.8 KiB
TypeScript
259 lines
8.8 KiB
TypeScript
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
import * as smartdiff from '../ts/index.js';
|
|
|
|
// =============================================================================
|
|
// Backward Compatibility Tests
|
|
// =============================================================================
|
|
|
|
tap.test('createDiff and applyPatch should work (backward compatible)', async () => {
|
|
const text1 = 'hi there';
|
|
const text2 = 'hi Polly, there is a Sandwich.';
|
|
const patch = smartdiff.createDiff(text1, text2);
|
|
console.log('Compact diff:', patch);
|
|
const result = smartdiff.applyPatch(text1, patch);
|
|
console.log('Reconstructed:', result);
|
|
expect(result).toEqual(text2);
|
|
});
|
|
|
|
tap.test('createDiff should produce compact format', async () => {
|
|
const original = 'Hello World';
|
|
const revised = 'Hello smart World';
|
|
const diff = smartdiff.createDiff(original, revised);
|
|
const parsed = JSON.parse(diff);
|
|
|
|
// Should be array of tuples
|
|
expect(Array.isArray(parsed)).toBeTrue();
|
|
|
|
// Each tuple should have operation and value
|
|
for (const item of parsed) {
|
|
expect(Array.isArray(item)).toBeTrue();
|
|
expect(item.length).toEqual(2);
|
|
expect([-1, 0, 1]).toContain(item[0]);
|
|
}
|
|
});
|
|
|
|
// =============================================================================
|
|
// Character Diff Tests
|
|
// =============================================================================
|
|
|
|
tap.test('getCharDiff should return character-level diff segments', async () => {
|
|
const original = 'hello';
|
|
const revised = 'hallo';
|
|
const segments = smartdiff.getCharDiff(original, revised);
|
|
|
|
expect(Array.isArray(segments)).toBeTrue();
|
|
expect(segments.length).toBeGreaterThan(0);
|
|
|
|
// Each segment should have type and value
|
|
for (const segment of segments) {
|
|
expect(['equal', 'insert', 'delete']).toContain(segment.type);
|
|
expect(typeof segment.value).toEqual('string');
|
|
}
|
|
|
|
// Should detect the 'e' -> 'a' change
|
|
const deleteSegment = segments.find(s => s.type === 'delete');
|
|
const insertSegment = segments.find(s => s.type === 'insert');
|
|
expect(deleteSegment).toBeDefined();
|
|
expect(insertSegment).toBeDefined();
|
|
});
|
|
|
|
tap.test('formatCharDiffForConsole should produce ANSI colored output', async () => {
|
|
const original = 'hello world';
|
|
const revised = 'hello beautiful world';
|
|
const output = smartdiff.formatCharDiffForConsole(original, revised);
|
|
|
|
console.log('Char diff console output:', output);
|
|
|
|
// Should contain ANSI codes
|
|
expect(output).toInclude('\x1b[');
|
|
// Should contain the unchanged parts
|
|
expect(output).toInclude('hello');
|
|
expect(output).toInclude('world');
|
|
});
|
|
|
|
tap.test('formatCharDiffAsHtml should produce HTML spans', async () => {
|
|
const original = 'hello';
|
|
const revised = 'hallo';
|
|
const html = smartdiff.formatCharDiffAsHtml(original, revised);
|
|
|
|
console.log('Char diff HTML:', html);
|
|
|
|
expect(html).toInclude('<span class="smartdiff-');
|
|
expect(html).toInclude('smartdiff-delete');
|
|
expect(html).toInclude('smartdiff-insert');
|
|
});
|
|
|
|
// =============================================================================
|
|
// Word Diff Tests
|
|
// =============================================================================
|
|
|
|
tap.test('getWordDiff should return word-level diff segments', async () => {
|
|
const original = 'The quick brown fox';
|
|
const revised = 'The slow brown dog';
|
|
const segments = smartdiff.getWordDiff(original, revised);
|
|
|
|
console.log('Word diff segments:', segments);
|
|
|
|
expect(Array.isArray(segments)).toBeTrue();
|
|
|
|
// Should detect word changes
|
|
const hasDelete = segments.some(s => s.type === 'delete');
|
|
const hasInsert = segments.some(s => s.type === 'insert');
|
|
expect(hasDelete).toBeTrue();
|
|
expect(hasInsert).toBeTrue();
|
|
});
|
|
|
|
tap.test('formatWordDiffForConsole should produce readable output', async () => {
|
|
const original = 'Hello World';
|
|
const revised = 'Hello Beautiful World';
|
|
const output = smartdiff.formatWordDiffForConsole(original, revised);
|
|
|
|
console.log('Word diff console output:', output);
|
|
|
|
expect(output).toInclude('Hello');
|
|
expect(output).toInclude('World');
|
|
});
|
|
|
|
tap.test('formatWordDiffAsHtml should produce HTML spans', async () => {
|
|
const original = 'one two three';
|
|
const revised = 'one TWO three';
|
|
const html = smartdiff.formatWordDiffAsHtml(original, revised);
|
|
|
|
console.log('Word diff HTML:', html);
|
|
|
|
expect(html).toInclude('<span class="smartdiff-');
|
|
});
|
|
|
|
// =============================================================================
|
|
// Line Diff Tests
|
|
// =============================================================================
|
|
|
|
tap.test('getLineDiff should return line-level diff', async () => {
|
|
const original = 'line1\nline2\nline3';
|
|
const revised = 'line1\nmodified\nline3';
|
|
const lineDiff = smartdiff.getLineDiff(original, revised);
|
|
|
|
console.log('Line diff:', lineDiff);
|
|
|
|
expect(Array.isArray(lineDiff)).toBeTrue();
|
|
|
|
// Should have line numbers and types
|
|
for (const line of lineDiff) {
|
|
expect(typeof line.lineNumber).toEqual('number');
|
|
expect(['equal', 'insert', 'delete']).toContain(line.type);
|
|
expect(typeof line.value).toEqual('string');
|
|
}
|
|
});
|
|
|
|
tap.test('formatLineDiffForConsole should produce unified-style output', async () => {
|
|
const original = 'function hello() {\n console.log("hi");\n}';
|
|
const revised = 'function hello() {\n console.log("hello world");\n}';
|
|
const output = smartdiff.formatLineDiffForConsole(original, revised);
|
|
|
|
console.log('Line diff console output:\n' + output);
|
|
|
|
// Should have +/- prefixes
|
|
expect(output).toInclude('-');
|
|
expect(output).toInclude('+');
|
|
});
|
|
|
|
tap.test('formatLineDiffAsHtml should produce HTML divs', async () => {
|
|
const original = 'a\nb\nc';
|
|
const revised = 'a\nB\nc';
|
|
const html = smartdiff.formatLineDiffAsHtml(original, revised);
|
|
|
|
console.log('Line diff HTML:\n' + html);
|
|
|
|
expect(html).toInclude('<div class="smartdiff-lines">');
|
|
expect(html).toInclude('<div class="smartdiff-line');
|
|
expect(html).toInclude('smartdiff-prefix');
|
|
});
|
|
|
|
// =============================================================================
|
|
// Unified Diff Tests
|
|
// =============================================================================
|
|
|
|
tap.test('createUnifiedDiff should produce git-style unified diff', async () => {
|
|
const original = 'line1\nline2\nline3\nline4\nline5';
|
|
const revised = 'line1\nmodified\nline3\nline4\nline5';
|
|
const unifiedDiff = smartdiff.createUnifiedDiff(original, revised, {
|
|
originalFileName: 'file.txt',
|
|
revisedFileName: 'file.txt',
|
|
});
|
|
|
|
console.log('Unified diff:\n' + unifiedDiff);
|
|
|
|
expect(unifiedDiff).toInclude('---');
|
|
expect(unifiedDiff).toInclude('+++');
|
|
expect(unifiedDiff).toInclude('@@');
|
|
});
|
|
|
|
tap.test('formatUnifiedDiffForConsole should colorize unified diff', async () => {
|
|
const original = 'old content';
|
|
const revised = 'new content';
|
|
const output = smartdiff.formatUnifiedDiffForConsole(original, revised);
|
|
|
|
console.log('Unified diff console:\n' + output);
|
|
|
|
// Should contain ANSI codes
|
|
expect(output).toInclude('\x1b[');
|
|
});
|
|
|
|
// =============================================================================
|
|
// CSS Helper Test
|
|
// =============================================================================
|
|
|
|
tap.test('getDefaultDiffCss should return valid CSS', async () => {
|
|
const css = smartdiff.getDefaultDiffCss();
|
|
|
|
console.log('Default CSS:\n' + css);
|
|
|
|
expect(css).toInclude('.smartdiff-delete');
|
|
expect(css).toInclude('.smartdiff-insert');
|
|
expect(css).toInclude('.smartdiff-equal');
|
|
expect(css).toInclude('background-color');
|
|
});
|
|
|
|
// =============================================================================
|
|
// Edge Cases
|
|
// =============================================================================
|
|
|
|
tap.test('should handle empty strings', async () => {
|
|
const diff1 = smartdiff.createDiff('', 'new');
|
|
const diff2 = smartdiff.createDiff('old', '');
|
|
const diff3 = smartdiff.createDiff('', '');
|
|
|
|
expect(smartdiff.applyPatch('', diff1)).toEqual('new');
|
|
expect(smartdiff.applyPatch('old', diff2)).toEqual('');
|
|
expect(smartdiff.applyPatch('', diff3)).toEqual('');
|
|
});
|
|
|
|
tap.test('should handle identical strings', async () => {
|
|
const text = 'no changes here';
|
|
const diff = smartdiff.createDiff(text, text);
|
|
const result = smartdiff.applyPatch(text, diff);
|
|
|
|
expect(result).toEqual(text);
|
|
|
|
// Visualization should show all equal
|
|
const segments = smartdiff.getCharDiff(text, text);
|
|
expect(segments.every(s => s.type === 'equal')).toBeTrue();
|
|
});
|
|
|
|
tap.test('should escape HTML in output', async () => {
|
|
const original = '<div>test</div>';
|
|
const revised = '<span>test</span>';
|
|
const html = smartdiff.formatCharDiffAsHtml(original, revised);
|
|
|
|
console.log('HTML escaped output:', html);
|
|
|
|
// Should escape < and >
|
|
expect(html).toInclude('<');
|
|
expect(html).toInclude('>');
|
|
// Should not contain raw HTML tags from input
|
|
expect(html).not.toInclude('<div>');
|
|
expect(html).not.toInclude('<span>');
|
|
});
|
|
|
|
export default tap.start();
|