Skip to content

Commit 845706c

Browse files
committed
Fixes bug in diffing algorithm & improves fixture testing method.
1 parent c5057ee commit 845706c

File tree

64 files changed

+213
-202
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+213
-202
lines changed

src/vs/editor/common/diff/algorithms/joinSequenceDiffs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ export function shiftSequenceDiffs(sequence1: ISequence, sequence2: ISequence, s
8585
const diff = sequenceDiffs[i];
8686
if (diff.seq1Range.isEmpty) {
8787
const seq2PrevEndExclusive = (i > 0 ? sequenceDiffs[i - 1].seq2Range.endExclusive : -1);
88-
const seq2NextStart = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1].seq2Range.start : sequence2.length + 1);
88+
const seq2NextStart = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1].seq2Range.start : sequence2.length);
8989
sequenceDiffs[i] = shiftDiffToBetterPosition(diff, sequence1, sequence2, seq2NextStart, seq2PrevEndExclusive);
9090
} else if (diff.seq2Range.isEmpty) {
9191
const seq1PrevEndExclusive = (i > 0 ? sequenceDiffs[i - 1].seq1Range.endExclusive : -1);
92-
const seq1NextStart = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1].seq1Range.start : sequence1.length + 1);
92+
const seq1NextStart = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1].seq1Range.start : sequence1.length);
9393
sequenceDiffs[i] = shiftDiffToBetterPosition(diff.reverse(), sequence2, sequence1, seq1NextStart, seq1PrevEndExclusive).reverse();
9494
}
9595
}
@@ -102,15 +102,15 @@ function shiftDiffToBetterPosition(diff: SequenceDiff, sequence1: ISequence, seq
102102

103103
// don't touch previous or next!
104104
let deltaBefore = 1;
105-
while (diff.seq1Range.start - deltaBefore > seq2PrevEndExclusive &&
105+
while (diff.seq2Range.start - deltaBefore > seq2PrevEndExclusive &&
106106
sequence2.getElement(diff.seq2Range.start - deltaBefore) ===
107107
sequence2.getElement(diff.seq2Range.endExclusive - deltaBefore) && deltaBefore < maxShiftLimit) {
108108
deltaBefore++;
109109
}
110110
deltaBefore--;
111111

112112
let deltaAfter = 1;
113-
while (diff.seq1Range.start + deltaAfter < seq2NextStart &&
113+
while (diff.seq2Range.start + deltaAfter < seq2NextStart &&
114114
sequence2.getElement(diff.seq2Range.start + deltaAfter) ===
115115
sequence2.getElement(diff.seq2Range.endExclusive + deltaAfter) && deltaAfter < maxShiftLimit) {
116116
deltaAfter++;

src/vs/editor/test/node/diffing/diffing.test.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@
55

66
import assert = require('assert');
77
import { readdirSync, readFileSync, existsSync, writeFileSync } from 'fs';
8-
import { join } from 'path';
8+
import { join, resolve } from 'path';
99
import { FileAccess } from 'vs/base/common/network';
1010
import { SmartLinesDiffComputer } from 'vs/editor/common/diff/smartLinesDiffComputer';
1111
import { StandardLinesDiffComputer } from 'vs/editor/common/diff/standardLinesDiffComputer';
1212

1313
suite('diff fixtures', () => {
14-
const fixturesDir = FileAccess.asFileUri('vs/editor/test/node/diffing/fixtures').fsPath;
15-
const folders = readdirSync(fixturesDir);
14+
const fixturesOutDir = FileAccess.asFileUri('vs/editor/test/node/diffing/fixtures').fsPath;
15+
// We want the dir in src, so we can directly update the source files if they disagree and create invalid files to capture the previous state.
16+
// This makes it very easy to update the fixtures.
17+
const fixturesSrcDir = resolve(fixturesOutDir).replaceAll('\\', '/').replace('/out/vs/editor/', '/src/vs/editor/');
18+
const folders = readdirSync(fixturesSrcDir);
1619

1720
for (const folder of folders) {
1821
for (const diffingAlgoName of ['smart', 'experimental']) {
19-
2022
test(`${folder}-${diffingAlgoName}`, () => {
21-
const folderPath = join(fixturesDir, folder);
23+
const folderPath = join(fixturesSrcDir, folder);
2224
const files = readdirSync(folderPath);
2325

2426
const firstFileName = files.find(f => f.startsWith('1.'))!;
@@ -31,7 +33,7 @@ suite('diff fixtures', () => {
3133

3234
const diff = diffingAlgo.computeDiff(firstContentLines, secondContentLines, { ignoreTrimWhitespace: false, maxComputationTime: Number.MAX_SAFE_INTEGER });
3335

34-
const diffingResult: DiffingResult = {
36+
const actualDiffingResult: DiffingResult = {
3537
originalFileName: `./${firstFileName}`,
3638
modifiedFileName: `./${secondFileName}`,
3739
diffs: diff.changes.map<IDetailedDiff>(c => ({
@@ -44,29 +46,34 @@ suite('diff fixtures', () => {
4446
}))
4547
};
4648

47-
const actualFilePath = join(folderPath, `${diffingAlgoName}.actual.diff.json`);
4849
const expectedFilePath = join(folderPath, `${diffingAlgoName}.expected.diff.json`);
50+
const invalidFilePath = join(folderPath, `${diffingAlgoName}.invalid.diff.json`);
51+
52+
const expectedFileContentFromActual = JSON.stringify(actualDiffingResult, null, '\t');
4953

50-
const expectedFileContent = JSON.stringify(diffingResult, null, '\t');
54+
const invalidExists = existsSync(invalidFilePath);
5155

52-
if (!existsSync(actualFilePath)) {
53-
writeFileSync(actualFilePath, expectedFileContent);
54-
writeFileSync(expectedFilePath, expectedFileContent);
55-
throw new Error('No actual file! Actual and expected files were written.');
56+
if (!existsSync(expectedFilePath)) {
57+
writeFileSync(expectedFilePath, expectedFileContentFromActual);
58+
writeFileSync(invalidFilePath, '');
59+
throw new Error('No expected file! Expected and invalid files were written. Delete the invalid file to make the test pass.');
5660
} else {
57-
const actualFileContent = readFileSync(actualFilePath, 'utf8');
58-
const actualFileDiffResult: DiffingResult = JSON.parse(actualFileContent);
61+
const expectedFileContent = readFileSync(invalidExists ? invalidFilePath : expectedFilePath, 'utf8');
62+
const expectedFileDiffResult: DiffingResult = JSON.parse(expectedFileContent);
5963

6064
try {
61-
assert.deepStrictEqual(actualFileDiffResult, diffingResult);
65+
assert.deepStrictEqual(actualDiffingResult, expectedFileDiffResult);
6266
} catch (e) {
63-
writeFileSync(expectedFilePath, expectedFileContent);
67+
if (!invalidExists) {
68+
writeFileSync(invalidFilePath, expectedFileContent);
69+
}
70+
writeFileSync(expectedFilePath, expectedFileContentFromActual);
6471
throw e;
6572
}
6673
}
6774

68-
if (existsSync(expectedFilePath)) {
69-
throw new Error('Expected file exists! Please delete it.');
75+
if (invalidExists) {
76+
throw new Error('Invalid file exists and agrees with expected file! Delete the invalid file to make the test pass.');
7077
}
7178
});
7279
}

src/vs/editor/test/node/diffing/fixtures/bracket-aligning/experimental.actual.diff.json renamed to src/vs/editor/test/node/diffing/fixtures/bracket-aligning/experimental.expected.diff.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
]
6262
},
6363
{
64-
"originalRange": "[86,95)",
65-
"modifiedRange": "[88,98)",
64+
"originalRange": "[86,98)",
65+
"modifiedRange": "[88,101)",
6666
"innerChanges": [
6767
{
6868
"originalRange": "[86,1 -> 86,1]",
@@ -102,9 +102,21 @@
102102
},
103103
{
104104
"originalRange": "[95,1 -> 95,1]",
105-
"modifiedRange": "[97,1 -> 98,1]"
105+
"modifiedRange": "[97,1 -> 97,2]"
106+
},
107+
{
108+
"originalRange": "[96,1 -> 96,1]",
109+
"modifiedRange": "[98,1 -> 98,2]"
110+
},
111+
{
112+
"originalRange": "[97,1 -> 97,1]",
113+
"modifiedRange": "[99,1 -> 99,2]"
114+
},
115+
{
116+
"originalRange": "[98,1 -> 98,1]",
117+
"modifiedRange": "[100,1 -> 101,1]"
106118
}
107119
]
108120
}
109121
]
110-
}
122+
}

src/vs/editor/test/node/diffing/fixtures/bracket-aligning/smart.actual.diff.json renamed to src/vs/editor/test/node/diffing/fixtures/bracket-aligning/smart.expected.diff.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
"innerChanges": null
1414
}
1515
]
16-
}
16+
}

src/vs/editor/test/node/diffing/fixtures/indentation/experimental.actual.diff.json renamed to src/vs/editor/test/node/diffing/fixtures/indentation/experimental.expected.diff.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,4 @@
7575
]
7676
}
7777
]
78-
}
78+
}

src/vs/editor/test/node/diffing/fixtures/indentation/smart.actual.diff.json renamed to src/vs/editor/test/node/diffing/fixtures/indentation/smart.expected.diff.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
"innerChanges": null
1414
}
1515
]
16-
}
16+
}

0 commit comments

Comments
 (0)