editableTextModelTestUtils.ts 5.4 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

A
Alex Dima 已提交
7 8
import * as assert from 'assert';
import * as editorCommon from 'vs/editor/common/editorCommon';
A
tslint  
Alex Dima 已提交
9
import {EditableTextModel} from 'vs/editor/common/model/editableTextModel';
A
Alex Dima 已提交
10
import {ICompatMirrorModelEvents, CompatMirrorModel} from 'vs/editor/common/model/compatMirrorModel';
11
import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2';
A
Alex Dima 已提交
12
import {TextModel} from 'vs/editor/common/model/textModel';
13
import {Position} from 'vs/editor/common/core/position';
14

15
export function testApplyEditsWithSyncedModels(original:string[], edits:editorCommon.IIdentifiedSingleEditOperation[], expected:string[], inputEditsAreInvalid:boolean = false): void {
16 17 18 19 20 21 22 23
	var originalStr = original.join('\n');
	var expectedStr = expected.join('\n');

	assertSyncedModels(originalStr, (model, assertMirrorModels) => {
		// Apply edits & collect inverse edits
		var inverseEdits = model.applyEdits(edits);

		// Assert edits produced expected result
A
Alex Dima 已提交
24
		assert.deepEqual(model.getValue(editorCommon.EndOfLinePreference.LF), expectedStr);
25 26 27 28 29 30 31

		assertMirrorModels();

		// Apply the inverse edits
		var inverseInverseEdits = model.applyEdits(inverseEdits);

		// Assert the inverse edits brought back model to original state
A
Alex Dima 已提交
32
		assert.deepEqual(model.getValue(editorCommon.EndOfLinePreference.LF), originalStr);
33

34 35 36 37
		if (!inputEditsAreInvalid) {
			// Assert the inverse of the inverse edits are the original edits
			assert.deepEqual(inverseInverseEdits, edits);
		}
38 39 40 41 42

		assertMirrorModels();
	});
}

A
Alex Dima 已提交
43
const enum AssertDocumentLineMappingDirection {
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	OffsetToPosition,
	PositionToOffset
}

function assertOneDirectionLineMapping(model:TextModel, direction:AssertDocumentLineMappingDirection, msg:string): void {
	let allText = model.getValue();

	let line = 1, column = 1, previousIsCarriageReturn = false;
	for (let offset = 0; offset <= allText.length; offset++) {
		// The position coordinate system cannot express the position between \r and \n
		let	position = new Position(line, column + (previousIsCarriageReturn ? -1 : 0));

		if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) {
			let actualPosition = model.getPositionAt(offset);
			assert.equal(actualPosition.toString(), position.toString(), msg + ' - getPositionAt mismatch for offset ' + offset);
		} else {
			// The position coordinate system cannot express the position between \r and \n
			let expectedOffset = offset + (previousIsCarriageReturn ? -1 : 0);
			let actualOffset = model.getOffsetAt(position);
			assert.equal(actualOffset, expectedOffset, msg + ' - getOffsetAt mismatch for position ' + position.toString());
		}

		if (allText.charAt(offset) === '\n') {
			line++;
			column = 1;
		} else {
			column++;
		}

		previousIsCarriageReturn = (allText.charAt(offset) === '\r');
	}
}

function assertLineMapping(model:TextModel, msg:string): void {
	assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.PositionToOffset, msg);
	assertOneDirectionLineMapping(model, AssertDocumentLineMappingDirection.OffsetToPosition, msg);
}


A
Alex Dima 已提交
83
export function assertSyncedModels(text:string, callback:(model:EditableTextModel, assertMirrorModels:()=>void)=>void, setup:(model:EditableTextModel)=>void = null): void {
84
	var model = new EditableTextModel([], TextModel.toRawText(text, TextModel.DEFAULT_CREATION_OPTIONS), null);
A
Alex Dima 已提交
85
	model.setEOL(editorCommon.EndOfLineSequence.LF);
86
	assertLineMapping(model, 'model');
87 88 89

	if (setup) {
		setup(model);
90
		assertLineMapping(model, 'model');
91 92
	}

A
Alex Dima 已提交
93
	var mirrorModel1 = new CompatMirrorModel(model.getVersionId(), model.toRawText(), null);
94
	assertLineMapping(mirrorModel1, 'mirrorModel1');
95 96 97 98 99
	var mirrorModel1PrevVersionId = model.getVersionId();

	var mirrorModel2 = new MirrorModel2(null, model.toRawText().lines, model.toRawText().EOL, model.getVersionId());
	var mirrorModel2PrevVersionId = model.getVersionId();

A
Alex Dima 已提交
100
	model.onDidChangeRawContent((e:editorCommon.IModelContentChangedEvent) => {
101 102 103 104 105
		let versionId = e.versionId;
		if (versionId < mirrorModel1PrevVersionId) {
			console.warn('Model version id did not advance between edits (1)');
		}
		mirrorModel1PrevVersionId = versionId;
A
Alex Dima 已提交
106
		let mirrorModelEvents:ICompatMirrorModelEvents = {
107 108 109 110 111
			contentChanged: [e]
		};
		mirrorModel1.onEvents(mirrorModelEvents);
	});

A
Alex Dima 已提交
112
	model.onDidChangeContent((e:editorCommon.IModelContentChangedEvent2) => {
113 114 115 116 117 118 119 120 121
		let versionId = e.versionId;
		if (versionId < mirrorModel2PrevVersionId) {
			console.warn('Model version id did not advance between edits (2)');
		}
		mirrorModel2PrevVersionId = versionId;
		mirrorModel2.onEvents([e]);
	});

	var assertMirrorModels = () => {
122 123
		assertLineMapping(model, 'model');
		assertLineMapping(mirrorModel1, 'mirrorModel1');
124 125 126 127 128 129 130 131 132 133 134 135 136
		model._assertLineNumbersOK();
		assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
		assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
		assert.equal(mirrorModel1.getValue(), model.getValue(), 'mirror model 1 text OK');
		assert.equal(mirrorModel1.getVersionId(), model.getVersionId(), 'mirror model 1 version OK');
	};

	callback(model, assertMirrorModels);

	model.dispose();
	mirrorModel1.dispose();
	mirrorModel2.dispose();
}