/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; import * as assert from 'assert'; import { TextModel } from 'vs/editor/common/model/textModel'; import { MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel'; import { Position } from 'vs/editor/common/core/position'; import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { EndOfLinePreference, IIdentifiedSingleEditOperation, EndOfLineSequence } from 'vs/editor/common/model'; export function testApplyEditsWithSyncedModels(original: string[], edits: IIdentifiedSingleEditOperation[], expected: string[], inputEditsAreInvalid: boolean = false): void { 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 assert.deepEqual(model.getValue(EndOfLinePreference.LF), expectedStr); assertMirrorModels(); // Apply the inverse edits var inverseInverseEdits = model.applyEdits(inverseEdits); // Assert the inverse edits brought back model to original state assert.deepEqual(model.getValue(EndOfLinePreference.LF), originalStr); if (!inputEditsAreInvalid) { const simplifyEdit = (edit: IIdentifiedSingleEditOperation) => { return { identifier: edit.identifier, range: edit.range, text: edit.text, forceMoveMarkers: edit.forceMoveMarkers, isAutoWhitespaceEdit: edit.isAutoWhitespaceEdit }; }; // Assert the inverse of the inverse edits are the original edits assert.deepEqual(inverseInverseEdits.map(simplifyEdit), edits.map(simplifyEdit)); } assertMirrorModels(); }); } const enum AssertDocumentLineMappingDirection { 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); } export function assertSyncedModels(text: string, callback: (model: TextModel, assertMirrorModels: () => void) => void, setup: (model: TextModel) => void = null): void { var model = new TextModel(text, TextModel.DEFAULT_CREATION_OPTIONS, null); model.setEOL(EndOfLineSequence.LF); assertLineMapping(model, 'model'); if (setup) { setup(model); assertLineMapping(model, 'model'); } var mirrorModel2 = new MirrorTextModel(null, model.getLinesContent(), model.getEOL(), model.getVersionId()); var mirrorModel2PrevVersionId = model.getVersionId(); model.onDidChangeContent((e: IModelContentChangedEvent) => { 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 = () => { assertLineMapping(model, 'model'); assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK'); assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK'); }; callback(model, assertMirrorModels); model.dispose(); mirrorModel2.dispose(); }