Start cleaning up unit tests by introducing new class/type-based comparators lookup table.

This commit is contained in:
Jürg Lehni 2014-12-28 14:33:22 +01:00
parent 28538d8a43
commit e95e17826e
7 changed files with 122 additions and 106 deletions

View file

@ -27,42 +27,70 @@ QUnit.jsDump.setParser('object', function (obj, stack) {
: objectParser).call(this, obj, stack);
});
function getFunctionBody(func) {
return func.toString().match(
var comparators = {
Number: function(actual, expected, message, options) {
// Compare with a default tolerance of Numerical.TOLERANCE:
var ok = Math.abs(actual - expected)
<= Base.pick(options && options.tolerance, Numerical.TOLERANCE);
QUnit.push(ok, ok ? expected : actual, expected, message);
},
Array: function(actual, expected, message, options) {
equals(actual.length, expected.length, (message || '') + ' length',
options);
for (var i = 0, l = actual.length; i < l; i++) {
equals(actual[i], expected[i], (message || '') + ' [' + i + ']',
options);
}
}
};
function getClass(object) {
return typeof object === 'number' && 'Number'
|| Array.isArray(object) && 'Array'
|| object && object._class;
}
function getFunctionMessage(func) {
var message = func.toString().match(
/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1]
.replace(/ /g, '')
.replace(/^\s+|\s+$/g, '');
if (/^return /.test(message)) {
message = message
.replace(/^return /, '')
.replace(/;$/, '');
}
return message;
}
// Override equals to convert functions to message and execute them as tests()
function equals(actual, expected, message, tolerance) {
function equals(actual, expected, message, options) {
// Allow the use of functions for actual, which will get called and their
// source content extracted for readable reports.
if (typeof actual === 'function') {
if (!message) {
message = getFunctionBody(actual);
if (/^return /.test(message)) {
message = message
.replace(/^return /, '')
.replace(/;$/, '');
}
}
if (!message)
message = getFunctionMessage(actual);
actual = actual();
}
if (typeof expected === 'number') {
// Compare with a default tolerance of Numerical.TOLERANCE:
var ok = Math.abs(actual - expected)
<= Base.pick(tolerance, Numerical.TOLERANCE);
return QUnit.push(ok, ok ? expected : actual, expected, message);
} else if (actual && actual.equals) {
// Support calling of #equals() on the actual or expected value, and
// automatically convert displayed values to strings.
return QUnit.push(actual.equals(expected), actual, expected, message);
} else if (expected && expected.equals) {
return QUnit.push(expected.equals(actual), actual, expected, message);
if (actual != null) {
var comparator = comparators[getClass(actual)];
if (comparator)
return comparator(actual, expected, message, options);
// Support calling of #equals() on the actual or expected value.
if (actual.equals)
return QUnit.push(actual.equals(expected),
actual, expected, message);
}
// Let's be strict
return strictEqual(actual, expected, message);
if (expected != null) {
var comparator = comparators[getClass(expected)];
if (comparator)
return comparator(actual, expected, message, options);
if (expected.equals)
return QUnit.push(expected.equals(actual),
actual, expected, message);
}
QUnit.push(actual === expected, actual, expected, message);
}
function test(testName, expected) {
@ -83,42 +111,36 @@ function asyncTest(testName, expected) {
});
}
function compareArrays(array1, array2, message, tolerance) {
equals(array1.length, array2.length, (message || '') + ' length');
for (var i = 0, l = array1.length; i < l; i++) {
equals(array1[i], array2[i], (message || '') + ' [' + i + ']',
tolerance);
}
function comparePoints(point1, point2, message, options) {
equals(point1.x, point2.x, (message || '') + ' x', options);
equals(point1.y, point2.y, (message || '') + ' y', options);
}
function comparePoints(point1, point2, message, tolerance) {
equals(point1.x, point2.x, (message || '') + ' x', tolerance);
equals(point1.y, point2.y, (message || '') + ' y', tolerance);
function compareSize(size1, size2, message, options) {
equals(size1.width, size2.width, (message || '') + ' width', options);
equals(size1.height, size2.height, (message || '') + ' height', options);
}
function compareSize(size1, size2, message, tolerance) {
equals(size1.width, size2.width, (message || '') + ' width', tolerance);
equals(size1.height, size2.height, (message || '') + ' height', tolerance);
function compareRectangles(rect1, rect2, message, options) {
comparePoints(rect1, rect2, message, options);
compareSize(rect1, rect2, message, options);
}
function compareRectangles(rect1, rect2, message, tolerance) {
comparePoints(rect1, rect2, message, tolerance);
compareSize(rect1, rect2, message, tolerance);
}
function compareColors(color1, color2, message, tolerance) {
function compareColors(color1, color2, message, options) {
color1 = color1 && new Color(color1);
color2 = color2 && new Color(color2);
if (color1 && color2) {
equals(color1.type, color2.type, (message || '') + ' type');
compareArrays(color1.components, color2.components,
(message || '') + ' components', tolerance);
equals(color1.type, color2.type,
(message || '') + ' type', options);
equals(color1.components, color2.components,
(message || '') + ' components', options);
} else {
equals(color1, color2, message, tolerance);
equals(color1, color2, message, options);
}
}
function compareStyles(style, style2, checkIdentity) {
function compareStyles(style, style2, options) {
var checkIdentity = options && options.checkIdentity;
if (checkIdentity) {
equals(function() {
return style !== style2;
@ -150,38 +172,30 @@ function compareStyles(style, style2, checkIdentity) {
}
});
compareObjects('Style', ['strokeCap', 'strokeJoin', 'dashArray',
'dashOffset', 'miterLimit', 'strokeOverprint', 'fillOverprint',
compareObjects(['strokeCap', 'strokeJoin', 'dashArray', 'dashOffset',
'miterLimit', 'strokeOverprint', 'fillOverprint',
'fontSize', 'font', 'leading', 'justification'],
style, style2, checkIdentity);
style, style2, 'Compare Style', options);
}
function compareObjects(name, keys, obj, obj2, checkIdentity) {
if (checkIdentity) {
function compareObjects(keys, obj, obj2, message, options) {
if (options && options.checkIdentity) {
equals(function() {
return obj !== obj2;
}, true);
}
Base.each(keys, function(key) {
var val = obj[key], val2 = obj2[key],
message = 'Compare ' + name + '#' + key;
if (typeof val === 'number') {
equals(val, val2, message);
} else if (Array.isArray(val)) {
compareArrays(val, val2, message);
} else {
equals(val, val2, message);
}
equals(obj[key], obj2[key], message + '#' + key, options);
});
}
function compareSegmentPoints(segmentPoint, segmentPoint2, checkIdentity) {
compareObjects('SegmentPoint', ['x', 'y', 'selected'],
segmentPoint, segmentPoint2, checkIdentity);
function compareSegmentPoints(segmentPoint, segmentPoint2, options) {
compareObjects(['x', 'y', 'selected'], segmentPoint, segmentPoint2,
'Compare SegmentPoint', options);
}
function compareSegments(segment, segment2, checkIdentity) {
if (checkIdentity) {
function compareSegments(segment, segment2, options) {
if (options.checkIdentity) {
equals(function() {
return segment !== segment2;
}, true);
@ -194,7 +208,8 @@ function compareSegments(segment, segment2, checkIdentity) {
});
}
function compareSegmentLists(segmentList, segmentList2, checkIdentity) {
function compareSegmentLists(segmentList, segmentList2, options) {
var checkIdentity = options && options.checkIdentity;
if (checkIdentity) {
equals(function() {
return segmentList !== segmentList2;
@ -206,12 +221,13 @@ function compareSegmentLists(segmentList, segmentList2, checkIdentity) {
for (var i = 0, l = segmentList.length; i < l; i++) {
var segment = segmentList[i],
segment2 = segmentList2[i];
compareSegments(segment, segment2, checkIdentity);
compareSegments(segment, segment2, options);
}
}
}
function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
function compareItems(item, item2, options) {
var checkIdentity = options && options.checkIdentity;
if (checkIdentity) {
equals(function() {
return item !== item2;
@ -232,7 +248,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
var value = item[key];
// When item was cloned and had a name, the name will be versioned
equals(
key == 'name' && cloned && value
key == 'name' && options && options.cloned && value
? value + ' 1'
: value,
item2[key],
@ -279,7 +295,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
equals(item[key], item2[key], 'Compare Path#' + key);
}
equals(item.length, item2.length, 'Compare Path#length');
compareSegmentLists(item.segments, item2.segments, checkIdentity);
compareSegmentLists(item.segments, item2.segments, options);
}
// Shape specific
@ -301,7 +317,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
// Layer specific
if (item instanceof Layer) {
equals(function() {
return dontShareProject
return options && options.dontShareProject
? item.project != item2.project
: item.project == item2.project;
}, true);
@ -309,9 +325,9 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
// PlacedSymbol specific
if (item instanceof PlacedSymbol) {
if (dontShareProject) {
if (options.dontShareProject) {
compareItems(item.symbol.definition, item2.symbol.definition,
cloned, checkIdentity, dontShareProject,
options,
'Compare Symbol#definition');
} else {
equals(function() {
@ -331,7 +347,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
'Compare Raster#ppi');
equals(item.source, item2.source, 'Compare Raster#source');
if (checkIdentity) {
if (options.checkIdentity) {
equals(item.image, item2.image, 'Compare Raster#image');
}
equals(item.size.toString(), item2.size.toString(),
@ -347,7 +363,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
// PointText specific:
if (item instanceof PointText) {
if (checkIdentity) {
if (options.checkIdentity) {
equals(function() {
return item.point !== item2.point;
}, true);
@ -358,7 +374,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
if (item.style) {
// Style
compareStyles(item.style, item2.style, checkIdentity);
compareStyles(item.style, item2.style, options);
}
// Check length of children and recursively compare them:
@ -367,8 +383,7 @@ function compareItems(item, item2, cloned, checkIdentity, dontShareProject) {
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], cloned,
checkIdentity, dontShareProject);
compareItems(item.children[i], item2.children[i], options);
}
}
}
@ -381,7 +396,7 @@ function compareProjects(project, project2) {
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, false, false, true,
compareItems(definition1, definition2, { dontShareProject: true },
'Compare Symbol#definition');
}
@ -390,7 +405,8 @@ function compareProjects(project, project2) {
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], false, false, true);
compareItems(project.layers[i], project2.layers[i],
{ dontShareProject: true });
}
}

View file

@ -71,5 +71,5 @@ test('text.bounds', function() {
var text = new PointText(new Point(50, 100));
text.fillColor = 'black';
text.content = 'This is a test';
compareRectangles(text.bounds, { x: 50, y: 89.2, width: 67, height: 14.4 } , 'text.bounds', 0.5);
compareRectangles(text.bounds, { x: 50, y: 89.2, width: 67, height: 14.4 } , 'text.bounds', { tolerance: 0.5 });
});

View file

@ -24,7 +24,7 @@ function cloneAndCompare(item) {
return copy.parent.children[copy.name] == copy;
}, true);
}
compareItems(item, copy, true, true);
compareItems(item, copy, { cloned: true, checkIdentity: true });
// Remove the cloned item to restore the document:
copy.remove();
}

View file

@ -64,30 +64,30 @@ test('Item#insertAbove(item) / Item#insertBelow(item)', function() {
item1 = new Group();
item2 = new Group();
command();
var str = getFunctionBody(command);
var str = getFunctionMessage(command);
equals(item0.index, indexes[0], str + ': item0.index');
equals(item1.index, indexes[1], str + ': item1.index');
equals(item2.index, indexes[2], str + ': item2.index');
}
testMove(function() { item0.insertBelow(item0) }, [0,1,2]);
testMove(function() { item0.insertBelow(item1) }, [0,1,2]);
testMove(function() { item0.insertBelow(item2) }, [1,0,2]);
testMove(function() { item1.insertBelow(item0) }, [1,0,2]);
testMove(function() { item1.insertBelow(item1) }, [0,1,2]);
testMove(function() { item1.insertBelow(item2) }, [0,1,2]);
testMove(function() { item0.insertBelow(item0); }, [0,1,2]);
testMove(function() { item0.insertBelow(item1); }, [0,1,2]);
testMove(function() { item0.insertBelow(item2); }, [1,0,2]);
testMove(function() { item1.insertBelow(item0); }, [1,0,2]);
testMove(function() { item1.insertBelow(item1); }, [0,1,2]);
testMove(function() { item1.insertBelow(item2); }, [0,1,2]);
testMove(function() { item2.insertBelow(item0) }, [1,2,0]);
testMove(function() { item2.insertBelow(item1) }, [0,2,1]);
testMove(function() { item2.insertBelow(item2) }, [0,1,2]);
testMove(function() { item2.insertBelow(item0); }, [1,2,0]);
testMove(function() { item2.insertBelow(item1); }, [0,2,1]);
testMove(function() { item2.insertBelow(item2); }, [0,1,2]);
testMove(function() { item0.insertAbove(item0) }, [0,1,2]);
testMove(function() { item0.insertAbove(item1) }, [1,0,2]);
testMove(function() { item0.insertAbove(item2) }, [2,0,1]);
testMove(function() { item1.insertAbove(item0) }, [0,1,2]);
testMove(function() { item1.insertAbove(item1) }, [0,1,2]);
testMove(function() { item1.insertAbove(item2) }, [0,2,1]);
testMove(function() { item2.insertAbove(item0) }, [0,2,1]);
testMove(function() { item2.insertAbove(item1) }, [0,1,2]);
testMove(function() { item2.insertAbove(item2) }, [0,1,2]);
testMove(function() { item0.insertAbove(item0); }, [0,1,2]);
testMove(function() { item0.insertAbove(item1); }, [1,0,2]);
testMove(function() { item0.insertAbove(item2); }, [2,0,1]);
testMove(function() { item1.insertAbove(item0); }, [0,1,2]);
testMove(function() { item1.insertAbove(item1); }, [0,1,2]);
testMove(function() { item1.insertAbove(item2); }, [0,2,1]);
testMove(function() { item2.insertAbove(item0); }, [0,2,1]);
testMove(function() { item2.insertAbove(item1); }, [0,1,2]);
testMove(function() { item2.insertAbove(item2); }, [0,1,2]);
});

View file

@ -131,7 +131,7 @@ test('Raster#getAverageColor(path)', function() {
});
var raster = paper.project.activeLayer.rasterize(72);
circle.scale(0.9);
compareColors(raster.getAverageColor(circle), circle.fillColor, null, 3);
compareColors(raster.getAverageColor(circle), circle.fillColor);
});
test('Raster#getAverageColor(path) with compound path', function() {
@ -153,5 +153,5 @@ test('Raster#getAverageColor(path) with compound path', function() {
var raster = paper.project.activeLayer.rasterize(72);
path.scale(0.9);
path2.scale(1.1);
compareColors(raster.getAverageColor(compoundPath), new Color(1, 0, 0), null, 3);
compareColors(raster.getAverageColor(compoundPath), new Color(1, 0, 0), null, { tolerance: 10e-4 });
});

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(), true, true);
compareItems(item, item.clone(), { cloned: true, checkIdentity: true });
});
test('make an svg line', function() {

View file

@ -22,7 +22,7 @@ test('PointText', function() {
compareColors(text.fillColor, new Color(0, 0, 0), 'text.fillColor should be black by default');
comparePoints(text.point, { x: 100, y: 100 }, 'text.point');
comparePoints(text.bounds.point, { x: 100, y: 87.4 }, 'text.bounds.point');
compareSize(text.bounds.size, { width: 77, height: 16.8 }, 'text.bounds.size', 1.0);
compareSize(text.bounds.size, { width: 77, height: 16.8 }, 'text.bounds.size', { tolerance: 1.0 });
equals(function() {
return text.hitTest(text.bounds.center) != null;
}, true);