Browse Source

Change operation tests and bug fixes.

Piotr Jasiun 10 years ago
parent
commit
9b10cea0cb

+ 19 - 19
packages/ckeditor5-utils/src/document/changeoperation.js

@@ -37,21 +37,13 @@ CKEDITOR.define( [ 'document/operation' ], function( Operation ) {
 			}
 
 			function remove() {
-				var attrs, i, len;
-
 				for ( var value of range ) {
 					// TODO: if debug
 					if ( !value.node.hasAttr( oldAttr ) ) {
 						throw 'The attribute which should be removed does not exists.';
 					}
 
-					attrs = value.node.attrs;
-
-					for ( i = 0, len = attrs.length; i < len; i++ ) {
-						if ( attrs[ i ].isEquals( oldAttr ) ) {
-							attrs.splice( i, 1 );
-						}
-					}
+					doRemove( value.node.attrs, oldAttr );
 				}
 			}
 
@@ -62,13 +54,11 @@ CKEDITOR.define( [ 'document/operation' ], function( Operation ) {
 						throw 'The attribute with given key already exists.';
 					}
 
-					value.node.attrs.push( newAttr );
+					doInsert( value.node.attrs, newAttr );
 				}
 			}
 
 			function change() {
-				var attrs, i, len;
-
 				for ( var value of range ) {
 					// TODO: if debug
 					if ( oldAttr.key != newAttr.key ) {
@@ -80,17 +70,27 @@ CKEDITOR.define( [ 'document/operation' ], function( Operation ) {
 						throw 'The attribute which should be changed does not exists.';
 					}
 
-					attrs = value.node.attrs;
+					doRemove( value.node.attrs, oldAttr );
 
-					for ( i = 0, len = attrs.length; i < len; i++ ) {
-						if ( attrs[ i ].isEquals( oldAttr ) ) {
-							attrs.splice( i, 1 );
-						}
-					}
+					doInsert( value.node.attrs, newAttr );
+				}
+			}
+
+			function doRemove( attrs, attrToRemove ) {
+				var i, len;
+
+				for ( i = 0, len = attrs.length; i < len; i++ ) {
+					if ( attrs[ i ].isEqual( attrToRemove ) ) {
+						attrs.splice( i, 1 );
 
-					attrs.push( newAttr );
+						return;
+					}
 				}
 			}
+
+			function doInsert( attrs, attrToInsert ) {
+				attrs.push( attrToInsert );
+			}
 		}
 
 		reverseOperation() {

+ 1 - 1
packages/ckeditor5-utils/src/document/node.js

@@ -46,7 +46,7 @@ CKEDITOR.define( [ 'document/attribute' ], function( Attribute ) {
 
 			if ( attr instanceof Attribute ) {
 				for ( i = 0, len = this.attrs.length; i < len; i++ ) {
-					if ( this.attrs[ i ].isEquals( attr ) ) {
+					if ( this.attrs[ i ].isEqual( attr ) ) {
 						return this.attrs[ i ];
 					}
 				}

+ 380 - 13
packages/ckeditor5-utils/tests/document/changeoperation.js

@@ -7,29 +7,396 @@
 
 'use strict';
 
+var modules = bender.amd.require(
+	'document/document',
+	'document/changeoperation',
+	'document/position',
+	'document/range',
+	'document/character',
+	'document/attribute' );
+
 describe( 'ChangeOperation', function() {
-	it( 'should insert attribute' );
+	it( 'should insert attribute to the set of nodes', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var newAttr = new Attribute( 'isNew', true );
+
+		doc.root.children.push( new Character( doc.root, 'b' ) );
+		doc.root.children.push( new Character( doc.root, 'a' ) );
+		doc.root.children.push( new Character( doc.root, 'r' ) );
+
+		doc.applyOperation( new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 2 ], doc ) ),
+			null,
+			newAttr,
+			doc.version ) );
+
+		expect( doc.version ).to.be.equal( 1 );
+		expect( doc.root.children.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].hasAttr( newAttr ) ).to.be.true;
+		expect( doc.root.children[ 1 ].hasAttr( newAttr ) ).to.be.true;
+		expect( doc.root.children[ 2 ].attrs.length ).to.be.equal( 0 );
+	} );
+
+	it( 'should add attribute to the existing attributes', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var newAttr = new Attribute( 'isNew', true );
+		var fooAttr = new Attribute( 'foo', true );
+		var barAttr = new Attribute( 'bar', true );
+
+		doc.root.children.push( new Character( doc.root, 'x', [ fooAttr, barAttr ] ) );
+
+		doc.applyOperation( new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+			null,
+			newAttr,
+			doc.version ) );
+
+		expect( doc.version ).to.be.equal( 1 );
+		expect( doc.root.children.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].hasAttr( newAttr ) ).to.be.true;
+		expect( doc.root.children[ 0 ].hasAttr( fooAttr ) ).to.be.true;
+		expect( doc.root.children[ 0 ].hasAttr( barAttr ) ).to.be.true;
+	} );
+
+	it( 'should change attribute to the set of nodes', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var oldAttr = new Attribute( 'isNew', false );
+		var newAttr = new Attribute( 'isNew', true );
+
+		doc.root.children.push( new Character( doc.root, 'b', [ oldAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'a', [ oldAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'r', [ oldAttr ] ) );
+
+		doc.applyOperation( new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 2 ], doc ) ),
+			oldAttr,
+			newAttr,
+			doc.version ) );
+
+		expect( doc.version ).to.be.equal( 1 );
+		expect( doc.root.children.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].hasAttr( newAttr ) ).to.be.true;
+		expect( doc.root.children[ 1 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 1 ].hasAttr( newAttr ) ).to.be.true;
+		expect( doc.root.children[ 2 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 2 ].hasAttr( oldAttr ) ).to.be.true;
+	} );
+
+	it( 'should change attribute in the middle of existing attributes', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var fooAttr = new Attribute( 'foo', true );
+		var x1Attr = new Attribute( 'x', 1 );
+		var x2Attr = new Attribute( 'x', 2 );
+		var barAttr = new Attribute( 'bar', true );
+
+		doc.root.children.push( new Character( doc.root, 'x', [ fooAttr, x1Attr, barAttr ] ) );
+
+		doc.applyOperation( new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+			x1Attr,
+			x2Attr,
+			doc.version ) );
+
+		expect( doc.version ).to.be.equal( 1 );
+		expect( doc.root.children.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].hasAttr( fooAttr ) ).to.be.true;
+		expect( doc.root.children[ 0 ].hasAttr( x2Attr ) ).to.be.true;
+		expect( doc.root.children[ 0 ].hasAttr( barAttr ) ).to.be.true;
+	} );
+
+	it( 'should remove attribute', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var fooAttr = new Attribute( 'foo', true );
+		var xAttr = new Attribute( 'x', true );
+		var barAttr = new Attribute( 'bar', true );
+
+		doc.root.children.push( new Character( doc.root, 'x', [ fooAttr, xAttr, barAttr ] ) );
+
+		doc.applyOperation( new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+			xAttr,
+			null,
+			doc.version ) );
+
+		expect( doc.version ).to.be.equal( 1 );
+		expect( doc.root.children.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 2 );
+		expect( doc.root.children[ 0 ].hasAttr( fooAttr ) ).to.be.true;
+		expect( doc.root.children[ 0 ].hasAttr( barAttr ) ).to.be.true;
+	} );
+
+	it( 'should create a change operation as a reverse', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var oldAttr = new Attribute( 'x', 'old' );
+		var newAttr = new Attribute( 'x', 'new' );
+
+		var range = new Range( new Position( [ 0 ], doc ), new Position( [ 3 ], doc ) );
+
+		var oppertaion = new ChangeOperation( range, oldAttr, newAttr, doc.version );
+
+		var reverse = oppertaion.reverseOperation();
+
+		expect( reverse ).to.be.an.instanceof( ChangeOperation );
+		expect( reverse.baseVersion ).to.be.equals( 1 );
+		expect( reverse.range ).to.be.equals( range );
+		expect( reverse.oldAttr ).to.be.equals( newAttr );
+		expect( reverse.newAttr ).to.be.equals( oldAttr );
+	} );
+
+	it( 'should undo insert attribute by applying reverse operation', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var newAttr = new Attribute( 'isNew', true );
+
+		doc.root.children.push( new Character( doc.root, 'b' ) );
+		doc.root.children.push( new Character( doc.root, 'a' ) );
+		doc.root.children.push( new Character( doc.root, 'r' ) );
+
+		var oppertaion = new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 3 ], doc ) ),
+			null,
+			newAttr,
+			doc.version );
+
+		var reverse = oppertaion.reverseOperation();
+
+		doc.applyOperation( oppertaion );
+
+		doc.applyOperation( reverse );
+
+		expect( doc.version ).to.be.equal( 2 );
+		expect( doc.root.children.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 0 );
+		expect( doc.root.children[ 1 ].attrs.length ).to.be.equal( 0 );
+		expect( doc.root.children[ 2 ].attrs.length ).to.be.equal( 0 );
+	} );
+
+	it( 'should undo change attribute by applying reverse operation', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var oldAttr = new Attribute( 'isNew', false );
+		var newAttr = new Attribute( 'isNew', true );
+
+		doc.root.children.push( new Character( doc.root, 'b', [ oldAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'a', [ oldAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'r', [ oldAttr ] ) );
+
+		var oppertaion = new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 3 ], doc ) ),
+			oldAttr,
+			newAttr,
+			doc.version );
+
+		var reverse = oppertaion.reverseOperation();
+
+		doc.applyOperation( oppertaion );
+
+		doc.applyOperation( reverse );
+
+		expect( doc.version ).to.be.equal( 2 );
+		expect( doc.root.children.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].hasAttr( oldAttr ) ).to.be.true;
+		expect( doc.root.children[ 1 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 1 ].hasAttr( oldAttr ) ).to.be.true;
+		expect( doc.root.children[ 2 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 2 ].hasAttr( oldAttr ) ).to.be.true;
+	} );
+
+	it( 'should undo remove attribute by applying reverse operation', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var fooAttr = new Attribute( 'foo', false );
+
+		doc.root.children.push( new Character( doc.root, 'b', [ fooAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'a', [ fooAttr ] ) );
+		doc.root.children.push( new Character( doc.root, 'r', [ fooAttr ] ) );
+
+		var oppertaion = new ChangeOperation(
+			new Range( new Position( [ 0 ], doc ), new Position( [ 3 ], doc ) ),
+			fooAttr,
+			null,
+			doc.version );
+
+		var reverse = oppertaion.reverseOperation();
+
+		doc.applyOperation( oppertaion );
+
+		doc.applyOperation( reverse );
+
+		expect( doc.version ).to.be.equal( 2 );
+		expect( doc.root.children.length ).to.be.equal( 3 );
+		expect( doc.root.children[ 0 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 0 ].hasAttr( fooAttr ) ).to.be.true;
+		expect( doc.root.children[ 1 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 1 ].hasAttr( fooAttr ) ).to.be.true;
+		expect( doc.root.children[ 2 ].attrs.length ).to.be.equal( 1 );
+		expect( doc.root.children[ 2 ].hasAttr( fooAttr ) ).to.be.true;
+	} );
+
+	it( 'should throw an error when one try to remove and the attribute does not exists', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var fooAttr = new Attribute( 'foo', true );
+
+		doc.root.children.push( new Character( doc.root, 'x' ) );
+
+		expect( function() {
+			doc.applyOperation( new ChangeOperation(
+				new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+				fooAttr,
+				null,
+				doc.version ) );
+		} ).to.throw( 'The attribute which should be removed does not exists.' );
+	} );
+
+	it( 'should throw an error when one try to insert and the attribute already exists', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
+
+		var doc = new Document();
+
+		var x1Attr = new Attribute( 'x', 1 );
+		var x2Attr = new Attribute( 'x', 2 );
 
-	it( 'should change attribute' );
+		doc.root.children.push( new Character( doc.root, 'x', [ x1Attr ] ) );
 
-	it( 'should remove attribute' );
+		expect( function() {
+			doc.applyOperation( new ChangeOperation(
+				new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+				null,
+				x2Attr,
+				doc.version ) );
+		} ).to.throw( 'The attribute with given key already exists.' );
+	} );
 
-	it( 'should create a change operation as a reverse' );
+	it( 'should throw an error when one try to change and the new and old attributes have different keys', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
 
-	it( 'should undo changes by applying reverse operation' );
+		var doc = new Document();
 
-	it( 'should undo insert attribute by applying reverse operation' );
+		var fooAttr = new Attribute( 'foo', true );
+		var barAttr = new Attribute( 'bar', true );
 
-	it( 'should undo change attribute by applying reverse operation' );
+		doc.root.children.push( new Character( doc.root, 'x' ) );
 
-	it( 'should undo remove attribute by applying reverse operation' );
+		expect( function() {
+			doc.applyOperation( new ChangeOperation(
+				new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+				fooAttr,
+				barAttr,
+				doc.version ) );
+		} ).to.throw( 'Old and new attributes should have the same keys.' );
+	} );
 
-	it( 'should throw an error when one try to remove and the attribute does not exists' );
+	it( 'should throw an error when one try to change and the old attribute does not exists', function() {
+		var Document = modules[ 'document/document' ];
+		var ChangeOperation = modules[ 'document/changeoperation' ];
+		var Position = modules[ 'document/position' ];
+		var Range = modules[ 'document/range' ];
+		var Character = modules[ 'document/character' ];
+		var Attribute = modules[ 'document/attribute' ];
 
-	it( 'should throw an error when one try to insert and the attribute already exists' );
+		var doc = new Document();
 
-	it( 'should throw an error when one try to change and the new and old attributes have different keys' );
+		var x1Attr = new Attribute( 'x', 1 );
+		var x2Attr = new Attribute( 'x', 2 );
 
-	it( 'should throw an error when one try to change and the old attribute does not exists' );
-} );
+		doc.root.children.push( new Character( doc.root, 'x' ) );
 
+		expect( function() {
+			doc.applyOperation( new ChangeOperation(
+				new Range( new Position( [ 0 ], doc ), new Position( [ 1 ], doc ) ),
+				x1Attr,
+				x2Attr,
+				doc.version ) );
+		} ).to.throw( 'The attribute which should be changed does not exists.' );
+	} );
+} );