Files
azuredatastudio/src/vs/editor/test/common/services/modelService.test.ts
Anthony Dresser f5ce7fb2a5 Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)
* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c

* remove files we don't want

* fix hygiene

* update distro

* update distro

* fix hygiene

* fix strict nulls

* distro

* distro

* fix tests

* fix tests

* add another edit

* fix viewlet icon

* fix azure dialog

* fix some padding

* fix more padding issues
2019-12-04 19:28:22 -08:00

386 lines
9.9 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { CharCode } from 'vs/base/common/charCode';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range } from 'vs/editor/common/core/range';
import { createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { DefaultEndOfLine } from 'vs/editor/common/model';
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
const GENERATE_TESTS = false;
suite('ModelService', () => {
let modelService: ModelServiceImpl;
setup(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'eol': '\n' });
configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot'));
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService), new TestThemeService());
});
teardown(() => {
modelService.dispose();
});
test('EOL setting respected depending on root', () => {
const model1 = modelService.createModel('farboo', null);
const model2 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\myroot\\myfile.txt' : '/myroot/myfile.txt'));
const model3 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\other\\myfile.txt' : '/other/myfile.txt'));
assert.equal(model1.getOptions().defaultEOL, DefaultEndOfLine.LF);
assert.equal(model2.getOptions().defaultEOL, DefaultEndOfLine.CRLF);
assert.equal(model3.getOptions().defaultEOL, DefaultEndOfLine.LF);
});
test('_computeEdits no change', function () {
const model = TextModel.createFromString(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n')
);
const textBuffer = createTextBuffer(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n'),
DefaultEndOfLine.LF
);
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, []);
});
test('_computeEdits first line changed', function () {
const model = TextModel.createFromString(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n')
);
const textBuffer = createTextBuffer(
[
'This is line One', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n'),
DefaultEndOfLine.LF
);
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replaceMove(new Range(1, 1, 2, 1), 'This is line One\n')
]);
});
test('_computeEdits EOL changed', function () {
const model = TextModel.createFromString(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n')
);
const textBuffer = createTextBuffer(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\r\n'),
DefaultEndOfLine.LF
);
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, []);
});
test('_computeEdits EOL and other change 1', function () {
const model = TextModel.createFromString(
[
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
'and finished with the fourth.', //29
].join('\n')
);
const textBuffer = createTextBuffer(
[
'This is line One', //16
'and this is line number two', //27
'It is followed by #3', //20
'and finished with the fourth.', //29
].join('\r\n'),
DefaultEndOfLine.LF
);
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replaceMove(
new Range(1, 1, 4, 1),
[
'This is line One',
'and this is line number two',
'It is followed by #3',
''
].join('\r\n')
)
]);
});
test('_computeEdits EOL and other change 2', function () {
const model = TextModel.createFromString(
[
'package main', // 1
'func foo() {', // 2
'}' // 3
].join('\n')
);
const textBuffer = createTextBuffer(
[
'package main', // 1
'func foo() {', // 2
'}', // 3
''
].join('\r\n'),
DefaultEndOfLine.LF
);
const actual = ModelServiceImpl._computeEdits(model, textBuffer);
assert.deepEqual(actual, [
EditOperation.replaceMove(new Range(3, 2, 3, 2), '\r\n')
]);
});
test('generated1', () => {
const file1 = ['pram', 'okctibad', 'pjuwtemued', 'knnnm', 'u', ''];
const file2 = ['tcnr', 'rxwlicro', 'vnzy', '', '', 'pjzcogzur', 'ptmxyp', 'dfyshia', 'pee', 'ygg'];
assertComputeEdits(file1, file2);
});
test('generated2', () => {
const file1 = ['', 'itls', 'hrilyhesv', ''];
const file2 = ['vdl', '', 'tchgz', 'bhx', 'nyl'];
assertComputeEdits(file1, file2);
});
test('generated3', () => {
const file1 = ['ubrbrcv', 'wv', 'xodspybszt', 's', 'wednjxm', 'fklajt', 'fyfc', 'lvejgge', 'rtpjlodmmk', 'arivtgmjdm'];
const file2 = ['s', 'qj', 'tu', 'ur', 'qerhjjhyvx', 't'];
assertComputeEdits(file1, file2);
});
test('generated4', () => {
const file1 = ['ig', 'kh', 'hxegci', 'smvker', 'pkdmjjdqnv', 'vgkkqqx', '', 'jrzeb'];
const file2 = ['yk', ''];
assertComputeEdits(file1, file2);
});
test('does insertions in the middle of the document', () => {
const file1 = [
'line 1',
'line 2',
'line 3'
];
const file2 = [
'line 1',
'line 2',
'line 5',
'line 3'
];
assertComputeEdits(file1, file2);
});
test('does insertions at the end of the document', () => {
const file1 = [
'line 1',
'line 2',
'line 3'
];
const file2 = [
'line 1',
'line 2',
'line 3',
'line 4'
];
assertComputeEdits(file1, file2);
});
test('does insertions at the beginning of the document', () => {
const file1 = [
'line 1',
'line 2',
'line 3'
];
const file2 = [
'line 0',
'line 1',
'line 2',
'line 3'
];
assertComputeEdits(file1, file2);
});
test('does replacements', () => {
const file1 = [
'line 1',
'line 2',
'line 3'
];
const file2 = [
'line 1',
'line 7',
'line 3'
];
assertComputeEdits(file1, file2);
});
test('does deletions', () => {
const file1 = [
'line 1',
'line 2',
'line 3'
];
const file2 = [
'line 1',
'line 3'
];
assertComputeEdits(file1, file2);
});
test('does insert, replace, and delete', () => {
const file1 = [
'line 1',
'line 2',
'line 3',
'line 4',
'line 5',
];
const file2 = [
'line 0', // insert line 0
'line 1',
'replace line 2', // replace line 2
'line 3',
// delete line 4
'line 5',
];
assertComputeEdits(file1, file2);
});
});
function assertComputeEdits(lines1: string[], lines2: string[]): void {
const model = TextModel.createFromString(lines1.join('\n'));
const textBuffer = createTextBuffer(lines2.join('\n'), DefaultEndOfLine.LF);
// compute required edits
// let start = Date.now();
const edits = ModelServiceImpl._computeEdits(model, textBuffer);
// console.log(`took ${Date.now() - start} ms.`);
// apply edits
model.pushEditOperations([], edits, null);
assert.equal(model.getValue(), lines2.join('\n'));
}
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getRandomString(minLength: number, maxLength: number): string {
let length = getRandomInt(minLength, maxLength);
let t = createStringBuilder(length);
for (let i = 0; i < length; i++) {
t.appendASCII(getRandomInt(CharCode.a, CharCode.z));
}
return t.build();
}
function generateFile(small: boolean): string[] {
let lineCount = getRandomInt(1, small ? 3 : 10000);
let lines: string[] = [];
for (let i = 0; i < lineCount; i++) {
lines.push(getRandomString(0, small ? 3 : 10000));
}
return lines;
}
if (GENERATE_TESTS) {
let number = 1;
while (true) {
console.log('------TEST: ' + number++);
const file1 = generateFile(true);
const file2 = generateFile(true);
console.log('------TEST GENERATED');
try {
assertComputeEdits(file1, file2);
} catch (err) {
console.log(err);
console.log(`
const file1 = ${JSON.stringify(file1).replace(/"/g, '\'')};
const file2 = ${JSON.stringify(file2).replace(/"/g, '\'')};
assertComputeEdits(file1, file2);
`);
break;
}
}
}
export class TestTextResourcePropertiesService implements ITextResourcePropertiesService {
_serviceBrand: undefined;
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
}
getEOL(resource: URI, language?: string): string {
const eol = this.configurationService.getValue<string>('files.eol', { overrideIdentifier: language, resource });
if (eol && eol !== 'auto') {
return eol;
}
return (platform.isLinux || platform.isMacintosh) ? '\n' : '\r\n';
}
}