8
0
Просмотр исходного кода

Tests: Additional tests for engine.model classes.

Szymon Cofalik 9 лет назад
Родитель
Сommit
61769b9d5e

+ 6 - 3
packages/ckeditor5-engine/src/model/textproxy.js

@@ -107,7 +107,7 @@ export default class TextProxy {
 	 * @type {Number}
 	 */
 	get startOffset() {
-		return this.textNode.startOffset + this.offsetInText;
+		return this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;
 	}
 
 	/**
@@ -129,7 +129,7 @@ export default class TextProxy {
 	 * @type {Number}
 	 */
 	get endOffset() {
-		return this.startOffset + this.offsetSize;
+		return this.startOffset !== null ? this.startOffset + this.offsetSize : null;
 	}
 
 	/**
@@ -141,7 +141,10 @@ export default class TextProxy {
 	 */
 	getPath() {
 		const path = this.textNode.getPath();
-		path[ path.length - 1 ] += this.offsetInText;
+
+		if ( path.length > 0 ) {
+			path[ path.length - 1 ] += this.offsetInText;
+		}
 
 		return path;
 	}

+ 40 - 4
packages/ckeditor5-engine/tests/model/documentfragment.js

@@ -39,6 +39,25 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
+	describe( 'iterator', () => {
+		it( 'should iterate over document fragment\'s children', () => {
+			let xx = new Text( 'xx' );
+			let p = new Element( 'p' );
+			let yy = new Text( 'yy' );
+			let frag = new DocumentFragment( [ xx, p, yy ] );
+
+			expect( Array.from( frag ) ).to.deep.equal( [ xx, p, yy ] );
+		} );
+	} );
+
+	describe( 'getPath', () => {
+		it( 'should return empty array', () => {
+			let frag = new DocumentFragment( [ new Text( 'x' ), new Element( 'p' ), new Text( 'y' ) ] );
+
+			expect( frag.getPath() ).to.deep.equal( [] );
+		} );
+	} );
+
 	describe( 'isEmpty', () => {
 		it( 'should return true if document fragment has no children', () => {
 			let frag = new DocumentFragment();
@@ -53,11 +72,28 @@ describe( 'DocumentFragment', () => {
 		} );
 	} );
 
-	describe( 'getPath', () => {
-		it( 'should return empty array', () => {
-			let frag = new DocumentFragment( [ new Text( 'x' ), new Element( 'p' ), new Text( 'y' ) ] );
+	describe( 'offsetToIndex', () => {
+		let frag;
 
-			expect( frag.getPath() ).to.deep.equal( [] );
+		beforeEach( () => {
+			frag = new Element( 'elem', [], [ new Element( 'p' ), new Text( 'bar' ), new Element( 'h' ) ] );
+		} );
+
+		it( 'should return index of a node that occupies given offset in this element', () => {
+			expect( frag.offsetToIndex( 0 ) ).to.equal( 0 );
+			expect( frag.offsetToIndex( 1 ) ).to.equal( 1 );
+			expect( frag.offsetToIndex( 2 ) ).to.equal( 1 );
+			expect( frag.offsetToIndex( 3 ) ).to.equal( 1 );
+			expect( frag.offsetToIndex( 4 ) ).to.equal( 2 );
+		} );
+
+		it( 'should return 0 if offset is too low', () => {
+			expect( frag.offsetToIndex( -1 ) ).to.equal( 0 );
+		} );
+
+		it( 'should return document fragment\'s child count if offset is too high', () => {
+			expect( frag.offsetToIndex( 5 ) ).to.equal( 3 );
+			expect( frag.offsetToIndex( 33 ) ).to.equal( 3 );
 		} );
 	} );
 

+ 25 - 0
packages/ckeditor5-engine/tests/model/element.js

@@ -185,6 +185,31 @@ describe( 'Element', () => {
 		} );
 	} );
 
+	describe( 'offsetToIndex', () => {
+		let element;
+
+		beforeEach( () => {
+			element = new Element( 'elem', [], [ new Element( 'p' ), new Text( 'bar' ), new Element( 'h' ) ] );
+		} );
+
+		it( 'should return index of a node that occupies given offset in this element', () => {
+			expect( element.offsetToIndex( 0 ) ).to.equal( 0 );
+			expect( element.offsetToIndex( 1 ) ).to.equal( 1 );
+			expect( element.offsetToIndex( 2 ) ).to.equal( 1 );
+			expect( element.offsetToIndex( 3 ) ).to.equal( 1 );
+			expect( element.offsetToIndex( 4 ) ).to.equal( 2 );
+		} );
+
+		it( 'should return 0 if offset is too low', () => {
+			expect( element.offsetToIndex( -1 ) ).to.equal( 0 );
+		} );
+
+		it( 'should return element\'s child count if offset is too high', () => {
+			expect( element.offsetToIndex( 5 ) ).to.equal( 3 );
+			expect( element.offsetToIndex( 33 ) ).to.equal( 3 );
+		} );
+	} );
+
 	describe( 'toJSON', () => {
 		it( 'should serialize empty element', () => {
 			let element = new Element( 'one' );

+ 20 - 0
packages/ckeditor5-engine/tests/model/operation/insertoperation.js

@@ -185,6 +185,26 @@ describe( 'InsertOperation', () => {
 		expect( clone.baseVersion ).to.equal( baseVersion );
 	} );
 
+	it( 'should save copies of inserted nodes after it is executed', () => {
+		let element = new Element( 'p', { key: 'value' } );
+
+		let op = new InsertOperation( new Position( root, [ 0 ] ), element, doc.version );
+		doc.applyOperation( wrapInDelta( op ) );
+
+		let text = new Text( 'text' );
+		let op2 = new InsertOperation( new Position( root, [ 0, 0 ] ), text, doc.version );
+		doc.applyOperation( wrapInDelta( op2 ) );
+
+		expect( op.nodes.getNode( 0 ) ).not.to.equal( element );
+		expect( op.nodes.getNode( 0 ).name ).to.equal( 'p' );
+		expect( Array.from( op.nodes.getNode( 0 ).getAttributes() ) ).to.deep.equal( [ [ 'key', 'value' ] ] );
+
+		expect( op.nodes.getNode( 0 ).getChildCount() ).to.equal( 0 );
+		expect( element.getChildCount() ).to.equal( 1 );
+
+		expect( op2.nodes.getNode( 0 ) ).not.to.equal( text );
+	} );
+
 	describe( 'toJSON', () => {
 		it( 'should create proper json object', () => {
 			const position = new Position( root, [ 0 ] );

+ 43 - 4
packages/ckeditor5-engine/tests/model/position.js

@@ -20,7 +20,7 @@ import { jsonParseStringify } from '/tests/engine/model/_utils/utils.js';
 testUtils.createSinonSandbox();
 
 describe( 'position', () => {
-	let doc, root, otherRoot, p, ul, li1, li2, f, o, z, b, a, r;
+	let doc, root, otherRoot, p, ul, li1, li2, f, o, z, b, a, r, foz, bar;
 
 	// root
 	//  |- p         Before: [ 0 ]       After: [ 1 ]
@@ -39,7 +39,7 @@ describe( 'position', () => {
 		root = doc.createRoot();
 		otherRoot = doc.createRoot( '$root', 'otherRoot' );
 
-		let foz = new Text( 'foz' );
+		foz = new Text( 'foz' );
 
 		li1 = new Element( 'li', [], foz );
 
@@ -47,7 +47,7 @@ describe( 'position', () => {
 		o = new TextProxy( foz, 1, 1 );
 		z = new TextProxy( foz, 2, 1 );
 
-		let bar = new Text( 'bar' );
+		bar = new Text( 'bar' );
 
 		li2 = new Element( 'li', [], bar );
 
@@ -278,6 +278,23 @@ describe( 'position', () => {
 		expect( new Position( root, [ 1, 0, 3 ] ) ).to.have.property( 'offset' ).that.equals( 3 );
 	} );
 
+	it( 'should have index', () => {
+		expect( new Position( root, [ 0 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+		expect( new Position( root, [ 1 ] ) ).to.have.property( 'index' ).that.equals( 1 );
+		expect( new Position( root, [ 2 ] ) ).to.have.property( 'index' ).that.equals( 2 );
+
+		expect( new Position( root, [ 0, 0 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+
+		expect( new Position( root, [ 1, 0 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+		expect( new Position( root, [ 1, 1 ] ) ).to.have.property( 'index' ).that.equals( 1 );
+		expect( new Position( root, [ 1, 2 ] ) ).to.have.property( 'index' ).that.equals( 2 );
+
+		expect( new Position( root, [ 1, 0, 0 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+		expect( new Position( root, [ 1, 0, 1 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+		expect( new Position( root, [ 1, 0, 2 ] ) ).to.have.property( 'index' ).that.equals( 0 );
+		expect( new Position( root, [ 1, 0, 3 ] ) ).to.have.property( 'index' ).that.equals( 1 );
+	} );
+
 	it( 'should be able to set offset', () => {
 		let position = new Position( root, [ 1, 0, 2 ] );
 		position.offset = 4;
@@ -303,7 +320,7 @@ describe( 'position', () => {
 		expect( new Position( root, [ 1, 0, 3 ] ).nodeBefore.data ).to.equal( 'foz' );
 	} );
 
-	it( 'should have nodeAfter', () => {
+	it( 'should have nodeAfter if it is not inside a text node', () => {
 		expect( new Position( root, [ 0 ] ).nodeAfter ).to.equal( p );
 		expect( new Position( root, [ 1 ] ).nodeAfter ).to.equal( ul );
 		expect( new Position( root, [ 2 ] ).nodeAfter ).to.be.null;
@@ -320,6 +337,28 @@ describe( 'position', () => {
 		expect( new Position( root, [ 1, 0, 3 ] ).nodeAfter ).to.be.null;
 	} );
 
+	it( 'should have a text node property if it is in text node', () => {
+		expect( new Position( root, [ 0 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 1 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 2 ] ).textNode ).to.be.null;
+
+		expect( new Position( root, [ 0, 0 ] ).textNode ).to.be.null;
+
+		expect( new Position( root, [ 1, 0 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 1, 1 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 1, 2 ] ).textNode ).to.be.null;
+
+		expect( new Position( root, [ 1, 0, 0 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 1, 0, 1 ] ).textNode ).to.equal( foz );
+		expect( new Position( root, [ 1, 0, 2 ] ).textNode ).to.equal( foz );
+		expect( new Position( root, [ 1, 0, 3 ] ).textNode ).to.be.null;
+
+		expect( new Position( root, [ 1, 1, 0 ] ).textNode ).to.be.null;
+		expect( new Position( root, [ 1, 1, 1 ] ).textNode ).to.equal( bar );
+		expect( new Position( root, [ 1, 1, 2 ] ).textNode ).to.equal( bar );
+		expect( new Position( root, [ 1, 1, 3 ] ).textNode ).to.be.null;
+	} );
+
 	it( 'should have proper parent path', () => {
 		let position = new Position( root, [ 1, 2, 3 ] );
 

+ 43 - 1
packages/ckeditor5-engine/tests/model/text.js

@@ -8,14 +8,16 @@
 'use strict';
 
 import Text from '/ckeditor5/engine/model/text.js';
+import Node from '/ckeditor5/engine/model/node.js';
+import { jsonParseStringify } from '/tests/engine/model/_utils/utils.js';
 
 describe( 'Text', () => {
 	describe( 'constructor', () => {
 		it( 'should create text node without attributes', () => {
 			let text = new Text( 'bar', { bold: true } );
 
+			expect( text ).to.be.instanceof( Node );
 			expect( text ).to.have.property( 'data' ).that.equals( 'bar' );
-			expect( text ).to.have.property( '_attrs' ).that.is.instanceof( Map );
 			expect( Array.from( text.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ] ] );
 		} );
 
@@ -27,4 +29,44 @@ describe( 'Text', () => {
 			expect( empty2.data ).to.equal( '' );
 		} );
 	} );
+
+	describe( 'offsetSize', () => {
+		it( 'should be equal to the number of characters in text node', () => {
+			expect( new Text( '' ).offsetSize ).to.equal( 0 );
+			expect( new Text( 'abc' ).offsetSize ).to.equal( 3 );
+		} );
+	} );
+
+	describe( 'clone', () => {
+		it( 'should return a new Text instance, with data and attributes equal to cloned text node', () => {
+			let text = new Text( 'foo', { bold: true } );
+			let copy = text.clone();
+
+			expect( copy.data ).to.equal( 'foo' );
+			expect( Array.from( copy.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ] ] );
+		} );
+	} );
+
+	describe( 'toJSON', () => {
+		it( 'should serialize text node', () => {
+			let text = new Text( 'foo', { bold: true } );
+
+			expect( jsonParseStringify( text ) ).to.deep.equal( {
+				attributes: [ [ 'bold', true ] ],
+				data: 'foo'
+			} );
+		} );
+	} );
+
+	describe( 'fromJSON', () => {
+		it( 'should create text node', () => {
+			let text = new Text( 'foo', { bold: true } );
+
+			let serialized = jsonParseStringify( text );
+			let deserialized = Text.fromJSON( serialized );
+
+			expect( deserialized.data ).to.equal( 'foo' );
+			expect( Array.from( deserialized.getAttributes() ) ).to.deep.equal( [ [ 'bold', true ] ] );
+		} );
+	} );
 } );

+ 50 - 7
packages/ckeditor5-engine/tests/model/textproxy.js

@@ -13,7 +13,7 @@ import TextProxy from '/ckeditor5/engine/model/textproxy.js';
 import Document from '/ckeditor5/engine/model/document.js';
 
 describe( 'TextProxy', () => {
-	let doc, text, element, textProxy, root;
+	let doc, element, textProxy, root, textProxyNoParent, text, textNoParent;
 
 	beforeEach( () => {
 		doc = new Document();
@@ -22,25 +22,62 @@ describe( 'TextProxy', () => {
 		root.insertChildren( 0, element );
 
 		text = new Text( 'foobar', { foo: 'bar' } );
-		element.insertChildren( 0, text );
+		element.insertChildren( 0, [ new Text( 'abc' ), text ] );
 		textProxy = new TextProxy( text, 2, 3 );
+
+		textNoParent = new Text( 'abcxyz' );
+		textProxyNoParent = new TextProxy( textNoParent, 1, 1 );
 	} );
 
 	it( 'should have data property', () => {
 		expect( textProxy ).to.have.property( 'data' ).that.equals( 'oba' );
+		expect( textProxyNoParent ).to.have.property( 'data' ).that.equals( 'b' );
 	} );
 
-	it( 'should have root', () => {
+	it( 'should have root property', () => {
 		expect( textProxy ).to.have.property( 'root' ).that.equals( root );
+		expect( textProxyNoParent ).to.have.property( 'root' ).that.equals( textNoParent );
 	} );
 
-	it( 'should have document', () => {
+	it( 'should have document property', () => {
 		expect( textProxy ).to.have.property( 'document' ).that.equals( doc );
+		expect( textProxyNoParent ).to.have.property( 'document' ).that.equals( null );
+	} );
+
+	it( 'should have parent property', () => {
+		expect( textProxy ).to.have.property( 'parent' ).that.equals( element );
+		expect( textProxyNoParent ).to.have.property( 'parent' ).that.equals( null );
+	} );
+
+	it( 'should have textNode property', () => {
+		expect( textProxy ).to.have.property( 'textNode' ).that.equals( text );
+		expect( textProxyNoParent ).to.have.property( 'textNode' ).that.equals( textNoParent );
+	} );
+
+	it( 'should have startOffset property', () => {
+		expect( textProxy ).to.have.property( 'startOffset' ).that.equals( 5 );
+		expect( textProxyNoParent ).to.have.property( 'startOffset' ).that.is.null;
+	} );
+
+	it( 'should have offsetSize property', () => {
+		expect( textProxy ).to.have.property( 'offsetSize' ).that.equals( 3 );
+		expect( textProxyNoParent ).to.have.property( 'offsetSize' ).that.equals( 1 );
+	} );
+
+	it( 'should have endOffset property', () => {
+		expect( textProxy ).to.have.property( 'endOffset' ).that.equals( 8 );
+		expect( textProxyNoParent ).to.have.property( 'endOffset' ).that.equals( null );
+	} );
+
+	it( 'should have offsetInText property', () => {
+		expect( textProxy ).to.have.property( 'offsetInText' ).that.equals( 2 );
+		expect( textProxyNoParent ).to.have.property( 'offsetInText' ).that.equals( 1 );
 	} );
 
 	describe( 'getPath', () => {
 		it( 'should return path to the text proxy', () => {
-			expect( textProxy.getPath() ).to.deep.equal( [ 0, 2 ] );
+			expect( textProxy.getPath() ).to.deep.equal( [ 0, 5 ] );
+			expect( textProxyNoParent.getPath() ).to.deep.equal( [] );
 		} );
 	} );
 
@@ -67,9 +104,15 @@ describe( 'TextProxy', () => {
 
 		describe( 'getAttributes', () => {
 			it( 'should return an iterator that iterates over all attributes set on the text proxy', () => {
-				let attrs = Array.from( textProxy.getAttributes() );
+				expect( Array.from( textProxy.getAttributes() ) ).to.deep.equal( [ [ 'foo', 'bar' ] ] );
+				expect( Array.from( textProxyNoParent.getAttributes() ) ).to.deep.equal( [] );
+			} );
+		} );
 
-				expect( attrs ).to.deep.equal( [ [ 'foo', 'bar' ] ] );
+		describe( 'getAttributeKeys', () => {
+			it( 'should return an iterator that iterates over all attribute keys set on the text proxy', () => {
+				expect( Array.from( textProxy.getAttributeKeys() ) ).to.deep.equal( [ 'foo' ] );
+				expect( Array.from( textProxyNoParent.getAttributeKeys() ) ).to.deep.equal( [] );
 			} );
 		} );
 	} );