Implement unit test comparator for Item & co + Project, and further improve new comparator code.

This commit is contained in:
Jürg Lehni 2014-12-28 18:10:53 +01:00
parent 1de750bc77
commit 644fb71dc1
4 changed files with 132 additions and 168 deletions

View file

@ -27,6 +27,34 @@ QUnit.jsDump.setParser('object', function (obj, stack) {
: objectParser).call(this, obj, stack);
});
function compareProperties(actual, expected, properties, message, options) {
Base.each(properties, function(key) {
equals(actual[key], expected[key], message + '.' + key, options);
});
}
function compareItem(actual, expected, message, options, properties) {
if (options && options.cloned)
QUnit.notStrictEqual(actual.id, 'not ' + expected.id, message + '.id');
QUnit.strictEqual(actual.constructor, expected.constructor,
message + '.constructor');
// When item was cloned and had a name, the name will be versioned
equals(options && options.cloned && actual.name ? actual.name + ' 1'
: actual.name, expected.name,
message + '.name');
compareProperties(actual, expected, ['children', 'bounds', 'position',
'matrix', 'data', 'opacity', 'locked', 'visible', 'blendMode',
'selected', 'fullySelected', 'clipMask', 'guide'],
message, options);
if (properties)
compareProperties(actual, expected, properties, message, options);
// Style
compareProperties(actual.style, expected.style, ['fillColor', 'strokeColor',
'strokeCap', 'strokeJoin', 'dashArray', 'dashOffset', 'miterLimit',
'fontSize', 'font', 'leading', 'justification'],
message + '.style', options);
}
var comparators = {
Null: QUnit.strictEqual,
Undefined: QUnit.strictEqual,
@ -48,26 +76,23 @@ var comparators = {
},
Array: function(actual, expected, message, options) {
QUnit.strictEqual(actual.length, expected.length,
(message || '') + ' length');
QUnit.strictEqual(actual.length, expected.length, message + '.length');
for (var i = 0, l = actual.length; i < l; i++) {
equals(actual[i], expected[i], (message || '') + ' [' + i + ']',
equals(actual[i], expected[i], (message || '') + '[' + i + ']',
options);
}
},
Point: function(actual, expected, message, options) {
comparators.Number(actual.x, expected.x, (message || '') + ' x',
options);
comparators.Number(actual.y, expected.y, (message || '') + ' y',
options);
comparators.Number(actual.x, expected.x, message + '.x', options);
comparators.Number(actual.y, expected.y, message + '.y', options);
},
Size: function(actual, expected, message, options) {
comparators.Number(actual.width, expected.width,
(message || '') + ' width', options);
comparators.Number(actual.height, expected.height,
(message || '') + ' height', options);
comparators.Number(actual.width, expected.width, message + '.width',
options);
comparators.Number(actual.height, expected.height, message + '.height',
options);
},
Rectangle: function(actual, expected, message, options) {
@ -81,20 +106,24 @@ var comparators = {
Color: function(actual, expected, message, options) {
if (actual && expected) {
equals(actual.type, expected.type,
(message || '') + ' type', options);
equals(actual.type, expected.type, message + '.type', options);
// NOTE: This also compares gradients, with identity checks and all.
equals(actual.components, expected.components,
(message || '') + ' components', options);
message + '.components', options);
} else {
equals(actual, expected, message, options);
QUnit.strictEqual(actual, expected, message);
}
},
Symbol: function(actual, expected, message, options) {
equals(actual.definition, expected.definition, message + '.definition',
options);
},
Segment: function(actual, expected, message, options) {
Base.each(['handleIn', 'handleOut', 'point', 'selected'],
function(key) {
equals(actual[key], expected[key], (message || '') + ' ' + key);
equals(actual[key], expected[key], message + '.' + key);
}
);
},
@ -102,11 +131,67 @@ var comparators = {
SegmentPoint: function(actual, expected, message, options) {
comparators.Point(actual, expected, message, options);
comparators.Boolean(actual.selected, expected.selected,
(message || '') + ' selected', options);
message + '.selected', options);
},
Item: compareItem,
Group: function(actual, expected, message, options) {
compareItem(actual, expected, message, options,
['clipped']);
},
Layer: function(actual, expected, message, options) {
compareItem(actual, expected, message, options);
equals(function() {
return options && options.dontShareProject
? actual.project !== expected.project
: actual.project === expected.project;
}, true);
},
Path: function(actual, expected, message, options) {
compareItem(actual, expected, message, options,
['segments', 'closed', 'clockwise', 'length']);
},
CompoundPath: function(actual, expected, message, options) {
compareItem(actual, expected, message, options);
},
Raster: function(actual, expected, message, options) {
compareItem(actual, expected, message, options,
['size', 'width', 'height', 'ppi', 'source', 'image']);
equals(actual.toDataURL(), expected.toDataURL(),
message + '.toDataUrl()');
},
Shape: function(actual, expected, message, options) {
compareItem(actual, expected, message, options,
['shape', 'size', 'radius']);
},
PlacedSymbol: function(actual, expected, message, options) {
compareItem(actual, expected, message,
// Cloning PlacedSymbols does not result in cloned Symbols
options && options.cloned
? new Base(options, { cloned: false })
: options,
['symbol']);
},
PointText: function(actual, expected, message, options) {
compareItem(actual, expected, message, options,
['content', 'point']);
},
Project: function(actual, expected, message, options) {
compareProperties(actual, expected, ['symbols', 'layers'],
message, options);
}
};
var identicalAfterClone = {
var strictIdenticalAfterCloning = {
Gradient: true,
Symbol: true
};
@ -145,6 +230,11 @@ function equals(actual, expected, message, options) {
|| (cls = expected && expected._class)
|| type === 'object' && 'Object';
var comparator = type && comparators[type];
if (!message) {
message = type
? type.charAt(0).toLowerCase() + type.substring(1)
: 'value';
}
if (comparator) {
comparator(actual, expected, message, options);
} else if (expected && expected.equals) {
@ -155,10 +245,10 @@ function equals(actual, expected, message, options) {
QUnit.push(actual === expected, actual, expected, message);
}
if (options && options.cloned && cls) {
var identical = identicalAfterClone[cls];
var identical = strictIdenticalAfterCloning[cls];
QUnit.push(identical ? actual === expected : actual !== expected,
actual, identical ? expected : 'not ' + expected,
(message || '') + ' identity');
message + ': identical after cloning');
}
}
@ -180,132 +270,6 @@ function asyncTest(testName, expected) {
});
}
function compareItems(item, item2, options) {
if (options && options.cloned)
QUnit.notStrictEqual(item.id, item2.id, 'Compare Item#id');
QUnit.strictEqual(item.constructor, item2.constructor,
'Compare Item#constructor');
// When item was cloned and had a name, the name will be versioned
equals(options && options.cloned && item.name ? item.name + ' 1'
: item.name, item2.name, 'Compare Item#name');
Base.each(['bounds', 'position', 'data', 'matrix', 'opacity', 'locked',
'visible', 'blendMode', 'selected', 'fullySelected', 'clipMask',
'guide'],
function(key) {
equals(item[key], item2[key], 'Compare Item#' + key, options);
}
);
// Style
Base.each(['fillColor', 'strokeColor', 'strokeCap', 'strokeJoin',
'dashArray', 'dashOffset', 'miterLimit',
'fontSize', 'font', 'leading', 'justification'],
function(key) {
equals(item.style[key], item2.style[key], 'Compare Style#' + key,
options);
}
);
// Path specific
if (item instanceof Path) {
Base.each(['segments', 'closed', 'clockwise', 'length'],
function(key) {
equals(item[key], item2[key], 'Compare Path#' + key, options);
}
);
}
// Shape specific
if (item instanceof Shape) {
Base.each(['shape', 'size', 'radius'],
function(key) {
equals(item[key], item2[key], 'Compare Shape#' + key, options);
}
);
}
// Group specific
if (item instanceof Group) {
equals(item.clipped, item2.clipped, 'Compare Group#clipped', options);
}
// Layer specific
if (item instanceof Layer) {
equals(function() {
return options && options.dontShareProject
? item.project != item2.project
: item.project == item2.project;
}, true);
}
// PlacedSymbol specific
if (item instanceof PlacedSymbol) {
if (options.dontShareProject) {
compareItems(item.symbol.definition, item2.symbol.definition,
options,
'Compare Symbol#definition');
} else {
equals(item.symbol, item2.symbol, 'Compare PlacedSymbol#symbol',
options);
}
}
// Raster specific
if (item instanceof Raster) {
equals(item.size, item2.size, 'Compare Raster#size');
equals(item.width, item2.width, 'Compare Raster#width');
equals(item.height, item2.height, 'Compare Raster#height');
equals(item.ppi, item2.ppi, 'Compare Raster#ppi');
equals(item.source, item2.source, 'Compare Raster#source');
equals(item.image, item2.image, 'Compare Raster#image');
equals(item.toDataURL(), item2.toDataURL(),
'Compare Raster#toDataUrl()');
}
// TextItem specific:
if (item instanceof TextItem) {
equals(item.content, item2.content, 'Compare Item#content');
}
// PointText specific:
if (item instanceof PointText) {
equals(item.point, item2.point, 'Compare Item#point');
}
// Check length of children and recursively compare them:
if (item.children) {
equals(function() {
return item.children.length == item2.children.length;
}, true);
for (var i = 0, l = item.children.length; i < l; i++) {
compareItems(item.children[i], item2.children[i], options);
}
}
}
function compareProjects(project, project2) {
// Compare Project#symbols:
equals(function() {
return project.symbols.length == project2.symbols.length;
}, true);
for (var i = 0, l = project.symbols.length; i < l; i++) {
var definition1 = project.symbols[i].definition;
var definition2 = project2.symbols[i].definition;
compareItems(definition1, definition2, { dontShareProject: true },
'Compare Symbol#definition');
}
// Compare Project#layers:
equals(function() {
return project.layers.length == project2.layers.length;
}, true);
for (var i = 0, l = project.layers.length; i < l; i++) {
compareItems(project.layers[i], project2.layers[i],
{ dontShareProject: true });
}
}
// SVG
function createSVG(xml) {

View file

@ -24,7 +24,7 @@ function cloneAndCompare(item) {
return copy.parent.children[copy.name] == copy;
}, true);
}
compareItems(item, copy, { cloned: true });
equals(item, copy, 'item.clone()', { cloned: true });
// Remove the cloned item to restore the document:
copy.remove();
}
@ -134,7 +134,7 @@ test('Symbol#clone()', function() {
path.selected = true;
var symbol = new Symbol(path);
var copy = symbol.clone();
compareItems(symbol.definition, copy.definition);
equals(symbol.definition, copy.definition, 'symbol.definition');
equals(function() {
return symbol.project == copy.project;
}, true);

View file

@ -17,7 +17,7 @@ function testExportImportJSON(project) {
var json = project.exportJSON({ precision: 8 });
var project2 = new Project();
project2.importJSON(json);
compareProjects(project2, project);
equals(project, project2, null, { dontShareProject: true });
}
test('Circles', function() {

View file

@ -15,7 +15,7 @@ module('SVGImport');
test('Import complex CompoundPath and clone', function() {
var svg = createSVG('<path id="path" fill="red" d="M4,14h20v-2H4V14z M15,26h7v-2h-7V26z M15,22h9v-2h-9V22z M15,18h9v-2h-9V18z M4,26h9V16H4V26z M28,10V6H0v22c0,0,0,4,4,4 h25c0,0,3-0.062,3-4V10H28z M4,30c-2,0-2-2-2-2V8h24v20c0,0.921,0.284,1.558,0.676,2H4z"/>;');
var item = paper.project.importSVG(svg.getElementById('path'));
compareItems(item, item.clone(), { cloned: true });
equals(item, item.clone(), null, { cloned: true });
});
test('make an svg line', function() {
@ -34,7 +34,7 @@ test('make an svg line', function() {
var line = new Path.Line([x1, y1], [x2, y2]);
compareItems(importedLine, line);
equals(importedLine, line);
});
test('make an svg line with invalid values', function() {
@ -49,7 +49,7 @@ test('make an svg line with invalid values', function() {
var line = new Path.Line([0, 0], [0, 0]);
compareItems(importedLine, line);
equals(importedLine, line);
});
test('compare rectangle values', function() {
@ -71,7 +71,7 @@ test('compare rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var realRectangle = new Shape.Rectangle(rectangle);
compareItems(importedRectangle, realRectangle);
equals(importedRectangle, realRectangle);
});
@ -93,7 +93,7 @@ test('compare negative rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var realRectangle = new Shape.Rectangle(rectangle);
compareItems(importedRectangle, realRectangle);
equals(importedRectangle, realRectangle);
});
@ -113,7 +113,7 @@ test('compare invalid rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var realRectangle = new Shape.Rectangle(rectangle);
compareItems(importedRectangle, realRectangle);
equals(importedRectangle, realRectangle);
});
test('compare round rectangle values', function() {
@ -140,7 +140,7 @@ test('compare round rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var roundRect = new Shape.Rectangle(rectangle, cornerSize);
compareItems(importedRectangle, roundRect);
equals(importedRectangle, roundRect);
});
test('compare negative round rectangle values', function() {
@ -167,7 +167,7 @@ test('compare negative round rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var roundRect = new Shape.Rectangle(rectangle, cornerSize);
compareItems(importedRectangle, roundRect);
equals(importedRectangle, roundRect);
});
test('compare invalid round rectangle values', function() {
@ -194,7 +194,7 @@ test('compare invalid round rectangle values', function() {
var rectangle = new Rectangle(topLeft, size);
var roundRect = new Shape.Rectangle(rectangle, cornerSize);
compareItems(importedRectangle, roundRect);
equals(importedRectangle, roundRect);
});
test('compare ellipse values', function() {
@ -216,7 +216,7 @@ test('compare ellipse values', function() {
radius: new Point(rx, ry)
});
compareItems(importedEllipse, ellipse);
equals(importedEllipse, ellipse);
});
test('compare negative ellipse values', function() {
@ -238,7 +238,7 @@ test('compare negative ellipse values', function() {
radius: new Point(rx, ry)
});
compareItems(importedEllipse, ellipse);
equals(importedEllipse, ellipse);
});
test('compare invalid ellipse values', function() {
@ -256,7 +256,7 @@ test('compare invalid ellipse values', function() {
radius: new Point(0, 0)
});
compareItems(importedEllipse, ellipse);
equals(importedEllipse, ellipse);
});
test('compare circle values', function() {
@ -274,7 +274,7 @@ test('compare circle values', function() {
var center = new Point(cx, cy);
var circle = new Shape.Circle(center, r);
compareItems(importedCircle, circle);
equals(importedCircle, circle);
});
test('compare negative circle values', function() {
@ -292,7 +292,7 @@ test('compare negative circle values', function() {
var center = new Point(cx, cy);
var circle = new Shape.Circle(center, r);
compareItems(importedCircle, circle);
equals(importedCircle, circle);
});
@ -308,7 +308,7 @@ test('compare invalid circle values', function() {
var center = new Point(0, 0);
var circle = new Shape.Circle(center, 0);
compareItems(importedCircle, circle);
equals(importedCircle, circle);
});
@ -330,7 +330,7 @@ test('compare polygon values', function() {
poly.closePath();
}
compareItems(importedPolygon, poly);
equals(importedPolygon, poly);
});
test('compare negative polygon values', function() {
@ -351,7 +351,7 @@ test('compare negative polygon values', function() {
poly.closePath();
}
compareItems(importedPolygon, poly);
equals(importedPolygon, poly);
});
test('compare polyline values', function() {
@ -372,7 +372,7 @@ test('compare polyline values', function() {
poly.closePath();
}
compareItems(importedPolyline, poly);
equals(importedPolyline, poly);
});
test('compare negative polyline values', function() {
@ -393,5 +393,5 @@ test('compare negative polyline values', function() {
poly.closePath();
}
compareItems(importedPolyline, poly);
equals(importedPolyline, poly);
});