paper.js/test/lib/helpers.js

422 lines
14 KiB
JavaScript
Raw Normal View History

/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
2014-01-03 19:47:16 -05:00
* Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
* http://scratchdisk.com/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
2013-06-11 16:43:29 -04:00
// Register a jsDump parser for Base.
QUnit.jsDump.setParser('Base', function (obj, stack) {
2014-08-16 13:24:54 -04:00
// Just compare the string representation of classes inheriting from Base,
// since they hide the internal values.
return obj.toString();
});
2013-06-11 16:43:29 -04:00
// Override the default object parser to handle Base objects.
// We need to keep a reference to the previous implementation.
var objectParser = QUnit.jsDump.parsers.object;
QUnit.jsDump.setParser('object', function (obj, stack) {
2014-08-16 13:24:54 -04:00
return (obj instanceof Base
? QUnit.jsDump.parsers.Base
: objectParser).call(this, obj, stack);
});
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);
}
},
Point: function(actual, expected, message, options) {
equals(actual.x, expected.x, (message || '') + ' x', options);
equals(actual.y, expected.y, (message || '') + ' y', options);
},
Size: function(actual, expected, message, options) {
equals(actual.width, expected.width, (message || '') + ' width',
options);
equals(actual.height, expected.height, (message || '') + ' height',
options);
},
Rectangle: function(actual, expected, message, options) {
comparators.Point(actual, expected, message, options);
comparators.Size(actual, expected, message, options);
}
};
function getClass(object) {
return typeof object === 'number' && 'Number'
|| Array.isArray(object) && 'Array'
|| object && object._class;
}
function getFunctionMessage(func) {
var message = func.toString().match(
2014-08-16 13:24:54 -04:00
/^\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, options) {
// Allow the use of functions for actual, which will get called and their
// source content extracted for readable reports.
2014-08-16 13:24:54 -04:00
if (typeof actual === 'function') {
if (!message)
message = getFunctionMessage(actual);
2014-08-16 13:24:54 -04:00
actual = actual();
}
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);
}
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);
}
QUnit.push(actual === expected, actual, expected, message);
}
2011-05-05 08:38:20 -04:00
function test(testName, expected) {
2014-08-16 13:24:54 -04:00
return QUnit.test(testName, function() {
var project = new Project();
expected();
project.remove();
});
}
function asyncTest(testName, expected) {
2014-08-16 13:24:54 -04:00
return QUnit.asyncTest(testName, function() {
var project = new Project();
expected(function() {
project.remove();
start();
});
});
}
function compareColors(color1, color2, message, options) {
2014-08-16 13:24:54 -04:00
color1 = color1 && new Color(color1);
color2 = color2 && new Color(color2);
if (color1 && color2) {
equals(color1.type, color2.type,
(message || '') + ' type', options);
equals(color1.components, color2.components,
(message || '') + ' components', options);
2014-08-16 13:24:54 -04:00
} else {
equals(color1, color2, message, options);
2014-08-16 13:24:54 -04:00
}
}
function compareStyles(style, style2, options) {
var checkIdentity = options && options.checkIdentity;
2014-08-16 13:24:54 -04:00
if (checkIdentity) {
equals(function() {
return style !== style2;
}, true);
}
Base.each(['fillColor', 'strokeColor'], function(key) {
if (style[key]) {
// The color should not point to the same color object:
if (checkIdentity) {
equals(function() {
return style[key] !== style2[key];
}, true, 'The ' + key
+ ' should not point to the same color object:');
}
if (style[key] instanceof Color) {
if (style[key].type === 'gradient' && checkIdentity) {
equals(function() {
return style[key].gradient === style2[key].gradient;
}, true, 'The ' + key
+ '.gradient should point to the same object:');
}
compareColors(style[key], style2[key],
'Compare Style#' + key);
} else {
equals(style[key] && style[key].toString(),
style2[key] && style2[key].toString(),
'Compare Style#' + key);
}
}
});
compareObjects(['strokeCap', 'strokeJoin', 'dashArray', 'dashOffset',
'miterLimit', 'strokeOverprint', 'fillOverprint',
2014-08-16 13:24:54 -04:00
'fontSize', 'font', 'leading', 'justification'],
style, style2, 'Compare Style', options);
2011-05-21 12:38:49 -04:00
}
function compareObjects(keys, obj, obj2, message, options) {
if (options && options.checkIdentity) {
2014-08-16 13:24:54 -04:00
equals(function() {
return obj !== obj2;
}, true);
}
Base.each(keys, function(key) {
equals(obj[key], obj2[key], message + '#' + key, options);
2014-08-16 13:24:54 -04:00
});
}
2011-05-21 12:38:49 -04:00
function compareSegmentPoints(segmentPoint, segmentPoint2, options) {
compareObjects(['x', 'y', 'selected'], segmentPoint, segmentPoint2,
'Compare SegmentPoint', options);
}
function compareSegments(segment, segment2, options) {
if (options.checkIdentity) {
2014-08-16 13:24:54 -04:00
equals(function() {
return segment !== segment2;
}, true);
}
equals(function() {
return segment.selected == segment2.selected;
}, true);
Base.each(['handleIn', 'handleOut', 'point'], function(key) {
compareSegmentPoints(segment[key], segment2[key]);
});
}
function compareSegmentLists(segmentList, segmentList2, options) {
var checkIdentity = options && options.checkIdentity;
2014-08-16 13:24:54 -04:00
if (checkIdentity) {
equals(function() {
return segmentList !== segmentList2;
}, true);
}
equals(segmentList.toString(), segmentList2.toString(),
'Compare Item#segments');
if (checkIdentity) {
for (var i = 0, l = segmentList.length; i < l; i++) {
var segment = segmentList[i],
segment2 = segmentList2[i];
compareSegments(segment, segment2, options);
2014-08-16 13:24:54 -04:00
}
}
}
function compareItems(item, item2, options) {
var checkIdentity = options && options.checkIdentity;
2014-08-16 13:24:54 -04:00
if (checkIdentity) {
equals(function() {
return item !== item2;
}, true);
equals(function() {
return item.id !== item2.id;
}, true);
}
equals(function() {
return item.constructor == item2.constructor;
}, true);
var itemProperties = ['opacity', 'locked', 'visible', 'blendMode', 'name',
'selected', 'clipMask', 'guide'];
Base.each(itemProperties, function(key) {
var value = item[key];
// When item was cloned and had a name, the name will be versioned
equals(
key == 'name' && options && options.cloned && value
2014-08-16 13:24:54 -04:00
? value + ' 1'
: value,
item2[key],
'compare Item#' + key);
});
if (checkIdentity) {
equals(function() {
return item.bounds !== item2.bounds;
}, true);
}
equals(item.bounds.toString(), item2.bounds.toString(),
'Compare Item#bounds');
if (checkIdentity) {
equals(function() {
return item.position !== item2.position;
}, true);
}
equals(item.position.toString(), item2.position.toString(),
'Compare Item#position');
equals(function() {
return Base.equals(item.data, item2.data);
}, true);
if (item.matrix) {
if (checkIdentity) {
equals(function() {
return item.matrix !== item2.matrix;
}, true);
}
equals(item.matrix.toString(), item2.matrix.toString(),
'Compare Item#matrix');
}
// Path specific
if (item instanceof Path) {
var keys = ['closed', 'fullySelected', 'clockwise'];
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
equals(item[key], item2[key], 'Compare Path#' + key);
}
equals(item.length, item2.length, 'Compare Path#length');
compareSegmentLists(item.segments, item2.segments, options);
2014-08-16 13:24:54 -04:00
}
// Shape specific
if (item instanceof Shape) {
var keys = ['shape', 'size', 'radius'];
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
equals(item[key], item2[key], 'Compare Shape#' + key);
}
}
// Group specific
if (item instanceof Group) {
equals(function() {
return item.clipped == item2.clipped;
}, true);
}
// Layer specific
if (item instanceof Layer) {
equals(function() {
return options && options.dontShareProject
2014-08-16 13:24:54 -04:00
? item.project != item2.project
: item.project == item2.project;
}, true);
}
// PlacedSymbol specific
if (item instanceof PlacedSymbol) {
if (options.dontShareProject) {
2014-08-16 13:24:54 -04:00
compareItems(item.symbol.definition, item2.symbol.definition,
options,
2014-08-16 13:24:54 -04:00
'Compare Symbol#definition');
} else {
equals(function() {
return item.symbol == item2.symbol;
}, true);
}
}
// Raster specific
if (item instanceof Raster) {
equals(item.size.toString(), item2.size.toString(),
'Compare Raster#size');
equals(item.width, item2.width, 'Compare Raster#width');
equals(item.height, item2.height, 'Compare Raster#height');
2014-08-16 13:24:54 -04:00
equals(item.ppi.toString(), item2.ppi.toString(),
'Compare Raster#ppi');
equals(item.source, item2.source, 'Compare Raster#source');
if (options.checkIdentity) {
2014-08-16 13:24:54 -04:00
equals(item.image, item2.image, 'Compare Raster#image');
}
equals(item.size.toString(), item2.size.toString(),
'Compare Raster#size');
equals(item.toDataURL() == item2.toDataURL(), true,
'Compare Raster#toDataUrl()');
}
// TextItem specific:
if (item instanceof TextItem) {
equals(item.content, item2.content, 'Compare Item#content');
}
// PointText specific:
if (item instanceof PointText) {
if (options.checkIdentity) {
2014-08-16 13:24:54 -04:00
equals(function() {
return item.point !== item2.point;
}, true);
}
equals(item.point.toString(), item2.point.toString(),
'Compare Item#point');
}
if (item.style) {
// Style
compareStyles(item.style, item2.style, options);
2014-08-16 13:24:54 -04:00
}
// 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);
2014-08-16 13:24:54 -04:00
}
}
}
function compareProjects(project, project2) {
2014-08-16 13:24:54 -04:00
// 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 },
2014-08-16 13:24:54 -04:00
'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 });
2014-08-16 13:24:54 -04:00
}
}
// SVG
2013-04-23 10:19:08 -04:00
function createSVG(xml) {
2014-08-16 13:24:54 -04:00
return new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg">' + xml + '</svg>',
'text/xml');
}