es6-collections
Version:
ES6 Harmony like collections such Map, WeakMap, and Set
478 lines (437 loc) • 12.7 kB
JavaScript
// test the polyfill
(this.window || global).Map = undefined;
(this.window || global).Set = undefined;
(this.window || global).WeakMap = undefined;
(this.window || global).WeakSet = undefined;
var assert = require('better-assert');
// require('../index');
require('../es6-collections');
describe('ES Collections test', function(){
it("WeakMap existence", function () {
assert(WeakMap);
});
it("WeakMap constructor behavior", function () {
assert(new WeakMap instanceof WeakMap);
assert(new WeakMap() instanceof WeakMap);
var a = {};
var b = {};
var c = new WeakMap();
var m = new WeakMap([[a,1], [b,2], [c, 3]]);
assert(m.has(a));
assert(m.has(b));
assert(m.has(c));
if ("__proto__" in {}) {
assert((new WeakMap).__proto__.isPrototypeOf(new WeakMap()));
assert((new WeakMap).__proto__ === WeakMap.prototype);
}
});
it("WeakMap#has", function () {
var
o = new WeakMap(),
generic = {},
callback = function () {}
;
assert(false === o.has(callback));
o.set(callback, generic);
assert(true === o.has(callback));
});
it("WeakMap#get", function () {
var
o = new WeakMap(),
generic = {},
callback = function () {}
;
//:was assert(o.get(callback, 123) === 123);
o.set(callback, generic);
assert(o.get(callback, 123) === generic);
assert(o.get(callback) === generic);
});
it("WeakMap#set", function () {
var
o = new WeakMap(),
generic = {},
callback = function () {}
;
o.set(callback, generic);
assert(o.get(callback) === generic);
o.set(callback, callback);
assert(o.get(callback) === callback);
o.set(callback, o);
assert(o.get(callback) === o);
o.set(o, callback);
assert(o.get(o) === callback);
});
it("WeakMap#['delete']", function () {
var
o = new WeakMap(),
generic = {},
callback = function () {}
;
o.set(callback, generic);
o.set(generic, callback);
o.set(o, callback);
assert(o.has(callback) && o.has(generic) && o.has(o));
o["delete"](callback);
o["delete"](generic);
o["delete"](o);
assert(!o.has(callback) && !o.has(generic) && !o.has(o));
assert(o["delete"](o) === false);
o.set(o, callback);
assert(o["delete"](o));
});
it("non object key throws an error", function () {
var o = new WeakMap();
try {
o.set("key", o);
assert(false);
} catch(emAll) {
assert(true);
}
});
it("Map existence", function () {
assert(Map);
});
it("Map constructor behavior", function () {
assert(new Map instanceof Map);
assert(new Map() instanceof Map);
var a = 1;
var b = {};
var c = new Map();
var m = new Map([[1,1], [b,2], [c, 3]]);
assert(m.has(a));
assert(m.has(b));
assert(m.has(c));
assert(m.size, 3);
if ("__proto__" in {}) {
assert((new Map).__proto__.isPrototypeOf(new Map()));
assert((new Map).__proto__ === Map.prototype);
}
});
it("Map#size - Mozilla only", function () {
var
o = new Map()
;
if ("size" in o) {
assert(o.size === 0);
o.set("a", "a");
assert(o.size === 1);
o["delete"]("a");
assert(o.size === 0);
}
});
it("Map#has", function () {
var
o = new Map(),
generic = {},
callback = function () {}
;
assert(false === o.has(callback));
o.set(callback, generic);
assert(true === o.has(callback));
});
it("Map#get", function () {
var
o = new Map(),
generic = {},
callback = function () {}
;
//:was assert(o.get(callback, 123) === 123);
o.set(callback, generic);
assert(o.get(callback, 123) === generic);
assert(o.get(callback) === generic);
});
it("Map#set", function () {
var
o = new Map(),
generic = {},
callback = function () {}
;
o.set(callback, generic);
assert(o.get(callback) === generic);
o.set(callback, callback);
assert(o.get(callback) === callback);
o.set(callback, o);
assert(o.get(callback) === o);
o.set(o, callback);
assert(o.get(o) === callback);
o.set(NaN, generic);
assert(o.has(NaN));
assert(o.get(NaN) === generic);
o.set("key", undefined);
assert(o.has("key"));
assert(o.get("key") === undefined);
assert(!o.has(-0));
assert(!o.has(0));
o.set(-0, callback);
assert(o.has(-0));
assert(o.has(0));
assert(o.get(-0) === callback);
assert(o.get(0) === callback);
o.set(0, generic);
assert(o.has(-0));
assert(o.has(0));
assert(o.get(-0) === generic);
assert(o.get(0) === generic);
});
it("Map#['delete']", function () {
var
o = new Map(),
generic = {},
callback = function () {}
;
o.set(callback, generic);
o.set(generic, callback);
o.set(o, callback);
assert(o.has(callback) && o.has(generic) && o.has(o));
o["delete"](callback);
o["delete"](generic);
o["delete"](o);
assert(!o.has(callback) && !o.has(generic) && !o.has(o));
assert(o["delete"](o) === false);
o.set(o, callback);
assert(o["delete"](o));
});
it("non object key does not throw an error", function () {
var o = new Map();
try {
o.set("key", o);
assert(true);
} catch(emAll) {
assert(false);
}
});
it("keys, values, entries behavior", function () {
// test that things get returned in insertion order as per the specs
var o = new Map([["1", 1], ["2", 2], ["3", 3]]);
var keys = o.keys(), values = o.values();
var k = keys.next(), v = values.next();
assert(k.value === "1" && v.value === 1);
o.delete("2");
k = keys.next(), v = values.next();
assert(k.value === "3" && v.value === 3);
// insertion of previously-removed item goes to the end
o.set("2", 2);
k = keys.next(), v = values.next();
assert(k.value === "2" && v.value === 2);
// when called again, new iterator starts from beginning
var entriesagain = o.entries();
assert(entriesagain.next().value[0] === "1");
assert(entriesagain.next().value[0] === "3");
assert(entriesagain.next().value[0] === "2");
// after a iterator is finished, don't return any more elements
k = keys.next(), v = values.next();
assert(k.done && v.done);
k = keys.next(), v = values.next();
assert(k.done && v.done);
o.set("4", 4);
k = keys.next(), v = values.next();
assert(k.done && v.done);
// new element shows up in iterators that didn't yet finish
assert(entriesagain.next().value[0] === "4");
assert(entriesagain.next().done);
});
it("Map#forEach", function () {
var o = new Map(), i;
o.set("key 0", 0);
o.set("key 1", 1);
if ("forEach" in o) {
o.forEach(function (value, key, obj) {
assert(key === "key " + value);
assert(obj === o);
// even if dropped, keeps looping
o["delete"](key);
});
assert(!o.size);
}
});
it("Map#forEach with mutations", function () {
var o = new Map([["0", 0], ["1", 1], ["2", 2]]), seen = [];
o.forEach(function (value, key, obj) {
seen.push(value);
assert(obj === o);
assert(""+value === key);
// mutations work as expected
if (value === 1) {
o.delete("0"); // remove from before current index
o.delete("2"); // remove from after current index
o.set("3", 3); // insertion
} else if (value === 3) {
o.set("0", 0); // insertion at the end
}
});
assert(JSON.stringify(seen) === JSON.stringify([0, 1, 3, 0]));
assert(JSON.stringify(o._values) === JSON.stringify([1, 3, 0]));
});
it("Map#clear", function(){
var o = new Map();
o.set(1, '1');
o.set(2, '2');
o.set(3, '3');
o.clear();
assert(!o.size);
});
it("Set existence", function () {
assert(Set);
});
it("Set constructor behavior", function () {
assert(new Set instanceof Set);
assert(new Set() instanceof Set);
var s = new Set([1,2]);
assert(s.has(1));
assert(s.has(2));
assert(s.size, 2);
if ("__proto__" in {}) {
assert((new Set).__proto__.isPrototypeOf(new Set()));
assert((new Set).__proto__ === Set.prototype);
}
});
it("Set#size - Mozilla only", function () {
var
o = new Set()
;
if ("size" in o) {
assert(o.size === 0);
o.add("a");
assert(o.size === 1);
o["delete"]("a");
assert(o.size === 0);
}
});
it("Set#add", function () {
var o = new Set();
assert(o.add(NaN));
assert(o.has(NaN));
});
it("Set#['delete']", function () {
var
o = new Set(),
generic = {},
callback = function () {}
;
o.add(callback);
o.add(generic);
o.add(o);
assert(o.has(callback) && o.has(generic) && o.has(o));
o["delete"](callback);
o["delete"](generic);
o["delete"](o);
assert(!o.has(callback) && !o.has(generic) && !o.has(o));
assert(o["delete"](o) === false);
o.add(o);
assert(o["delete"](o) === true);
});
it("values behavior", function () {
// test that things get returned in insertion order as per the specs
var o = new Set([1, 2, 3]);
assert(o.keys === o.values); // same function, as per the specs
var values = o.values();
var v = values.next();
assert(v.value === 1);
o.delete(2);
v = values.next();
assert(v.value === 3);
// insertion of previously-removed item goes to the end
o.add(2);
v = values.next();
assert(v.value === 2);
// when called again, new iterator starts from beginning
var entriesagain = o.entries();
assert(entriesagain.next().value[1] === 1);
assert(entriesagain.next().value[1] === 3);
assert(entriesagain.next().value[1] === 2);
// after a iterator is finished, don't return any more elements
v = values.next();
assert(v.done);
v = values.next();
assert(v.done);
o.add(4);
v = values.next();
assert(v.done);
// new element shows up in iterators that didn't yet finish
assert(entriesagain.next().value[1] === 4);
assert(entriesagain.next().done);
});
it("Set#has", function () {
var
o = new Set(),
generic = {},
callback = function () {}
;
assert(false === o.has(callback));
o.add(callback);
assert(true === o.has(callback));
});
it("Set#forEach", function () {
var o = new Set(), i = 0;
o.add("value 0");
o.add("value 1");
if ("forEach" in o) {
o.forEach(function (value, sameValue, obj) {
assert(value === "value " + i++);
assert(obj === o);
assert(value === sameValue);
// even if dropped, keeps looping
o["delete"](value);
});
assert(!o.size);
}
});
it("Set#forEach with mutations", function () {
var o = new Set([0, 1, 2]), seen = [];
o.forEach(function (value, sameValue, obj) {
seen.push(value);
assert(obj === o);
assert(value === sameValue);
// mutations work as expected
if (value === 1) {
o.delete(0); // remove from before current index
o.delete(2); // remove from after current index
o.add(3); // insertion
} else if (value === 3) {
o.add(0); // insertion at the end
}
});
assert(JSON.stringify(seen) === JSON.stringify([0, 1, 3, 0]));
assert(JSON.stringify(o._values) === JSON.stringify([1, 3, 0]));
});
it("Set#clear", function(){
var o = new Set();
o.add(1);
o.add(2);
o.clear();
assert(!o.size);
});
it("WeakSet existence", function () {
assert(WeakSet);
});
it("WeakSet constructor behavior", function () {
assert(new WeakSet instanceof WeakSet);
assert((new WeakSet) instanceof WeakSet);
var a = {}, b = {};
var s = new WeakSet([a, b]);
assert(s.has(a) && s.has(b));
if ("__proto__" in {}) {
assert((new WeakSet).__proto__.isPrototypeOf(new WeakSet()));
assert((new WeakSet).__proto__ === WeakSet.prototype);
}
});
it("Set#add, WeakSet#add, Map#set and WeakMap#set are chainable now", function(){
var s = new Set();
var ws = new WeakSet();
var m = new Map();
var wm = new WeakMap();
var a = {}, b = {};
s.add(1).add(2);
assert(s.has(1) && s.has(2) && s.size === 2);
ws.add(a).add(b);
assert(ws.has(a) && ws.has(b));
m.set(1, 1).set(a, 2);
assert(m.has(1) && m.has(a) && m.size === 2);
wm.set(a, b).set(b, a);
assert(wm.get(a) === b && wm.get(b) === a);
});
it("Recognize any iterable as the constructor input", function(){
var a = new Set(new Set([1,2]));
assert(a.has(1));
});
});