pop-clone
Version:
A polymorphic clone operator for arbitrary object graphs
142 lines (120 loc) • 4.08 kB
JavaScript
;
var cloneOperator = require("../pop-clone");
var equalsOperator = require("pop-equals");
describe("clone", function () {
var graph = {
object: {a: 10},
array: [1, 2, 3],
string: "hello",
number: 10,
nestedObject: {
a: {a1: 10, a2: 20},
b: {b1: "a", b2: "c"}
},
nestedArray: [
[1, 2, 3],
[4, 5, 6]
],
mixedObject: {
array: [1, 3, 4],
object: {a: 10, b: 20}
},
mixedArray: [
[],
{a: 10, b: 20}
],
arrayWithHoles: [],
clonable: Object.create({
clone: function () {
return this;
}
})
}
graph.cycle = graph;
graph.arrayWithHoles[10] = 10;
// Not reflexively equal, not equal to clone
//graph.typedObject = Object.create(null);
//graph.typedObject.a = 10;
//graph.typedObject.b = 10;
Object.keys(graph).forEach(function (name) {
var value = graph[name];
it(name + " cloned equals self", function () {
expect(cloneOperator(value)).toEqual(value);
});
});
it("should clone zero levels of depth", function () {
var clone = cloneOperator(graph, 0);
expect(clone).toBe(graph);
});
it("should clone object at one level of depth", function () {
var clone = cloneOperator(graph, 1);
expect(clone).toEqual(graph);
expect(clone).not.toBe(graph);
});
it("should clone object at two levels of depth", function () {
var clone = cloneOperator(graph, 2);
expect(clone).toEqual(graph);
expect(clone.object).not.toBe(graph.object);
expect(clone.object).toEqual(graph.object);
expect(clone.nestedObject.a).toBe(graph.nestedObject.a);
});
it("should clone array at two levels of depth", function () {
var clone = cloneOperator(graph, 2);
expect(clone).toEqual(graph);
});
it("should clone identical values at least once", function () {
var clone = cloneOperator(graph);
expect(clone.cycle).not.toBe(graph.cycle);
});
it("should clone identical values only once", function () {
var clone = cloneOperator(graph);
expect(clone.cycle).toBe(clone);
});
it("should clone clonable", function () {
var clone = cloneOperator(graph);
expect(clone.clonable).toBe(graph.clonable);
});
it("should clone an object with a function property", function () {
var original = {foo: function () {}};
var clone = cloneOperator(original);
expect(clone.foo).toBe(original.foo);
expect(equalsOperator(clone, original)).toBe(true);
});
var object = {a: {a1: 10, a2: 20}, b: {b1: 10, b2: 20}};
it("should clone zero levels", function () {
expect(cloneOperator(object, 0)).toBe(object);
});
it("should clone one level", function () {
var clone = cloneOperator(object, 1);
expect(clone).toEqual(object);
expect(clone).not.toBe(object);
expect(clone.a).toBe(object.a);
});
it("should clone two levels", function () {
var clone = cloneOperator(object, 2);
expect(clone).toEqual(object);
expect(clone).not.toBe(object);
expect(clone.a).not.toBe(object.a);
});
it("should clone with reference cycles", function () {
var cycle = {};
cycle.cycle = cycle;
var clone = cloneOperator(cycle);
expect(clone).toEqual(cycle);
expect(clone).not.toBe(cycle);
expect(clone.cycle).toBe(clone);
});
});
it("delegates to clone method, with less depth", function () {
var object = {
child: {
clone: function (depth, memo) {
expect(memo.has(object)).toBe(true);
expect(depth).toBe(1);
return "hello";
}
}
};
var cloned = cloneOperator(object, 2);
expect(cloned.child).toBe("hello");
});