diff --git a/CHANGELOG.md b/CHANGELOG.md index 95d47fcc..6b591834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.39.3 + +* Adding `#isEqual` to Set helpers. + ## 0.39.2 * Fixing typings of low-level structure consuming methods (@jerome-benoit). diff --git a/set.js b/set.js index e0d020bb..8188e01c 100644 --- a/set.js +++ b/set.js @@ -181,6 +181,33 @@ exports.isSubset = function(A, B) { return true; }; + +/** + * Function returning whether A equals B (same size and B has all elements of A) + * + * @param {Set} A - First set. + * @param {Set} B - Second set. + * @return {boolean} + */ +exports.isEqual = function(A, B) { + var iterator = A.values(), + step; + + // Shortcuts + if (A === B) + return true; + + if (A.size !== B.size) + return false; + + while ((step = iterator.next(), !step.done)) { + if (!B.has(step.value)) + return false; + } + + return true; +}; + /** * Function returning whether A is a superset of B. * diff --git a/test/set.js b/test/set.js index 8624e2cb..7f264f65 100644 --- a/test/set.js +++ b/test/set.js @@ -11,23 +11,93 @@ describe('Set functions', function() { describe('#.intersection', function() { it('should properly compute the intersection of two sets.', function() { - var A = new Set([1, 2, 3]), - B = new Set([2, 3, 4]); + var Exemplar = new Set([2, 3, 1]); + var Equiv = new Set([1, 2, 3]); + var Missing1 = new Set([2, 3]); + var Extra45 = new Set([1, 2, 3, 4, 5]); + var Disjoint = new Set([7, 8, 9]); + var Empty = new Set([]) + // + var WithItself = functions.intersection(Exemplar, Exemplar); + assert.deepStrictEqual(Array.from(WithItself), [2, 3, 1]); + var WithEquiv = functions.intersection(Exemplar, Equiv); + assert.deepStrictEqual(Array.from(WithEquiv), [2, 3, 1]); + var WithSubset = functions.intersection(Exemplar, Missing1); + assert.deepStrictEqual(Array.from(WithSubset), [2, 3]); + var WithExtras = functions.intersection(Exemplar, Extra45); + assert.deepStrictEqual(Array.from(WithExtras), [2, 3, 1]); + var WithDisjoint = functions.intersection(Exemplar, Disjoint); + assert.deepStrictEqual(Array.from(WithDisjoint), []); + var WithEmpty = functions.intersection(Exemplar, Empty); + assert.deepStrictEqual(Array.from(WithEmpty), []); + }); - var I = functions.intersection(A, B); + it('Makes no guarantees for element ordering.', function() { + // To be clear: it *currently* preserves the order of the earliest of + // sets with the smallest size, but do not depend on this behavior. + // + var Exemplar = new Set([2, 3, 99, 1, 10]); + var Equiv = new Set([1, 2, 3, 10, 99]); + var SubsetA = new Set([99, 3, 2]); + var SubsetB = new Set([3, 99, 2]); + // + var R1 = functions.intersection(Exemplar, Equiv); + assert.deepStrictEqual(Array.from(R1), [2, 3, 99, 1, 10]); + // + var R2 = functions.intersection(Equiv, Exemplar); + assert.deepStrictEqual(Array.from(R2), [1, 2, 3, 10, 99]); + // + var R3 = functions.intersection(Exemplar, Equiv, SubsetA); + assert.deepStrictEqual(Array.from(R3), [99, 3, 2]); + // + var R4 = functions.intersection(Exemplar, SubsetB, Equiv, SubsetA); + assert.deepStrictEqual(Array.from(R4), [3, 99, 2]); + }); - assert.deepStrictEqual(Array.from(I), [2, 3]); + it('compares identity, not equivalence.', function() { + var arrE1 = [] + var arrE2 = [] + var arrN1 = [1] + var arrN2 = [1] + var Exemplar = new Set([1, 2, 3, 'same', arrE1, arrN1]); + var NoneIdentical = new Set([2, 3, 'same', arrE2, arrN2]); + var SomeIdentical = new Set([arrN2, 2, 3, 'same', arrE1]); + // + var WithNoneI = functions.intersection(Exemplar, NoneIdentical); + assert.deepStrictEqual(Array.from(WithNoneI), [2, 3, 'same']); + var WithSomeI = functions.intersection(Exemplar, SomeIdentical); + assert.deepStrictEqual(Array.from(WithSomeI), [2, 3, 'same', arrE1]); }); - it('should be variadic.', function() { - var A = new Set([1, 2, 3, 4]), - B = new Set([2, 3, 4]), - C = new Set([1, 4]), - D = new Set([4, 5, 6]); + it('returns a new set, modifying none', function() { + var Exemplar = new Set([1, 2, 3]); + var Missing1 = new Set([2, 3]); + var Extra45 = new Set([1, 2, 3, 4, 5]); + var Disjoint = new Set([7, 8, 9]); + // + functions.intersection(Exemplar, Missing1, Extra45, Disjoint); + // + assert.deepStrictEqual(Array.from(Exemplar), [1, 2, 3]); + assert.deepStrictEqual(Array.from(Missing1), [2, 3]); + assert.deepStrictEqual(Array.from(Extra45), [1, 2, 3, 4, 5]); + assert.deepStrictEqual(Array.from(Disjoint), [7, 8, 9]); + }); + + it('should be variadic (work with multiple sets).', function() { + var Exemplar = new Set([1, 2, 3]); + var Equiv = new Set([1, 2, 3]); + var Missing1 = new Set([2, 3]); + var Extra45 = new Set([1, 2, 3, 4, 5]); + var Disjoint = new Set([7, 8, 9]); + var Empty = new Set([]) - var I = functions.intersection(A, B, C, D); + var I1 = functions.intersection(Exemplar, Missing1, Extra45); - assert.deepStrictEqual(Array.from(I), [4]); + assert.deepStrictEqual(Array.from(I1), [2, 3]); + + var I2 = functions.intersection(Exemplar, Missing1, Extra45, Disjoint); + + assert.deepStrictEqual(Array.from(I2), []); }); }); @@ -82,21 +152,52 @@ describe('Set functions', function() { it('should properly return if the first set is a subset of the second.', function() { var A = new Set([1, 2]), B = new Set([1, 2, 3]), - C = new Set([2, 4]); + C = new Set([2, 4]), + Empty = new Set([]); assert.strictEqual(functions.isSubset(A, B), true); assert.strictEqual(functions.isSubset(C, B), false); + assert.strictEqual(functions.isSubset(Empty, B), true); + assert.strictEqual(functions.isSubset(B, Empty), false); + assert.strictEqual(functions.isSubset(Empty, Empty), true); + }); + }); + + describe('#.isEqual', function() { + it('should properly return if the first set is equal to the second set.', function() { + var Exemplar = new Set([1, 2, 3]), + SameObj = Exemplar, + YepEqualsTo = new Set([1, 2, 3]), + MoreEls = new Set([1, 2, 3, 4]), + FewerEls = new Set([1]), + DifferentEls = new Set([1, 2, 4]), + Empty = new Set([]); + + assert.strictEqual(functions.isEqual(Exemplar, Exemplar), true); + assert.strictEqual(functions.isEqual(SameObj, Exemplar), true); + assert.strictEqual(functions.isEqual(YepEqualsTo, Exemplar), true); + assert.strictEqual(functions.isEqual(Empty, Empty), true); + // + assert.strictEqual(functions.isEqual(MoreEls, Exemplar), false); + assert.strictEqual(functions.isEqual(FewerEls, Exemplar), false); + assert.strictEqual(functions.isEqual(DifferentEls, Exemplar), false); + assert.strictEqual(functions.isEqual(Empty, Exemplar), false); + assert.strictEqual(functions.isEqual(Exemplar, Empty), false); }); }); describe('#.isSuperset', function() { - it('should properly return if the first set is a subset of the second.', function() { + it('should properly return if the first set is a superset of the second.', function() { var A = new Set([1, 2]), B = new Set([1, 2, 3]), - C = new Set([2, 4]); + C = new Set([2, 4]), + Empty = new Set([]); assert.strictEqual(functions.isSuperset(B, A), true); assert.strictEqual(functions.isSuperset(B, C), false); + assert.strictEqual(functions.isSuperset(B, Empty), true); + assert.strictEqual(functions.isSuperset(Empty, B), false); + assert.strictEqual(functions.isSuperset(Empty, Empty), true); }); }); @@ -107,6 +208,10 @@ describe('Set functions', function() { functions.add(A, new Set([2, 3])); assert.deepStrictEqual(Array.from(A), [1, 2, 3]); + + functions.add(A, new Set()); + + assert.deepStrictEqual(Array.from(A), [1, 2, 3]); }); }); @@ -117,16 +222,65 @@ describe('Set functions', function() { functions.subtract(A, new Set([2, 3])); assert.deepStrictEqual(Array.from(A), [1]); + + functions.subtract(A, new Set()); + + assert.deepStrictEqual(Array.from(A), [1]); + }); + + it('should properly subtract sets from an empty set.', function() { + var Empty = new Set([]); + + functions.subtract(Empty, new Set([2, 3])); + + assert.deepStrictEqual(Array.from(Empty), []); + + functions.subtract(Empty, new Set()); + + assert.deepStrictEqual(Array.from(Empty), []); }); }); describe('#.intersect', function() { - it('should properly intersect the second set to the first.', function() { - var A = new Set([1, 2]); + var Equiv = new Set([1, 2, 3]); + var Missing1 = new Set([2, 3]); + var Disjoint = new Set([7, 8, 9]); + var Empty = new Set([]) + + it('should properly intersect overlapping sets.', function() { + var Exemplar = new Set([1, 2, 3]); + functions.intersect(Exemplar, Missing1) + + assert.deepStrictEqual(Array.from(Exemplar), [2, 3]); + assert.deepStrictEqual(Array.from(Missing1), [2, 3]); + }); + + it('should properly intersect equivalent sets.', function() { + var Exemplar = new Set([1, 2, 3]); + functions.intersect(Exemplar, Exemplar) + + assert.deepStrictEqual(Array.from(Exemplar), [1, 2, 3]); + + functions.intersect(Exemplar, Equiv) + + assert.deepStrictEqual(Array.from(Exemplar), [1, 2, 3]); + assert.deepStrictEqual(Array.from(Equiv), [1, 2, 3]); + }); + + it('should properly intersect disjoint sets.', function() { + var Exemplar = new Set([1, 2, 3]); + + functions.intersect(Exemplar, Disjoint); + + assert.deepStrictEqual(Array.from(Exemplar), []); + assert.deepStrictEqual(Array.from(Disjoint), [7, 8, 9]); + + Exemplar = new Set([1, 2, 3]); - functions.intersect(A, new Set([2, 3])); + functions.intersect(Exemplar, Empty); - assert.deepStrictEqual(Array.from(A), [2]); + assert.deepStrictEqual(Array.from(Exemplar), []); + assert.deepStrictEqual(Array.from(Empty), []); }); });