DIR : /home/kozerus/public_html/pn/uize/site-source/js/Uize/Test/Uize/Data/Diff.js

/home/kozerus/public_html/pn/uize/site-source/js/Uize/Test/Uize/Data

/*______________
|       ______  |   U I Z E    J A V A S C R I P T    F R A M E W O R K
|     /      /  |   ---------------------------------------------------
|    /    O /   |    MODULE : Uize.Test.Uize.Data.Diff Class
|   /    / /    |
|  /    / /  /| |    ONLINE : http://www.uize.com
| /____/ /__/_| | COPYRIGHT : (c)2014-2016 UIZE
|          /___ |   LICENSE : Available under MIT License or GNU General Public License
|_______________|             http://www.uize.com/license.html
*/

/* Module Meta Data
	type: Test
	importance: 1
	codeCompleteness: 100
	docCompleteness: 100
*/

/*?
	Introduction
		The =Uize.Test.Uize.Data.Diff= module defines a suite of unit tests for the =Uize.Data.Diff= module.

		*DEVELOPERS:* `Chris van Rensburg`
*/

Uize.module ({
	name:'Uize.Test.Uize.Data.Diff',
	required:'Uize.Test',
	builder:function () {
		'use strict';

		function _addedOrModifiedValuesPropertyComparer (_object1Property,_object2Property) {
			return (
				_object2Property && (!_object1Property || _object2Property.value !== _object1Property.value)
					? _object2Property
					: undefined
			);
		}

		function _addedPropertyComparer (_object1Property,_object2Property) {
			return !_object1Property && _object2Property ? {value:'added'} : undefined;
		}

		function _modifiedPropertyComparer (_object1Property,_object2Property) {
			return (
				_object1Property && _object2Property && _object1Property.value !== _object2Property.value
					? {value:'modified'}
					: undefined
			);
		}

		function _removedPropertyComparer (_object1Property,_object2Property) {
			return _object1Property && !_object2Property ? {value:'removed'} : undefined;
		}

		function _unmodifiedPropertyComparer (_object1Property,_object2Property) {
			return (
				_object1Property && _object2Property && _object1Property.value === _object2Property.value
					? {value:'unchanged'}
					: undefined
			);
		}

		return Uize.Test.resolve ({
			title:'Test for Uize.Data.Diff Module',
			test:[
				Uize.Test.requiredModulesTest ('Uize.Data.Diff'),
				Uize.Test.staticMethodsTest ([
					['Uize.Data.Diff.diff',[
						/*** test the default property comparer ***/
							['With the default property comparer, modified properties are marked by the value "modified"',
								[
									{foo:'bar'},
									{foo:'BAR'}
								],
								{foo:'modified'}
							],
							['With the default property comparer, added properties are marked by the value "added"',
								[
									{},
									{foo:'bar'}
								],
								{foo:'added'}
							],
							['With the default property comparer, removed properties are marked by the value "removed"',
								[
									{foo:'bar'},
									{}
								],
								{foo:'removed'}
							],
							['With the default property comparer, unmodified properties are marked by the value "unchanged"',
								[
									{foo:'bar'},
									{foo:'bar'}
								],
								{foo:'unchanged'}
							],
							['An arbitrarily complex data structure can be diff\'ed',
								[
									{
										prop1:'foo',
										prop2:'bar',
										prop4:{
											prop1:'foo',
											prop2:'bar'
										},
										prop6:{
											prop1:'foo',
											prop2:'bar',
											prop3:'baz'
										}
									},
									{
										prop1:'FOO',
										prop3:'bar',
										prop5:{
											prop1:'foo',
											prop2:'bar'
										},
										prop6:{
											prop1:'foo',
											prop2:'BAR',
											prop4:'qux'
										}
									}
								],
								{
									prop1:'modified',
									prop2:'removed',
									prop3:'added',
									prop4:{
										prop1:'removed',
										prop2:'removed'
									},
									prop5:{
										prop1:'added',
										prop2:'added'
									},
									prop6:{
										prop1:'unchanged',
										prop2:'modified',
										prop3:'removed',
										prop4:'added'
									}
								}
							],

							/*** test array diffing ***/
								['When the value of a property in both objects being compared is an array, then all the elements of the two array values will be compared',
									[
										{array:['foo','bar']},
										{array:['foo','baz','qux']}
									],
									{array:['unchanged','modified','added']}
								],
								['When the value of a property is an array in the first object and missing in the second object, all the values from the array in the first object will appear to have been removed',
									[
										{array:['foo','bar','baz','qux']},
										{}
									],
									{array:['removed','removed','removed','removed']}
								],
								['When the value of a property is an array in the second object and missing in the first object, all the values from the array in the second object will appear to have been added',
									[
										{},
										{array:['foo','bar','baz','qux']}
									],
									{array:['added','added','added','added']}
								],

							/*** test the skeleton option ***/
								['When the value false is specified for the optional skeleton option, then the returned comparison result will not contain empty nodes in which there are no property comparison values',
									[
										{
											foo:{
												bar:{},
												baz:{
													qux:[]
												}
											}
										},
										{
											foo:{
												BAR:{
													BAZ:[]
												}
											},
											QUX:{}
										},
										{skeleton:false}
									],
									{}
								],
								['When the value true is specified for the optional skeleton option, then the returned comparison result will at a minimum be a skeleton object that is the union of the structures of the two objects being compared',
									[
										{
											foo:{
												bar:{},
												baz:{
													qux:[]
												}
											}
										},
										{
											foo:{
												BAR:{
													BAZ:[]
												}
											},
											QUX:{}
										},
										null,
										{skeleton:true}
									],
									{
										foo:{
											bar:{},
											baz:{
												qux:[]
											},
											BAR:{
												BAZ:[]
											}
										},
										QUX:{}
									}
								],
								['When no value is specified for the optional skeleton option, it is defaulted to false and the skeleton behavior is disabled',
									[
										{
											foo:{
												bar:{},
												baz:{
													qux:[]
												}
											}
										},
										{
											foo:{
												BAR:{
													BAZ:[]
												}
											},
											QUX:{}
										},
										null,
										{}
									],
									{}
								],

							/*** test the dual option ***/
								['When the value false is specified for the optional dual option, then the recursion is driven by the first object',
									[
										{
											foo:{
												bar:{0:'fee',2:'FO',3:'fum'},
												BAR:['fee','fi','fo'],
												baz:{
													qux:'nux',
													dux:['bux','pux']
												}
											},
											hello:5
										},
										{
											foo:{
												bar:['fee','fi','fo'],
												BAR:{0:'fee',2:'FO',3:'fum'},
												baz:'baz'
											},
											hello:{
												thebird:['is','the','word']
											}
										},
										null,
										{dual:false,skeleton:true}
									],
									{
										foo:{
											bar:{0:'removed',2:'removed',3:'removed'},
											BAR:['removed','removed','removed'],
											baz:{
												qux:'removed',
												dux:['removed','removed']
											}
										},
										hello:'modified'
									}
								],
								['When a non-dual diff is performed, properties in object B whose values are not arrays when the values of the corresponding properties in object A are arrays are treated as being empty arrays for the purpose of the diff recursion',
									[
										{
											prop1:['foo','bar'],
											prop2:['foo','bar'],
											prop3:['foo','bar'],
											prop4:['foo','bar'],
											prop5:['foo','bar'],
											prop6:['foo','bar'],
											prop7:['foo','bar']
										},
										{
											prop1:42,
											prop2:false,
											prop3:'foo',
											prop4:{foo:'bar'},
											prop5:null,
											prop6:/\d+/
										},
										null,
										{dual:false}
									],
									{
										prop1:['removed','removed'],
										prop2:['removed','removed'],
										prop3:['removed','removed'],
										prop4:['removed','removed'],
										prop5:['removed','removed'],
										prop6:['removed','removed'],
										prop7:['removed','removed']
									}
								],
								['When a non-dual diff is performed, properties in object B whose values are not plain objects when the values of the corresponding properties in object A are plain objects are treated as being empty objects for the purpose of the diff recursion',
									[
										{
											prop1:{foo:'FOO',bar:'BAR'},
											prop2:{foo:'FOO',bar:'BAR'},
											prop3:{foo:'FOO',bar:'BAR'},
											prop4:{foo:'FOO',bar:'BAR'},
											prop5:{foo:'FOO',bar:'BAR'},
											prop6:{foo:'FOO',bar:'BAR'},
											prop7:{foo:'FOO',bar:'BAR'}
										},
										{
											prop1:42,
											prop2:false,
											prop3:'foo',
											prop4:['foo','bar'],
											prop5:null,
											prop6:/\d+/
										},
										null,
										{dual:false}
									],
									{
										prop1:{foo:'removed',bar:'removed'},
										prop2:{foo:'removed',bar:'removed'},
										prop3:{foo:'removed',bar:'removed'},
										prop4:{foo:'removed',bar:'removed'},
										prop5:{foo:'removed',bar:'removed'},
										prop6:{foo:'removed',bar:'removed'},
										prop7:{foo:'removed',bar:'removed'}
									}
								],
								['When performing a non-dual diff, properties in object B whose values are arrays or objects, when the values of the corresponding properties in object A are non-object types, are not recursed and are compared directly against the values in object A',
									[
										{
											prop1:42,
											prop2:false,
											prop3:'foo',
											prop4:undefined,
											prop5:null,
											prop6:/\d+/
										},
										{
											prop1:{foo:'FOO',bar:'BAR'},
											prop2:{foo:'FOO',bar:'BAR'},
											prop3:{foo:'FOO',bar:'BAR'},
											prop4:{foo:'FOO',bar:'BAR'},
											prop5:{foo:'FOO',bar:'BAR'},
											prop6:{foo:'FOO',bar:'BAR'}
										},
										null,
										{dual:false}
									],
									{
										prop1:'modified',
										prop2:'modified',
										prop3:'modified',
										prop4:'modified',
										prop5:'modified',
										prop6:'modified'
									}
								],
								['When performing a non-dual diff, properties that are present in objects in object B that are not present in the corresponding objects in object A are not iterated over',
									[
										{
											foo:{foo:'FOO',bar:'BAR'}
										},
										{
											foo:{foo:'FOO!',bar:'BAR',baz:'BAZ',qux:'QUX'}
										},
										null,
										{dual:false}
									],
									{
										foo:{foo:'modified',bar:'unchanged'}
									}
								],
								['When performing a non-dual diff, elements that are present in arrays in object B that are not present in the corresponding arrays in object A are not iterated over',
									[
										{
											foo:['FOO','BAR']
										},
										{
											foo:['FOO!','BAR','BAZ','QUX']
										},
										null,
										{dual:false}
									],
									{
										foo:['modified','unchanged']
									}
								],
								['When the value true is specified explicitly for the optional dual option, then the standard dual diff is performed',
									[
										{
											prop1:{foo:'FOO',bar:'BAR'},
											prop2:['FOO','BAR']
										},
										{
											prop1:{foo:'FOO!',bar:'BAR',baz:'BAZ',qux:'QUX'},
											prop2:['FOO!','BAR','BAZ','QUX']
										},
										null,
										{dual:true}
									],
									{
										prop1:{foo:'modified',bar:'unchanged',baz:'added',qux:'added'},
										prop2:['modified','unchanged','added','added']
									}
								],

						/*** test a custom added-or-modified property comparer ***/
							['With a custom added-or-modified property comparer, modified properties are marked by their new value',
								[
									{foo:'bar'},
									{foo:'BAR'},
									_addedOrModifiedValuesPropertyComparer
								],
								{foo:'BAR'}
							],
							['With a custom added-or-modified property comparer, added properties are marked by their new value',
								[
									{},
									{foo:'bar'},
									_addedOrModifiedValuesPropertyComparer
								],
								{foo:'bar'}
							],
							['With a custom added-or-modified property comparer, removed properties are omitted from the result',
								[
									{foo:'bar'},
									{},
									_addedOrModifiedValuesPropertyComparer
								],
								{}
							],
							['With a custom added-or-modified property comparer, unmodified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'bar'},
									_addedOrModifiedValuesPropertyComparer
								],
								{}
							],

						/*** test a custom added property comparer ***/
							['With a custom added property comparer, modified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'BAR'},
									_addedPropertyComparer
								],
								{}
							],
							['With a custom added property comparer, added properties are marked by the value "added"',
								[
									{},
									{foo:'bar'},
									_addedPropertyComparer
								],
								{foo:'added'}
							],
							['With a custom added property comparer, removed properties are omitted from the result',
								[
									{foo:'bar'},
									{},
									_addedPropertyComparer
								],
								{}
							],
							['With a custom added property comparer, unmodified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'bar'},
									_addedPropertyComparer
								],
								{}
							],

						/*** test a custom modified property comparer ***/
							['With a custom modified property comparer, modified properties are marked by the value "modified"',
								[
									{foo:'bar'},
									{foo:'BAR'},
									_modifiedPropertyComparer
								],
								{foo:'modified'}
							],
							['With a custom modified property comparer, added properties are omitted from the result',
								[
									{},
									{foo:'bar'},
									_modifiedPropertyComparer
								],
								{}
							],
							['With a custom modified property comparer, removed properties are omitted from the result',
								[
									{foo:'bar'},
									{},
									_modifiedPropertyComparer
								],
								{}
							],
							['With a custom modified property comparer, unmodified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'bar'},
									_modifiedPropertyComparer
								],
								{}
							],

						/*** test a custom removed property comparer ***/
							['With a custom removed property comparer, modified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'BAR'},
									_removedPropertyComparer
								],
								{}
							],
							['With a custom removed property comparer, added properties are omitted from the result',
								[
									{},
									{foo:'bar'},
									_removedPropertyComparer
								],
								{}
							],
							['With a custom removed property comparer, removed properties are marked by the value "removed"',
								[
									{foo:'bar'},
									{},
									_removedPropertyComparer
								],
								{foo:'removed'}
							],
							['With a custom removed property comparer, unmodified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'bar'},
									_removedPropertyComparer
								],
								{}
							],

						/*** test a custom unmodified property comparer ***/
							['With a custom unmodified property comparer, modified properties are omitted from the result',
								[
									{foo:'bar'},
									{foo:'BAR'},
									_unmodifiedPropertyComparer
								],
								{}
							],
							['With a custom unmodified property comparer, added properties are omitted from the result',
								[
									{},
									{foo:'bar'},
									_unmodifiedPropertyComparer
								],
								{}
							],
							['With a custom unmodified property comparer, removed properties are omitted from the result',
								[
									{foo:'bar'},
									{},
									_unmodifiedPropertyComparer
								],
								{}
							],
							['With a custom unmodified property comparer, unmodified properties are marked by the value "unchanged"',
								[
									{foo:'bar'},
									{foo:'bar'},
									_unmodifiedPropertyComparer
								],
								{foo:'unchanged'}
							],

						/*** miscellaneous tests ***/
							['The property info arguments that are provided to the property comparer function each contain a key property which indicates the name of the current property being compared',
								[
									{
										foo:'FOO',
										bar:{baz:'BAZ'}
									},
									{
										qux:'QUX',
										hello:{world:'WORLD'}
									},
									function (_object1PropertyInfo,_object2PropertyInfo) {
										return {
											value:[
												_object1PropertyInfo && _object1PropertyInfo.key,
												_object2PropertyInfo && _object2PropertyInfo.key
											]
										};
									}
								],
								{
									foo:['foo',undefined],
									bar:{
										baz:['baz',undefined]
									},
									qux:[undefined,'qux'],
									hello:{
										world:[undefined,'world']
									}
								}
							],
							{
								title:'The property comparer function is passed a third argument, whose value is an array representing the path to the current property being compared',
								test:function () {
									var _comparedPropertiesPaths = [];
									Uize.Data.Diff.diff (
										{
											prop1:'foo',
											prop2:'bar',
											prop4:{
												prop1:'foo',
												prop2:'bar'
											},
											prop6:{
												prop1:'foo',
												prop2:'bar',
												prop3:'baz',
												prop5:['foo','bar','baz']
											}
										},
										{
											prop1:'FOO',
											prop3:'bar',
											prop5:{
												prop1:'foo',
												prop2:'bar'
											},
											prop6:{
												prop1:'foo',
												prop2:'BAR',
												prop4:'qux',
												prop5:['foo']
											},
											prop7:['foo','bar']
										},
										function (_object1PropertyInfo,_object2PropertyInfo,_path) {
											_comparedPropertiesPaths.push (_path.concat ());
										}
									);
									return this.expect (
										[
											['prop1'],
											['prop2'],
											['prop4','prop1'],
											['prop4','prop2'],
											['prop6','prop1'],
											['prop6','prop2'],
											['prop6','prop3'],
											['prop6','prop5',0],
											['prop6','prop5',1],
											['prop6','prop5',2],
											['prop6','prop4'],
											['prop3'],
											['prop5','prop1'],
											['prop5','prop2'],
											['prop7',0],
											['prop7',1]
										],
										_comparedPropertiesPaths
									);
								}
							},
							['The key property in the property profile object returned by a property comparer function is used to determine the name of the property added to the diff result',
								[
									{
										leafNode1:'foo',
										leafNode2:'bar',
										nonLeadNode1:{
											leafNode1:'foo',
											leadNode2:'bar'
										},
										nonLeafNode2:{
											leafNode1:'foo',
											leafNode2:'bar',
											nonLeafNode1:{
												leafNode1:'foo',
												leadNode2:'bar'
											}
										}
									},
									{},
									function (_propertyProfile) {
										_propertyProfile.key = _propertyProfile.key.toUpperCase ();
										return _propertyProfile;
									}
								],
								{
									LEAFNODE1:'foo',
									LEAFNODE2:'bar',
									nonLeadNode1:{
										LEAFNODE1:'foo',
										LEADNODE2:'bar'
									},
									nonLeafNode2:{
										LEAFNODE1:'foo',
										LEAFNODE2:'bar',
										nonLeafNode1:{
											LEAFNODE1:'foo',
											LEADNODE2:'bar'
										}
									}
								}
							],
							['When a property in one object is a leaf node and the corresponding property in the other object is a non-leaf node, then the non-leaf node is recursed as if the leaf node was a non-leaf node',
								[
									{
										foo:{hello:1,world:2},
										bar:{hello:1,world:2},
										baz:{hello:1,world:2},
										FOO:'foo',
										BAR:2,
										BAZ:false
									},
									{
										foo:'foo',
										bar:2,
										baz:false,
										FOO:{hello:1,world:2},
										BAR:{hello:1,world:2},
										BAZ:{hello:1,world:2}
									},
									function (_object1PropertyInfo,_object2PropertyInfo) {
										return _object1PropertyInfo || _object2PropertyInfo;
									}
								],
								{
									foo:{hello:1,world:2},
									bar:{hello:1,world:2},
									baz:{hello:1,world:2},
									FOO:{hello:1,world:2},
									BAR:{hello:1,world:2},
									BAZ:{hello:1,world:2}
								}
							]
					]]
				])
			]
		});
	}
});

//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer