Browse Source

Added: Added delta transformations for AttributeDelta, SplitDelta and RenameDelta.

Szymon Cofalik 9 years ago
parent
commit
f133311673

+ 99 - 3
packages/ckeditor5-engine/src/model/delta/basic-transformations.js

@@ -10,6 +10,7 @@ import Position from '../position.js';
 
 import NoOperation from '../operation/nooperation.js';
 import AttributeOperation from '../operation/attributeoperation.js';
+import InsertOperation from '../operation/insertoperation.js';
 import ReinsertOperation from '../operation/reinsertoperation.js';
 
 import Delta from './delta.js';
@@ -21,6 +22,7 @@ import SplitDelta from './splitdelta.js';
 import WeakInsertDelta from './weakinsertdelta.js';
 import WrapDelta from './wrapdelta.js';
 import UnwrapDelta from './unwrapdelta.js';
+import RenameDelta from './renamedelta.js';
 
 import compareArrays from '../../../utils/comparearrays.js';
 
@@ -39,6 +41,41 @@ addTransformationCase( AttributeDelta, WeakInsertDelta, ( a, b, isStrong ) => {
 	return deltas;
 } );
 
+// Add special case for AttributeDelta x SplitDelta transformation.
+addTransformationCase( AttributeDelta, SplitDelta, ( a, b, isStrong ) => {
+	const splitPosition = new Position( b.position.root, b.position.path.slice( 0, -1 ) );
+
+	const deltas = defaultTransform( a, b, isStrong );
+
+	for ( let operation of a.operations ) {
+		// If a node that has been split has it's attribute updated, we should also update attribute of
+		// the node created during splitting.
+		if ( operation.range.containsPosition( splitPosition ) || operation.range.start.isEqual( splitPosition ) ) {
+			const additionalAttributeDelta = new AttributeDelta();
+
+			const rangeStart = splitPosition.getShiftedBy( 1 );
+			const rangeEnd = Position.createFromPosition( rangeStart );
+			rangeEnd.path.push( 0 );
+
+			const oldValue = b._cloneOperation.nodes.getNode( 0 ).getAttribute( operation.key );
+
+			additionalAttributeDelta.addOperation( new AttributeOperation(
+				new Range( rangeStart, rangeEnd ),
+				operation.key,
+				oldValue === undefined ? null : oldValue,
+				operation.newValue,
+				0
+			) );
+
+			deltas.push( additionalAttributeDelta );
+
+			break;
+		}
+	}
+
+	return deltas;
+} );
+
 // Add special case for InsertDelta x MergeDelta transformation.
 addTransformationCase( InsertDelta, MergeDelta, ( a, b, isStrong ) => {
 	// If insert is applied at the same position where merge happened, we reverse the merge (we treat it like it
@@ -223,6 +260,31 @@ addTransformationCase( SplitDelta, WrapDelta, ( a, b, isStrong ) => {
 	return defaultTransform( a, b, isStrong );
 } );
 
+// Add special case for SplitDelta x WrapDelta transformation.
+addTransformationCase( SplitDelta, AttributeDelta, ( a, b ) => {
+	a = a.clone();
+
+	const splitPosition = new Position( a.position.root, a.position.path.slice( 0, -1 ) );
+
+	if ( a._cloneOperation instanceof InsertOperation ) {
+		// If element to split had it's attribute changed, we have to reflect this change in an element
+		// that is in SplitDelta's InsertOperation.
+		for ( let operation of b.operations ) {
+			if ( operation.range.containsPosition( splitPosition ) || operation.range.start.isEqual( splitPosition ) ) {
+				if ( operation.newValue !== null ) {
+					a._cloneOperation.nodes.getNode( 0 ).setAttribute( operation.key, operation.newValue );
+				} else {
+					a._cloneOperation.nodes.getNode( 0 ).removeAttribute( operation.key );
+				}
+
+				break;
+			}
+		}
+	}
+
+	return [ a ];
+} );
+
 // Add special case for UnwrapDelta x SplitDelta transformation.
 addTransformationCase( UnwrapDelta, SplitDelta, ( a, b, isStrong ) => {
 	// If incoming unwrap delta tries to unwrap node that got split we should unwrap the original node and the split copy.
@@ -247,10 +309,9 @@ addTransformationCase( UnwrapDelta, SplitDelta, ( a, b, isStrong ) => {
 } );
 
 // Add special case for WeakInsertDelta x AttributeDelta transformation.
-addTransformationCase( WeakInsertDelta, AttributeDelta, ( a, b, isStrong ) => {
+addTransformationCase( WeakInsertDelta, AttributeDelta, ( a, b ) => {
 	// If nodes are weak-inserted into attribute delta range, we need to apply changes from attribute delta on them.
-	// So first we do the normal transformation and if this special cases happens, we will add an extra delta.
-	const deltas = defaultTransform( a, b, isStrong );
+	const deltas = [ a.clone() ];
 
 	if ( b.range.containsPosition( a.position ) ) {
 		deltas.push( _getComplementaryAttrDelta( a, b ) );
@@ -290,6 +351,41 @@ addTransformationCase( WrapDelta, SplitDelta, ( a, b, isStrong ) => {
 	return defaultTransform( a, b, isStrong );
 } );
 
+// Add special case for RenameDelta x SplitDelta transformation.
+addTransformationCase( RenameDelta, SplitDelta, ( a, b, isStrong ) => {
+	const splitPosition = new Position( b.position.root, b.position.path.slice( 0, -1 ) );
+
+	const deltas = defaultTransform( a, b, isStrong );
+
+	if ( a.operations[ 0 ].position.isEqual( splitPosition ) ) {
+		// If a node that has been split has it's name changed, we should also change name of
+		// the node created during splitting.
+		const additionalRenameDelta = a.clone();
+		additionalRenameDelta.operations[ 0 ].position = a.operations[ 0 ].position.getShiftedBy( 1 );
+
+		deltas.push( additionalRenameDelta );
+	}
+
+	return deltas;
+} );
+
+// Add special case for SplitDelta x RenameDelta transformation.
+addTransformationCase( SplitDelta, RenameDelta, ( a, b ) => {
+	a = a.clone();
+
+	const splitPosition = new Position( a.position.root, a.position.path.slice( 0, -1 ) );
+
+	if ( a._cloneOperation instanceof InsertOperation ) {
+		// If element to split had it's name changed, we have to reflect this change in an element
+		// that is in SplitDelta's InsertOperation.
+		if ( b.operations[ 0 ].position.isEqual( splitPosition ) ) {
+			a._cloneOperation.nodes.getNode( 0 ).name = b.operations[ 0 ].newName;
+		}
+	}
+
+	return [ a ];
+} );
+
 // Helper function for `AttributeDelta` class transformations.
 // Creates an attribute delta that sets attribute from given `attributeDelta` on nodes from given `weakInsertDelta`.
 function _getComplementaryAttrDelta( weakInsertDelta, attributeDelta ) {

+ 124 - 7
packages/ckeditor5-engine/tests/model/delta/transform/attributedelta.js

@@ -10,6 +10,7 @@ import transformations from 'ckeditor5/engine/model/delta/basic-transformations.
 
 import transform from 'ckeditor5/engine/model/delta/transform.js';
 
+import Element from 'ckeditor5/engine/model/element.js';
 import Text from 'ckeditor5/engine/model/text.js';
 import Position from 'ckeditor5/engine/model/position.js';
 import Range from 'ckeditor5/engine/model/range.js';
@@ -22,6 +23,7 @@ import {
 	getFilledDocument,
 	getAttributeDelta,
 	getWeakInsertDelta,
+	getSplitDelta
 } from 'tests/engine/model/delta/transform/_utils/utils.js';
 
 describe( 'transform', () => {
@@ -34,15 +36,11 @@ describe( 'transform', () => {
 	} );
 
 	describe( 'AttributeDelta by', () => {
-		let attrDelta;
-
-		beforeEach( () => {
-			let attrRange = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 3, 3, 9 ] ) );
-			attrDelta = getAttributeDelta( attrRange, 'key', 'old', 'new', baseVersion );
-		} );
-
 		describe( 'WeakInsertDelta', () => {
 			it( 'weak insert inside attribute range should "fix" splitting the range', () => {
+				let attrRange = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 3, 3, 9 ] ) );
+				let attrDelta = getAttributeDelta( attrRange, 'key', 'old', 'new', baseVersion );
+
 				let insertPosition = new Position( root, [ 3, 3, 0 ] );
 				let insertDelta = getWeakInsertDelta(
 					insertPosition,
@@ -115,6 +113,9 @@ describe( 'transform', () => {
 			} );
 
 			it( 'should be normally transformed if weak insert is not in the attribute range', () => {
+				let attrRange = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 3, 3, 9 ] ) );
+				let attrDelta = getAttributeDelta( attrRange, 'key', 'old', 'new', baseVersion );
+
 				let insertPosition = new Position( root, [ 5 ] );
 				let insertDelta = getWeakInsertDelta( insertPosition, 'abc', baseVersion );
 
@@ -139,5 +140,121 @@ describe( 'transform', () => {
 				} );
 			} );
 		} );
+
+		describe( 'SplitDelta', () => {
+			it( 'change attribute of split element', () => {
+				let attrRange1 = Range.createFromParentsAndOffsets( root, 0, root, 1 );
+				let attrRange2 = new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 4 ] ) );
+
+				let attrDelta = new AttributeDelta();
+				attrDelta.addOperation( new AttributeOperation( attrRange1, 'key', 'old', 'new', baseVersion ) );
+				attrDelta.addOperation( new AttributeOperation( attrRange2, 'key', 'old', 'new', baseVersion ) );
+
+				let splitPosition = new Position( root, [ 3, 3, 3, 3 ] );
+				let splitDelta = getSplitDelta( splitPosition, new Element( 'p' ), 9, baseVersion );
+
+				let transformed = transform( attrDelta, splitDelta );
+
+				expect( transformed.length ).to.equal( 2 );
+
+				baseVersion = splitDelta.operations.length;
+
+				expectDelta( transformed[ 0 ], {
+					type: AttributeDelta,
+					operations: [
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 0 ] ), new Position( root, [ 1 ] ) ),
+							key: 'key',
+							oldValue: 'old',
+							newValue: 'new',
+							baseVersion: baseVersion
+						},
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 3, 5 ] ), new Position( root, [ 3, 4 ] ) ),
+							key: 'key',
+							oldValue: 'old',
+							newValue: 'new',
+							baseVersion: baseVersion + 1
+						},
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 2 ] ), new Position( root, [ 3, 3, 4 ] ) ),
+							key: 'key',
+							oldValue: 'old',
+							newValue: 'new',
+							baseVersion: baseVersion + 2
+						},
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 3, 4, 0 ] ), new Position( root, [ 3, 3, 4, 9 ] ) ),
+							key: 'key',
+							oldValue: 'old',
+							newValue: 'new',
+							baseVersion: baseVersion + 3
+						}
+					]
+				} );
+
+				expectDelta( transformed[ 1 ], {
+					type: AttributeDelta,
+					operations: [
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 3, 4 ] ), new Position( root, [ 3, 3, 4, 0 ] ) ),
+							key: 'key',
+							oldValue: null,
+							newValue: 'new',
+							baseVersion: baseVersion + 4
+						}
+					]
+				} );
+			} );
+
+			// A different case.
+			it( 'change attribute of split element #2', () => {
+				let attrRange = new Range( new Position( root, [ 3, 3, 3 ] ), new Position( root, [ 3, 3, 3, 0 ] ) );
+				let attrDelta = new AttributeDelta();
+				attrDelta.addOperation( new AttributeOperation( attrRange, 'foo', null, 'bar', baseVersion ) );
+
+				let splitPosition = new Position( root, [ 3, 3, 3, 3 ] );
+				let splitDelta = getSplitDelta( splitPosition, new Element( 'p', { foo: 'old' } ), 9, baseVersion );
+
+				let transformed = transform( attrDelta, splitDelta );
+
+				expect( transformed.length ).to.equal( 2 );
+
+				baseVersion = splitDelta.operations.length;
+
+				expectDelta( transformed[ 0 ], {
+					type: AttributeDelta,
+					operations: [
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 3, 3 ] ), new Position( root, [ 3, 3, 3, 0 ] ) ),
+							key: 'foo',
+							oldValue: null,
+							newValue: 'bar',
+							baseVersion: baseVersion
+						}
+					]
+				} );
+
+				expectDelta( transformed[ 1 ], {
+					type: AttributeDelta,
+					operations: [
+						{
+							type: AttributeOperation,
+							range: new Range( new Position( root, [ 3, 3, 4 ] ), new Position( root, [ 3, 3, 4, 0 ] ) ),
+							key: 'foo',
+							oldValue: 'old',
+							newValue: 'bar',
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+			} );
+		} );
 	} );
 } );

+ 112 - 0
packages/ckeditor5-engine/tests/model/delta/transform/renamedelta.js

@@ -0,0 +1,112 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: model, operation */
+
+import transformations from 'ckeditor5/engine/model/delta/basic-transformations.js';
+/*jshint unused: false*/
+
+import transform from 'ckeditor5/engine/model/delta/transform.js';
+
+import Element from 'ckeditor5/engine/model/element.js';
+import Position from 'ckeditor5/engine/model/position.js';
+import Range from 'ckeditor5/engine/model/range.js';
+
+import RenameDelta from 'ckeditor5/engine/model/delta/renamedelta.js';
+import RenameOperation from 'ckeditor5/engine/model/operation/renameoperation.js';
+
+import {
+	getFilledDocument,
+	expectDelta,
+	getSplitDelta
+} from 'tests/engine/model/delta/transform/_utils/utils.js';
+
+describe( 'transform', () => {
+	let doc, root, baseVersion;
+
+	beforeEach( () => {
+		doc = getFilledDocument();
+		root = doc.getRoot();
+		baseVersion = doc.version;
+	} );
+
+	describe( 'RenameDelta by', () => {
+		describe( 'SplitDelta', () => {
+			it( 'split element is renamed', () => {
+				let renameDelta = new RenameDelta();
+				renameDelta.addOperation( new RenameOperation(
+					new Position( root, [ 3, 3 ] ),
+					'p',
+					'li',
+					baseVersion
+				) );
+
+				let splitPosition = new Position( root, [ 3, 3, 3 ] );
+				let splitDelta = getSplitDelta( splitPosition, new Element( 'p' ), 9, baseVersion );
+
+				let transformed = transform( renameDelta, splitDelta );
+
+				baseVersion = splitDelta.length;
+
+				expect( transformed.length ).to.equal( 2 );
+
+				expectDelta( transformed[ 0 ], {
+					type: RenameDelta,
+					operations: [
+						{
+							type: RenameOperation,
+							oldName: 'p',
+							newName: 'li',
+							position: new Position( root, [ 3, 3 ] )
+						}
+					]
+				} );
+
+				expectDelta( transformed[ 1 ], {
+					type: RenameDelta,
+					operations: [
+						{
+							type: RenameOperation,
+							oldName: 'p',
+							newName: 'li',
+							position: new Position( root, [ 3, 4 ] )
+						}
+					]
+				} );
+			} );
+
+			it( 'split element is different than renamed element', () => {
+				let renameDelta = new RenameDelta();
+				renameDelta.addOperation( new RenameOperation(
+					new Position( root, [ 3, 3 ] ),
+					'p',
+					'li',
+					baseVersion
+				) );
+
+				let splitPosition = new Position( root, [ 3, 2, 1 ] );
+				let splitDelta = getSplitDelta( splitPosition, new Element( 'p' ), 9, baseVersion );
+
+				let transformed = transform( renameDelta, splitDelta );
+
+				baseVersion = splitDelta.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: RenameDelta,
+					operations: [
+						{
+							type: RenameOperation,
+							oldName: 'p',
+							newName: 'li',
+							position: new Position( root, [ 3, 4 ] )
+						}
+					]
+				} );
+			} );
+		} );
+	} );
+} );

+ 229 - 0
packages/ckeditor5-engine/tests/model/delta/transform/splitdelta.js

@@ -16,11 +16,15 @@ import Range from 'ckeditor5/engine/model/range.js';
 
 import Delta from 'ckeditor5/engine/model/delta/delta.js';
 import SplitDelta from 'ckeditor5/engine/model/delta/splitdelta.js';
+import AttributeDelta from 'ckeditor5/engine/model/delta/attributedelta.js';
+import RenameDelta from 'ckeditor5/engine/model/delta/renamedelta.js';
 
 import InsertOperation from 'ckeditor5/engine/model/operation/insertoperation.js';
+import AttributeOperation from 'ckeditor5/engine/model/operation/attributeoperation.js';
 import ReinsertOperation from 'ckeditor5/engine/model/operation/reinsertoperation.js';
 import MoveOperation from 'ckeditor5/engine/model/operation/moveoperation.js';
 import NoOperation from 'ckeditor5/engine/model/operation/nooperation.js';
+import RenameOperation from 'ckeditor5/engine/model/operation/renameoperation.js';
 
 import { getNodesAndText, jsonParseStringify } from 'tests/engine/model/_utils/utils.js';
 
@@ -461,5 +465,230 @@ describe( 'transform', () => {
 				expect( nodesAndText ).to.equal( 'EXabcdXPabcPPfoobarxyzPE' );
 			} );
 		} );
+
+		describe( 'AttributeDelta', () => {
+			it( 'attribute changed on split element', () => {
+				let attributeDelta = new AttributeDelta();
+
+				attributeDelta.addOperation( new AttributeOperation(
+					Range.createFromParentsAndOffsets( root, 0, root, 2 ), 'key', 'oldValue', 'newValue', baseVersion
+				) );
+
+				attributeDelta.addOperation( new AttributeOperation(
+					Range.createFromPositionAndShift( new Position( root, [ 3, 3, 2 ] ), 3 ), 'key', null, 'newValue', baseVersion + 1
+				) );
+
+				let transformed = transform( splitDelta, attributeDelta );
+
+				baseVersion = attributeDelta.operations.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: InsertOperation,
+							position: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+
+				expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).getAttribute( 'key' ) ).to.equal( 'newValue' );
+			} );
+
+			it( 'attribute removed from split element', () => {
+				splitDelta.operations[ 0 ].nodes.getNode( 0 ).setAttribute( 'key', 'oldValue' );
+				let attributeDelta = new AttributeDelta();
+
+				attributeDelta.addOperation( new AttributeOperation(
+					Range.createFromParentsAndOffsets( root, 0, root, 2 ), 'key', 'otherValue', null, baseVersion
+				) );
+
+				attributeDelta.addOperation( new AttributeOperation(
+					Range.createFromPositionAndShift( new Position( root, [ 3, 3, 2 ] ), 3 ), 'key', 'oldValue', null, baseVersion + 1
+				) );
+
+				let transformed = transform( splitDelta, attributeDelta );
+
+				baseVersion = attributeDelta.operations.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: InsertOperation,
+							position: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+
+				expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).hasAttribute( 'key' ) ).to.be.false;
+			} );
+
+			it( 'attribute changed on split element that is reinserted from graveyard', () => {
+				splitDelta.operations[ 0 ] = new ReinsertOperation(
+					new Position( gy, [ 1 ] ),
+					1,
+					new Position( root, [ 3, 3, 4 ] ),
+					baseVersion
+				);
+
+				let attributeDelta = new AttributeDelta();
+
+				attributeDelta.addOperation( new AttributeOperation(
+					Range.createFromParentsAndOffsets( root, 0, root, 4 ), 'key', 'oldValue', 'newValue', baseVersion
+				) );
+
+				let transformed = transform( splitDelta, attributeDelta );
+
+				baseVersion = attributeDelta.operations.length;
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: ReinsertOperation,
+							sourcePosition: new Position( gy, [ 1 ] ),
+							howMany: 1,
+							targetPosition: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+			} );
+		} );
+
+		describe( 'RenameDelta', () => {
+			it( 'renamed split element', () => {
+				const renameDelta = new RenameDelta();
+				renameDelta.addOperation( new RenameOperation(
+					new Position( root, [ 3, 3, 3 ] ), 'p', 'li', baseVersion
+				) );
+
+				let transformed = transform( splitDelta, renameDelta );
+
+				baseVersion = renameDelta.operations.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: InsertOperation,
+							position: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+
+				expect( transformed[ 0 ].operations[ 0 ].nodes.getNode( 0 ).name ).to.equal( 'li' );
+			} );
+
+			it( 'split element is different than renamed element', () => {
+				const renameDelta = new RenameDelta();
+				renameDelta.addOperation( new RenameOperation(
+					new Position( root, [ 4 ] ), 'p', 'li', baseVersion
+				) );
+
+				let transformed = transform( splitDelta, renameDelta );
+
+				baseVersion = renameDelta.operations.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: InsertOperation,
+							position: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+			} );
+
+			it( 'renamed split element that is reinserted from graveyard', () => {
+				splitDelta.operations[ 0 ] = new ReinsertOperation(
+					new Position( gy, [ 1 ] ),
+					1,
+					new Position( root, [ 3, 3, 4 ] ),
+					baseVersion
+				);
+
+				const renameDelta = new RenameDelta();
+				renameDelta.addOperation( new RenameOperation(
+					new Position( root, [ 3, 3, 3 ] ), 'p', 'li', baseVersion
+				) );
+
+				let transformed = transform( splitDelta, renameDelta );
+
+				baseVersion = renameDelta.operations.length;
+
+				expect( transformed.length ).to.equal( 1 );
+
+				expectDelta( transformed[ 0 ], {
+					type: SplitDelta,
+					operations: [
+						{
+							type: ReinsertOperation,
+							sourcePosition: new Position( gy, [ 1 ] ),
+							howMany: 1,
+							targetPosition: new Position( root, [ 3, 3, 4 ] ),
+							baseVersion: baseVersion
+						},
+						{
+							type: MoveOperation,
+							sourcePosition: new Position( root, [ 3, 3, 3, 3 ] ),
+							howMany: 9,
+							targetPosition: new Position( root, [ 3, 3, 4, 0 ] ),
+							baseVersion: baseVersion + 1
+						}
+					]
+				} );
+			} );
+		} );
 	} );
 } );