r113386 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r113385‎ | r113386 | r113387 >
Date:19:35, 8 March 2012
Author:tparscal
Status:deferred
Tags:
Comment:
Added more tests for ve.dm.DocumentSynchronizer and fixed some bugs along the way
Modified paths:
  • /trunk/extensions/VisualEditor/modules/ve/dm/ve.dm.DocumentSynchronizer.js (modified) (history)
  • /trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentSynchronizer.test.js (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentSynchronizer.test.js
@@ -1,62 +1,159 @@
22 module( 've/dm' );
33
4 -test( 've.dm.TransactionSynchronizer', function() {
5 - var model,
6 - sync,
7 - node,
8 - data;
 4+test( 've.dm.TransactionSynchronizer', 9, function() {
 5+ var tests = {
 6+ // Test 1
 7+ 'resize actions adjust node lengths': {
 8+ 'actual': function( sync ) {
 9+ var model = sync.getModel();
 10+ // Delete bold "b" from first paragraph
 11+ model.data.splice( 2, 1 );
 12+ // Push resize action
 13+ sync.pushAction( 'resize', model.getChildren()[0], 0, -1 );
 14+ // Sync
 15+ sync.synchronize();
 16+ return model.getChildren()[0].getContentLength();
 17+ },
 18+ 'expected': 2
 19+ },
 20+ // Test 2
 21+ 'insert actions can add new nodes in the middle': {
 22+ 'actual': function( sync ) {
 23+ var model = sync.getModel(),
 24+ data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }],
 25+ node = ve.dm.DocumentNode.createNodesFromData( data )[0];
 26+ // Insert element after first paragraph
 27+ ve.insertIntoArray( model.data, 5, data );
 28+ // Push insertion action
 29+ sync.pushAction( 'insert', node, 5 );
 30+ // Sync
 31+ sync.synchronize();
 32+ return model.getChildren()[1].getContentData();
 33+ },
 34+ 'expected': ['x']
 35+ },
 36+ // Test 3
 37+ 'insert actions can add new nodes at the beginning': {
 38+ 'actual': function( sync ) {
 39+ var model = sync.getModel(),
 40+ data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }],
 41+ node = ve.dm.DocumentNode.createNodesFromData( data )[0];
 42+ // Insert element after first paragraph
 43+ ve.insertIntoArray( model.data, 0, data );
 44+ // Push insertion action
 45+ sync.pushAction( 'insert', node, 0 );
 46+ // Sync
 47+ sync.synchronize();
 48+ return model.getChildren()[0].getContentData();
 49+ },
 50+ 'expected': ['x']
 51+ },
 52+ // Test 4
 53+ 'insert actions can add new nodes at the end': {
 54+ 'actual': function( sync ) {
 55+ var model = sync.getModel(),
 56+ data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }],
 57+ node = ve.dm.DocumentNode.createNodesFromData( data )[0];
 58+ // Insert element after first paragraph
 59+ ve.insertIntoArray( model.data, 34, data );
 60+ // Push insertion action
 61+ sync.pushAction( 'insert', node, 34 );
 62+ // Sync
 63+ sync.synchronize();
 64+ return model.getChildren()[3].getContentData();
 65+ },
 66+ 'expected': ['x']
 67+ },
 68+ // Test 5
 69+ 'delete actions can remove nodes from the middle': {
 70+ 'actual': function( sync ) {
 71+ var model = sync.getModel(),
 72+ node = model.getChildren()[1];
 73+ // Delete the table
 74+ model.data.splice( 5, 26 );
 75+ // Push deletion action
 76+ sync.pushAction( 'delete', node, 5 );
 77+ // Sync
 78+ sync.synchronize();
 79+ return model.getChildren().length;
 80+ },
 81+ 'expected': 2
 82+ },
 83+ // Test 6
 84+ 'delete actions can remove nodes from the beginning': {
 85+ 'actual': function( sync ) {
 86+ var model = sync.getModel(),
 87+ node = model.getChildren()[0];
 88+ // Delete the first paragraph
 89+ model.data.splice( 0, 5 );
 90+ // Push deletion action
 91+ sync.pushAction( 'delete', node, 0 );
 92+ // Sync
 93+ sync.synchronize();
 94+ return model.getChildren().length;
 95+ },
 96+ 'expected': 2
 97+ },
 98+ // Test 7
 99+ 'delete actions can remove nodes from the end': {
 100+ 'actual': function( sync ) {
 101+ var model = sync.getModel(),
 102+ node = model.getChildren()[2];
 103+ // Delete the first paragraph
 104+ model.data.splice( 31, 3 );
 105+ // Push deletion action
 106+ sync.pushAction( 'delete', node, 31 );
 107+ // Sync
 108+ sync.synchronize();
 109+ return model.getChildren().length;
 110+ },
 111+ 'expected': 2
 112+ },
 113+ // Test 8
 114+ 'rebuild actions can convert element types': {
 115+ 'actual': function( sync ) {
 116+ var model = sync.getModel(),
 117+ node = model.getChildren()[0];
 118+ // Convert the first paragraph to a level 1 heading
 119+ model.data[0].type = 'heading';
 120+ model.data[0].attributes = { 'level': 1 };
 121+ model.data[4].type = '/heading';
 122+ // Push rebuild action
 123+ sync.pushAction( 'rebuild', node, 0 );
 124+ // Sync
 125+ sync.synchronize();
 126+ return model.getChildren()[0].getElementType();
 127+ },
 128+ 'expected': 'heading'
 129+ },
 130+ // Test 9
 131+ 'rebuild actions can replace one node with more than one node': {
 132+ 'actual': function( sync ) {
 133+ var model = sync.getModel(),
 134+ node = model.getChildren()[0],
 135+ data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }];
 136+ // Insert element after first paragraph
 137+ ve.insertIntoArray( model.data, 5, data );
 138+ // Push rebuild action with a length adustment of 3 to account for the new element
 139+ sync.pushAction( 'rebuild', node, 0, 3 );
 140+ // Sync
 141+ sync.synchronize();
 142+ return model.getChildren()[1].getContentData();
 143+ },
 144+ 'expected': ['x']
 145+ }
 146+ };
9147
10 - // Test 1 - node resizing
11 -
12 - model = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
13 - sync = new ve.dm.DocumentSynchronizer( model );
14 - // Delete bold "b" from first paragraph
15 - model.data.splice( 2, 1 );
16 - // Push resize action
17 - sync.pushAction( 'resize', model.getChildren()[0], 0, -1 );
18 - // Sync
19 - sync.synchronize();
20 - equal( model.getChildren()[0].getContentLength(), 2, 'resize actions adjust node lengths' );
21 -
22 - // Test 2 - node insertion (in the middle)
23 -
24 - model = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
25 - sync = new ve.dm.DocumentSynchronizer( model );
26 - // Insert element after first paragraph
27 - data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }];
28 - node = ve.dm.DocumentNode.createNodesFromData( data )[0];
29 - ve.insertIntoArray( model.data, 5, data );
30 - // Push insertion action
31 - sync.pushAction( 'insert', node, 5 );
32 - // Sync
33 - sync.synchronize();
34 - deepEqual( model.getChildren()[1].getContentData(), ['x'], 'insert actions add new nodes' );
35 -
36 - // Test 3 - node insertion (at the start)
37 -
38 - model = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
39 - sync = new ve.dm.DocumentSynchronizer( model );
40 - // Insert element after first paragraph
41 - data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }];
42 - node = ve.dm.DocumentNode.createNodesFromData( data )[0];
43 - ve.insertIntoArray( model.data, 0, data );
44 - // Push insertion action
45 - sync.pushAction( 'insert', node, 0 );
46 - // Sync
47 - sync.synchronize();
48 - deepEqual( model.getChildren()[0].getContentData(), ['x'], 'insert actions add new nodes' );
49 -
50 - // Test 4 - node insertion (at the end)
51 - model = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
52 - sync = new ve.dm.DocumentSynchronizer( model );
53 - // Insert element after first paragraph
54 - data = [{ 'type': 'paragraph' }, 'x', { 'type': '/paragraph' }];
55 - node = ve.dm.DocumentNode.createNodesFromData( data )[0];
56 - ve.insertIntoArray( model.data, 34, data );
57 - // Push insertion action
58 - sync.pushAction( 'insert', node, 34 );
59 - // Sync
60 - sync.synchronize();
61 - deepEqual( model.getChildren()[3].getContentData(), ['x'], 'insert actions add new nodes' );
 148+ // Run tests
 149+ for ( var test in tests ) {
 150+ deepEqual(
 151+ tests[test].actual(
 152+ new ve.dm.DocumentSynchronizer(
 153+ ve.dm.DocumentNode.newFromPlainObject( veTest.obj )
 154+ )
 155+ ),
 156+ tests[test].expected,
 157+ test
 158+ );
 159+ }
62160 } );
63 -
Index: trunk/extensions/VisualEditor/modules/ve/dm/ve.dm.DocumentSynchronizer.js
@@ -15,6 +15,10 @@
1616
1717 /* Methods */
1818
 19+ve.dm.DocumentSynchronizer.prototype.getModel = function() {
 20+ return this.model;
 21+};
 22+
1923 /**
2024 * Adds an action to the synchronizer.
2125 *
@@ -72,19 +76,23 @@
7377 case 'delete':
7478 // Replace original node with new node
7579 parent = action.node.getParent();
76 - parentNode.splice( parentNode.indexOf( action.node ), 1 );
 80+ parent.splice( parent.indexOf( action.node ), 1 );
7781 // Adjust proceeding offsets negatively by the length of the node being deleted
7882 adjustment -= action.node.getElementLength();
7983 break;
8084 case 'rebuild':
8185 // Replace original node with new node
82 - var newNode = ve.dm.DocumentNode.createNodesFromData( this.model.getData(
 86+ var newNodes = ve.dm.DocumentNode.createNodesFromData( this.model.getData(
8387 new ve.Range( offset, action.node.getElementLength() + action.adjustment )
8488 ) );
8589 parent = action.node.getParent();
86 - parentNode.splice( parentNode.indexOf( action.node ), 1, newNode );
 90+ parent.splice.apply( parent, [parent.indexOf( action.node ), 1].concat( newNodes ) );
8791 // Adjust proceeding offsets by the difference between the original and new nodes
88 - adjustment += newNode.getElementLength() - action.node.getElementLength();
 92+ var newNodesLength = 0;
 93+ for ( var j = 0, jlen = newNodes.length; j < jlen; j++ ) {
 94+ newNodesLength += newNodes[j].getElementLength();
 95+ }
 96+ adjustment += newNodesLength - action.node.getElementLength();
8997 break;
9098 case 'resize':
9199 // Adjust node length - causes update events to be emitted

Status & tagging log