373 lines
8 KiB
JavaScript
373 lines
8 KiB
JavaScript
![]() |
var clone = require('./');
|
||
|
|
||
|
function inspect(obj) {
|
||
|
seen = [];
|
||
|
return JSON.stringify(obj, function (key, val) {
|
||
|
if (val != null && typeof val == "object") {
|
||
|
if (seen.indexOf(val) >= 0) {
|
||
|
return '[cyclic]';
|
||
|
}
|
||
|
|
||
|
seen.push(val);
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Creates a new VM in node, or an iframe in a browser in order to run the
|
||
|
// script
|
||
|
function apartContext(context, script, callback) {
|
||
|
var vm = require('vm');
|
||
|
|
||
|
if (vm) {
|
||
|
var ctx = vm.createContext({ ctx: context });
|
||
|
callback(vm.runInContext(script, ctx));
|
||
|
} else if (document && document.createElement) {
|
||
|
var iframe = document.createElement('iframe');
|
||
|
iframe.style.display = 'none';
|
||
|
document.body.appendChild(iframe);
|
||
|
|
||
|
var myCtxId = 'tmpCtx' + Math.random();
|
||
|
|
||
|
window[myCtxId] = context;
|
||
|
iframe.src = 'test-apart-ctx.html?' + myCtxId + '&' + encodeURIComponent(script);
|
||
|
iframe.onload = function() {
|
||
|
try {
|
||
|
callback(iframe.contentWindow.results);
|
||
|
} catch (e) {
|
||
|
throw e;
|
||
|
}
|
||
|
};
|
||
|
} else {
|
||
|
console.log('WARNING: cannot create an apart context.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exports["clone string"] = function (test) {
|
||
|
test.expect(2); // how many tests?
|
||
|
|
||
|
var a = "foo";
|
||
|
test.strictEqual(clone(a), a);
|
||
|
a = "";
|
||
|
test.strictEqual(clone(a), a);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone number"] = function (test) {
|
||
|
test.expect(5); // how many tests?
|
||
|
|
||
|
var a = 0;
|
||
|
test.strictEqual(clone(a), a);
|
||
|
a = 1;
|
||
|
test.strictEqual(clone(a), a);
|
||
|
a = -1000;
|
||
|
test.strictEqual(clone(a), a);
|
||
|
a = 3.1415927;
|
||
|
test.strictEqual(clone(a), a);
|
||
|
a = -3.1415927;
|
||
|
test.strictEqual(clone(a), a);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone date"] = function (test) {
|
||
|
test.expect(3); // how many tests?
|
||
|
|
||
|
var a = new Date;
|
||
|
var c = clone(a);
|
||
|
test.ok(!!a.getUTCDate && !!a.toUTCString);
|
||
|
test.ok(!!c.getUTCDate && !!c.toUTCString);
|
||
|
test.equal(a.getTime(), c.getTime());
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone object"] = function (test) {
|
||
|
test.expect(1); // how many tests?
|
||
|
|
||
|
var a = { foo: { bar: "baz" } };
|
||
|
var b = clone(a);
|
||
|
|
||
|
test.deepEqual(b, a);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone array"] = function (test) {
|
||
|
test.expect(2); // how many tests?
|
||
|
|
||
|
var a = [
|
||
|
{ foo: "bar" },
|
||
|
"baz"
|
||
|
];
|
||
|
var b = clone(a);
|
||
|
|
||
|
test.ok(b instanceof Array);
|
||
|
test.deepEqual(b, a);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone buffer"] = function (test) {
|
||
|
if (typeof Buffer == 'undefined') {
|
||
|
return test.done();
|
||
|
}
|
||
|
|
||
|
test.expect(1);
|
||
|
|
||
|
var a = new Buffer("this is a test buffer");
|
||
|
var b = clone(a);
|
||
|
|
||
|
// no underscore equal since it has no concept of Buffers
|
||
|
test.deepEqual(b, a);
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone regexp"] = function (test) {
|
||
|
test.expect(5);
|
||
|
|
||
|
var a = /abc123/gi;
|
||
|
var b = clone(a);
|
||
|
test.deepEqual(b, a);
|
||
|
|
||
|
var c = /a/g;
|
||
|
test.ok(c.lastIndex === 0);
|
||
|
|
||
|
c.exec('123a456a');
|
||
|
test.ok(c.lastIndex === 4);
|
||
|
|
||
|
var d = clone(c);
|
||
|
test.ok(d.global);
|
||
|
test.ok(d.lastIndex === 4);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone object containing array"] = function (test) {
|
||
|
test.expect(1); // how many tests?
|
||
|
|
||
|
var a = {
|
||
|
arr1: [ { a: '1234', b: '2345' } ],
|
||
|
arr2: [ { c: '345', d: '456' } ]
|
||
|
};
|
||
|
|
||
|
var b = clone(a);
|
||
|
|
||
|
test.deepEqual(b, a);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["clone object with circular reference"] = function (test) {
|
||
|
test.expect(8); // how many tests?
|
||
|
|
||
|
var c = [1, "foo", {'hello': 'bar'}, function () {}, false, [2]];
|
||
|
var b = [c, 2, 3, 4];
|
||
|
|
||
|
var a = {'b': b, 'c': c};
|
||
|
a.loop = a;
|
||
|
a.loop2 = a;
|
||
|
c.loop = c;
|
||
|
c.aloop = a;
|
||
|
|
||
|
var aCopy = clone(a);
|
||
|
test.ok(a != aCopy);
|
||
|
test.ok(a.c != aCopy.c);
|
||
|
test.ok(aCopy.c == aCopy.b[0]);
|
||
|
test.ok(aCopy.c.loop.loop.aloop == aCopy);
|
||
|
test.ok(aCopy.c[0] == a.c[0]);
|
||
|
|
||
|
test.ok(eq(a, aCopy));
|
||
|
aCopy.c[0] = 2;
|
||
|
test.ok(!eq(a, aCopy));
|
||
|
aCopy.c = "2";
|
||
|
test.ok(!eq(a, aCopy));
|
||
|
|
||
|
function eq(x, y) {
|
||
|
return inspect(x) === inspect(y);
|
||
|
}
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['clone prototype'] = function (test) {
|
||
|
test.expect(3); // how many tests?
|
||
|
|
||
|
var a = {
|
||
|
a: "aaa",
|
||
|
x: 123,
|
||
|
y: 45.65
|
||
|
};
|
||
|
var b = clone.clonePrototype(a);
|
||
|
|
||
|
test.strictEqual(b.a, a.a);
|
||
|
test.strictEqual(b.x, a.x);
|
||
|
test.strictEqual(b.y, a.y);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['clone within an apart context'] = function (test) {
|
||
|
var results = apartContext({ clone: clone },
|
||
|
"results = ctx.clone({ a: [1, 2, 3], d: new Date(), r: /^foo$/ig })",
|
||
|
function (results) {
|
||
|
test.ok(results.a.constructor.toString() === Array.toString());
|
||
|
test.ok(results.d.constructor.toString() === Date.toString());
|
||
|
test.ok(results.r.constructor.toString() === RegExp.toString());
|
||
|
test.done();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
exports['clone object with no constructor'] = function (test) {
|
||
|
test.expect(3);
|
||
|
|
||
|
var n = null;
|
||
|
|
||
|
var a = { foo: 'bar' };
|
||
|
a.__proto__ = n;
|
||
|
test.ok(typeof a === 'object');
|
||
|
test.ok(typeof a !== null);
|
||
|
|
||
|
var b = clone(a);
|
||
|
test.ok(a.foo, b.foo);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['clone object with depth argument'] = function (test) {
|
||
|
test.expect(6);
|
||
|
|
||
|
var a = {
|
||
|
foo: {
|
||
|
bar : {
|
||
|
baz : 'qux'
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var b = clone(a, false, 1);
|
||
|
test.deepEqual(b, a);
|
||
|
test.notEqual(b, a);
|
||
|
test.strictEqual(b.foo, a.foo);
|
||
|
|
||
|
b = clone(a, true, 2);
|
||
|
test.deepEqual(b, a);
|
||
|
test.notEqual(b.foo, a.foo);
|
||
|
test.strictEqual(b.foo.bar, a.foo.bar);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['maintain prototype chain in clones'] = function (test) {
|
||
|
test.expect(1);
|
||
|
|
||
|
function T() {}
|
||
|
|
||
|
var a = new T();
|
||
|
var b = clone(a);
|
||
|
test.strictEqual(Object.getPrototypeOf(a), Object.getPrototypeOf(b));
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['parent prototype is overriden with prototype provided'] = function (test) {
|
||
|
test.expect(1);
|
||
|
|
||
|
function T() {}
|
||
|
|
||
|
var a = new T();
|
||
|
var b = clone(a, true, Infinity, null);
|
||
|
test.strictEqual(b.__defineSetter__, undefined);
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['clone object with null children'] = function (test) {
|
||
|
test.expect(1);
|
||
|
var a = {
|
||
|
foo: {
|
||
|
bar: null,
|
||
|
baz: {
|
||
|
qux: false
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var b = clone(a);
|
||
|
|
||
|
test.deepEqual(b, a);
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['clone instance with getter'] = function (test) {
|
||
|
test.expect(1);
|
||
|
function Ctor() {};
|
||
|
Object.defineProperty(Ctor.prototype, 'prop', {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function() {
|
||
|
return 'value';
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var a = new Ctor();
|
||
|
var b = clone(a);
|
||
|
|
||
|
test.strictEqual(b.prop, 'value');
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports['get RegExp flags'] = function (test) {
|
||
|
test.strictEqual(clone.__getRegExpFlags(/a/), '' );
|
||
|
test.strictEqual(clone.__getRegExpFlags(/a/i), 'i' );
|
||
|
test.strictEqual(clone.__getRegExpFlags(/a/g), 'g' );
|
||
|
test.strictEqual(clone.__getRegExpFlags(/a/gi), 'gi');
|
||
|
test.strictEqual(clone.__getRegExpFlags(/a/m), 'm' );
|
||
|
|
||
|
test.done();
|
||
|
};
|
||
|
|
||
|
exports["recognize Array object"] = function (test) {
|
||
|
var results = apartContext(null, "results = [1, 2, 3]", function(alien) {
|
||
|
var local = [4, 5, 6];
|
||
|
test.ok(clone.__isArray(alien)); // recognize in other context.
|
||
|
test.ok(clone.__isArray(local)); // recognize in local context.
|
||
|
test.ok(!clone.__isDate(alien));
|
||
|
test.ok(!clone.__isDate(local));
|
||
|
test.ok(!clone.__isRegExp(alien));
|
||
|
test.ok(!clone.__isRegExp(local));
|
||
|
test.done();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
exports["recognize Date object"] = function (test) {
|
||
|
var results = apartContext(null, "results = new Date()", function(alien) {
|
||
|
var local = new Date();
|
||
|
|
||
|
test.ok(clone.__isDate(alien)); // recognize in other context.
|
||
|
test.ok(clone.__isDate(local)); // recognize in local context.
|
||
|
test.ok(!clone.__isArray(alien));
|
||
|
test.ok(!clone.__isArray(local));
|
||
|
test.ok(!clone.__isRegExp(alien));
|
||
|
test.ok(!clone.__isRegExp(local));
|
||
|
|
||
|
test.done();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
exports["recognize RegExp object"] = function (test) {
|
||
|
var results = apartContext(null, "results = /foo/", function(alien) {
|
||
|
var local = /bar/;
|
||
|
|
||
|
test.ok(clone.__isRegExp(alien)); // recognize in other context.
|
||
|
test.ok(clone.__isRegExp(local)); // recognize in local context.
|
||
|
test.ok(!clone.__isArray(alien));
|
||
|
test.ok(!clone.__isArray(local));
|
||
|
test.ok(!clone.__isDate(alien));
|
||
|
test.ok(!clone.__isDate(local));
|
||
|
test.done();
|
||
|
});
|
||
|
};
|