2013-07-03 01:30:10 +00:00
|
|
|
/*!
|
|
|
|
* VisualEditor DataModel MediaWiki-specific InternalList tests.
|
|
|
|
*
|
2015-01-08 23:54:03 +00:00
|
|
|
* @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
|
2013-07-03 01:30:10 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
2015-05-17 09:37:34 +00:00
|
|
|
QUnit.module( 've.dm.InternalList (MW)', ve.test.utils.mwEnvironment );
|
2013-07-03 01:30:10 +00:00
|
|
|
|
|
|
|
/* Tests */
|
|
|
|
|
2013-09-19 22:57:08 +00:00
|
|
|
QUnit.test( 'addNode/removeNode', 6, function ( assert ) {
|
2013-07-03 01:30:10 +00:00
|
|
|
var doc = ve.dm.mwExample.createExampleDocument( 'references' ),
|
|
|
|
newInternalList = new ve.dm.InternalList( doc ),
|
|
|
|
referenceNodes = [
|
2015-08-19 17:33:02 +00:00
|
|
|
doc.getDocumentNode().children[ 0 ].children[ 0 ],
|
|
|
|
doc.getDocumentNode().children[ 1 ].children[ 1 ],
|
|
|
|
doc.getDocumentNode().children[ 1 ].children[ 3 ],
|
|
|
|
doc.getDocumentNode().children[ 1 ].children[ 5 ],
|
|
|
|
doc.getDocumentNode().children[ 2 ].children[ 0 ],
|
|
|
|
doc.getDocumentNode().children[ 2 ].children[ 1 ]
|
2013-07-03 01:30:10 +00:00
|
|
|
],
|
|
|
|
expectedNodes = {
|
|
|
|
'mwReference/': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/0': [ referenceNodes[ 0 ] ],
|
|
|
|
'literal/bar': [ referenceNodes[ 1 ], referenceNodes[ 3 ] ],
|
|
|
|
'literal/:3': [ referenceNodes[ 2 ] ],
|
|
|
|
'auto/1': [ referenceNodes[ 4 ] ]
|
2013-07-03 01:30:10 +00:00
|
|
|
},
|
2014-08-22 20:50:48 +00:00
|
|
|
firstNodes: [
|
2015-08-19 17:33:02 +00:00
|
|
|
referenceNodes[ 0 ],
|
|
|
|
referenceNodes[ 1 ],
|
|
|
|
referenceNodes[ 2 ],
|
|
|
|
referenceNodes[ 4 ]
|
2013-07-03 01:30:10 +00:00
|
|
|
],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 0, 1, 2, 3 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
|
|
|
'mwReference/foo': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/2': [ referenceNodes[ 5 ] ]
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
2015-08-19 17:33:02 +00:00
|
|
|
firstNodes: [ undefined, undefined, undefined, undefined, referenceNodes[ 5 ] ],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 4 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-07-03 01:30:10 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-19 22:57:08 +00:00
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
doc.internalList.nodes,
|
|
|
|
expectedNodes,
|
|
|
|
'Document construction populates internal list correctly'
|
|
|
|
);
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
newInternalList.addNode( 'mwReference/', 'auto/0', 0, referenceNodes[ 0 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 1 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/:3', 2, referenceNodes[ 2 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 3 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'auto/1', 3, referenceNodes[ 4 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/foo', 'auto/2', 4, referenceNodes[ 5 ] );
|
2013-07-03 01:30:10 +00:00
|
|
|
newInternalList.onTransact();
|
|
|
|
|
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
newInternalList.nodes,
|
|
|
|
expectedNodes,
|
|
|
|
'Nodes added in order'
|
|
|
|
);
|
|
|
|
|
|
|
|
newInternalList = new ve.dm.InternalList( doc );
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
newInternalList.addNode( 'mwReference/foo', 'auto/2', 4, referenceNodes[ 5 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'auto/1', 3, referenceNodes[ 4 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 3 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/:3', 2, referenceNodes[ 2 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 1 ] );
|
|
|
|
newInternalList.addNode( 'mwReference/', 'auto/0', 0, referenceNodes[ 0 ] );
|
2013-07-03 01:30:10 +00:00
|
|
|
newInternalList.onTransact();
|
|
|
|
|
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
newInternalList.nodes,
|
|
|
|
expectedNodes,
|
|
|
|
'Nodes added in reverse order'
|
|
|
|
);
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
newInternalList.removeNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 1 ] );
|
2013-07-03 01:30:10 +00:00
|
|
|
newInternalList.onTransact();
|
|
|
|
|
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
newInternalList.nodes,
|
|
|
|
{
|
|
|
|
'mwReference/': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/0': [ referenceNodes[ 0 ] ],
|
|
|
|
'literal/bar': [ referenceNodes[ 3 ] ],
|
|
|
|
'literal/:3': [ referenceNodes[ 2 ] ],
|
|
|
|
'auto/1': [ referenceNodes[ 4 ] ]
|
2013-07-03 01:30:10 +00:00
|
|
|
},
|
2014-08-22 20:50:48 +00:00
|
|
|
firstNodes: [
|
2015-08-19 17:33:02 +00:00
|
|
|
referenceNodes[ 0 ],
|
|
|
|
referenceNodes[ 3 ],
|
|
|
|
referenceNodes[ 2 ],
|
|
|
|
referenceNodes[ 4 ]
|
2013-07-03 01:30:10 +00:00
|
|
|
],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 0, 2, 1, 3 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
|
|
|
'mwReference/foo': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/2': [ referenceNodes[ 5 ] ]
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
2015-08-19 17:33:02 +00:00
|
|
|
firstNodes: [ undefined, undefined, undefined, undefined, referenceNodes[ 5 ] ],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 4 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-07-03 01:30:10 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
'Keys re-ordered after one item of key removed'
|
|
|
|
);
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
newInternalList.removeNode( 'mwReference/', 'literal/bar', 1, referenceNodes[ 3 ] );
|
2013-07-03 01:30:10 +00:00
|
|
|
newInternalList.onTransact();
|
|
|
|
|
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
newInternalList.nodes,
|
|
|
|
{
|
|
|
|
'mwReference/': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/0': [ referenceNodes[ 0 ] ],
|
|
|
|
'literal/:3': [ referenceNodes[ 2 ] ],
|
|
|
|
'auto/1': [ referenceNodes[ 4 ] ]
|
2013-07-03 01:30:10 +00:00
|
|
|
},
|
2014-08-22 20:50:48 +00:00
|
|
|
firstNodes: [
|
2015-08-19 17:33:02 +00:00
|
|
|
referenceNodes[ 0 ],
|
2013-07-03 01:30:10 +00:00
|
|
|
undefined,
|
2015-08-19 17:33:02 +00:00
|
|
|
referenceNodes[ 2 ],
|
|
|
|
referenceNodes[ 4 ]
|
2013-07-03 01:30:10 +00:00
|
|
|
],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 0, 2, 3 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
|
|
|
'mwReference/foo': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {
|
2015-08-19 17:33:02 +00:00
|
|
|
'auto/2': [ referenceNodes[ 5 ] ]
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
2015-08-19 17:33:02 +00:00
|
|
|
firstNodes: [ undefined, undefined, undefined, undefined, referenceNodes[ 5 ] ],
|
2014-08-22 20:50:48 +00:00
|
|
|
indexOrder: [ 4 ],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-07-03 01:30:10 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
'Keys truncated after last item of key removed'
|
|
|
|
);
|
|
|
|
|
2015-08-19 17:33:02 +00:00
|
|
|
newInternalList.removeNode( 'mwReference/', 'auto/0', 0, referenceNodes[ 0 ] );
|
|
|
|
newInternalList.removeNode( 'mwReference/foo', 'auto/2', 4, referenceNodes[ 5 ] );
|
|
|
|
newInternalList.removeNode( 'mwReference/', 'auto/1', 3, referenceNodes[ 4 ] );
|
|
|
|
newInternalList.removeNode( 'mwReference/', 'literal/:3', 2, referenceNodes[ 2 ] );
|
2013-07-03 01:30:10 +00:00
|
|
|
newInternalList.onTransact();
|
|
|
|
|
|
|
|
assert.deepEqualWithNodeTree(
|
|
|
|
newInternalList.nodes,
|
|
|
|
{
|
|
|
|
'mwReference/': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {},
|
|
|
|
firstNodes: new Array( 4 ),
|
|
|
|
indexOrder: [],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-09-19 22:57:08 +00:00
|
|
|
},
|
|
|
|
'mwReference/foo': {
|
2014-08-22 20:50:48 +00:00
|
|
|
keyedNodes: {},
|
|
|
|
firstNodes: new Array( 5 ),
|
|
|
|
indexOrder: [],
|
|
|
|
uniqueListKeys: {},
|
|
|
|
uniqueListKeysInUse: {}
|
2013-07-03 01:30:10 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
'All nodes removed'
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
|
|
|
|
QUnit.test( 'getItemInsertion', 4, function ( assert ) {
|
|
|
|
var insertion, index,
|
|
|
|
doc = ve.dm.mwExample.createExampleDocument( 'references' ),
|
|
|
|
internalList = doc.getInternalList();
|
|
|
|
|
2013-09-19 22:57:08 +00:00
|
|
|
insertion = internalList.getItemInsertion( 'mwReference/', 'literal/foo', [] );
|
2013-07-03 01:30:10 +00:00
|
|
|
index = internalList.getItemNodeCount();
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( insertion.index, index, 'Insertion creates a new reference' );
|
2013-07-03 01:30:10 +00:00
|
|
|
assert.deepEqual(
|
|
|
|
insertion.transaction.getOperations(),
|
|
|
|
[
|
2014-08-22 20:50:48 +00:00
|
|
|
{ type: 'retain', length: 91 },
|
2013-07-03 01:30:10 +00:00
|
|
|
{
|
2014-08-22 20:50:48 +00:00
|
|
|
type: 'replace',
|
|
|
|
remove: [],
|
|
|
|
insert: [
|
|
|
|
{ type: 'internalItem' },
|
|
|
|
{ type: '/internalItem' }
|
2014-06-13 13:15:03 +00:00
|
|
|
],
|
2014-08-22 20:50:48 +00:00
|
|
|
insertedDataOffset: 0,
|
|
|
|
insertedDataLength: 2
|
2013-07-03 01:30:10 +00:00
|
|
|
},
|
2014-08-22 20:50:48 +00:00
|
|
|
{ type: 'retain', length: 1 }
|
2013-07-03 01:30:10 +00:00
|
|
|
],
|
|
|
|
'New reference operations match' );
|
|
|
|
|
2013-09-19 22:57:08 +00:00
|
|
|
insertion = internalList.getItemInsertion( 'mwReference/', 'literal/foo', [] );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( insertion.index, index, 'Insertion with duplicate key reuses old index' );
|
|
|
|
assert.strictEqual( insertion.transaction, null, 'Insertion with duplicate key has null transaction' );
|
2013-07-03 01:30:10 +00:00
|
|
|
} );
|
2013-09-19 22:57:08 +00:00
|
|
|
|
|
|
|
QUnit.test( 'getUniqueListKey', 7, function ( assert ) {
|
|
|
|
var generatedName,
|
|
|
|
doc = ve.dm.mwExample.createExampleDocument( 'references' ),
|
|
|
|
internalList = doc.getInternalList();
|
|
|
|
|
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/0', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:0', '0 maps to 0' );
|
2013-09-19 22:57:08 +00:00
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/1', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:1', '1 maps to 1' );
|
2013-09-19 22:57:08 +00:00
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/2', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:2', '2 maps to 2' );
|
2013-09-19 22:57:08 +00:00
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/3', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:4', '3 maps to 4 (because a literal :3 is present)' );
|
2013-09-19 22:57:08 +00:00
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/4', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:5', '4 maps to 5' );
|
2013-09-19 22:57:08 +00:00
|
|
|
|
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/', 'auto/0', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:0', 'Reusing a key reuses the name' );
|
2013-09-19 22:57:08 +00:00
|
|
|
|
|
|
|
generatedName = internalList.getUniqueListKey( 'mwReference/foo', 'auto/4', 'literal/:' );
|
2014-09-11 17:50:44 +00:00
|
|
|
assert.strictEqual( generatedName, 'literal/:0', 'Different groups are treated separately' );
|
2013-12-06 02:34:44 +00:00
|
|
|
} );
|