UNPKG

lively.lang

Version:

JavaScript utils providing useful abstractions for working with collections, functions, objects.

230 lines (196 loc) 8.93 kB
/*global beforeEach, afterEach, describe, it, setInterval, clearInterval, setTimeout*/ import { expect } from "mocha-es6"; import { mapToMatchingIndexes, isInterval, sort, compare, coalesce, intervalsInRangeDo, intervalsInbetween, mergeOverlapping, coalesceOverlapping } from "../interval.js"; describe('interval', function() { it("tests for interval type", function() { expect(isInterval([1,2])).to.equal(true); expect(isInterval([1,2,'some addition'])).to.equal(true); expect(isInterval([1,1])).to.equal(true); expect(isInterval([1,0])).to.equal(false); }) it("compares intervals", function() { var inputAndExpected = [ [1,2], [3,4], -3, // less and at border [1,2], [2,3], -2, // less and overlapping [1,3], [2,4], -1, [1,5], [2,4], -1, [1,5], [2,4], -1, [1,5], [1,6], -1, // // equal [1,1], [1,1], 0, // // greater and pverlapping [2,4], [1,3], 1, // // greater and at border [3,4], [1,3], 2, // // greater and non-overlapping [2,4], [0,1], 3]; for (var i = 0; i < inputAndExpected.length; i += 3) { var expected = inputAndExpected[i+2], a = inputAndExpected[i+0], b = inputAndExpected[i+1]; expect(expected).to.equal(compare(a, b),expected + ' not result of cmp ' + a + ' vs ' + b); } // // less and non-overlapping // expect(-2).to.equal(Interval.compare([1,2], [3,4]),'< n-o'); // // less and overlapping // expect(-1).to.equal(Interval.compare([1,2], [2,3]),'< o'); // expect(-1).to.equal(Interval.compare([1,3], [2,4]),'< o'); // expect(-1).to.equal(Interval.compare([1,5], [2,4]),'< o'); // expect(-1).to.equal(Interval.compare([1,5], [2,4]),'< o'); // expect(-1).to.equal(Interval.compare([1,5], [1,6]),'< o'); // // // equal // expect(0).to.equal(Interval.compare([1,1], [1,1]),'='); // // // greater and overlapping // expect(1).to.equal(Interval.compare([3,4], [1,3]),'> o'); // expect(1).to.equal(Interval.compare([2,4], [1,3]),'> o'); // // // greater and non-overlapping // expect(2).to.equal(Interval.compare([2,4], [0,1]),'> n-o'); }) it("sorts intervals", function() { expect([]).to.eql(sort([])); expect([[1,2], [2,3]]).to.eql(sort([[1, 2], [2, 3]])); expect([[1,2], [1,3]]).to.eql(sort([[1, 3], [1, 2]])); expect([[1,2], [4,6], [5,9]]).to.eql(sort([[4,6], [1,2], [5,9]])); }) it("coalesces two overlapping intervals", function() { expect(null).to.eql(coalesce([1,4], [5,7])); expect([1, 5]).to.eql(coalesce([1,3], [2, 5])); expect([1, 5]).to.eql(coalesce([3, 5], [1,3])); // this.assertEqualState([1, 5], Interval.coalesce([1, 5], [2,3])); // this.assertEqualState([3,6], Interval.coalesce([3,6], [4,5])); // var callbackArgs; // Interval.coalesce([3,6], [4,5], function() { callbackArgs = Array.from(arguments); }) // this.assertEqualState([[3,6], [4,5], [3,6]], callbackArgs, 'callback'); }); it("coalesces any number of overlapping intervals", function() { expect([]).to.eql(coalesceOverlapping([])); expect([[1, 5]]).to.eql(coalesceOverlapping([[1,3], [2, 4], [2, 5]])); expect([[1, 3], [5, 10]]).to.eql(coalesceOverlapping([[1,3], [5,9 ], [6, 10]])); expect([[1, 8], [9, 10], [14, 21]]).to.eql(coalesceOverlapping([[9,10], [1,8], [3, 7], [15, 20], [14, 21]])); // with merge func var result = coalesceOverlapping( [[3,5, 'b'], [1,4, 'a'], [8, 10, 'c']], function(a, b, merged) { merged.push(a[2] + b[2]) }); expect([[1,5, 'ab'], [8, 10, 'c']]).to.eql(result); }); it("coalesces identical intervals", function() { expect([[1,3]]).to.eql(coalesceOverlapping([[1,3], [1, 3]])); }); it("finds free intervals inbetween", function() { expect([[0,10]]).to.eql(intervalsInbetween(0, 10, [])); expect([[5,10]]).to.eql(intervalsInbetween(0, 10, [[0, 5]])); expect([[0,3], [5,10]]).to.eql(intervalsInbetween(0, 10, [[3, 5]])); expect([[1,3], [5,8]]).to.eql(intervalsInbetween(0, 10, [[0, 1], [3, 5], [8, 10]])); expect([[5,8]]).to.eql(intervalsInbetween(0, 10, [[0, 1], [1, 5], [8, 10]])); expect([[0,5]]).to.eql(intervalsInbetween(0, 5, [[8, 10]])); expect([[0,3]]).to.eql(intervalsInbetween(0, 5, [[3, 10]])); expect([]).to.eql(intervalsInbetween(0, 5, [[0, 6]])); }); it("enumerates intervals using withIntervalsInRangeDo", function() { expect([[0,2, false], [2,3, true], [3,5, false], [5,8, true], [8,10, false]]).to.eql(intervalsInRangeDo( 0, 10, [[8, 10], [0, 2], [3, 5]], function(interval, isNew) { interval.push(isNew); return interval; })); expect([[0,3, true], [3,5, 'x', false]]).to.eql(intervalsInRangeDo( 0, 5, [[3, 6, 'x'], [6, 20, 'y']], function(interval, isNew) { interval.push(isNew); return interval; }),"slice interval in back"); expect([[1,2, 'x', false], [2,5, true]]).to.eql(intervalsInRangeDo( 1, 5, [[-4,0, 'y'], [0, 2, 'x']], function(interval, isNew) { interval.push(isNew); return interval; }),"slice interval in front"); expect([[0,1, 'ab'], [1,2, 'c']]).to.eql(intervalsInRangeDo( 0, 2, [[0,1, 'a'], [0,1, 'b'], [1,2, 'c']], function(interval, isNew) { return interval; }, function(a, b, merged) { merged[2] = a[2] + b[2] }),"identical intervals not merged"); }); it("finds matching intervals", function() { var existingIntervals = [[1,4], [4,5], [5,8], [9,20]]; var test = this, testTable = [ {expected: [[0]], input: [[1,4]]}, {expected: [[0], [0]], input: [[1,4], [1,4]]}, {expected: [[]], input: [[2,4]]}, {expected: [[]], input: [[4,6]]}, {expected: [[1,2], [2,3], []], input: [[4,8], [5,20], [10,20]]} ] testTable.forEach(function(ea) { expect(ea.expected).to.eql( mapToMatchingIndexes(existingIntervals, ea.input), 'On input: ' + ea.input); }); }); it("merges overlapping intervals", function() { return; // WIP var inputsAndExpected = [ {a: [[1,6, 'a'], [7,9, 'b']], b: [], expected: [[1,6, 'a'], [7,9, 'b']]}, {a: [[1,6, 'a'], [6,9, 'b']], b: [[1,3, 'c']], expected: [[1,3, 'ac'], [3,6, 'a'], [7,9, 'b']]}, // {a: [[1,3, 'a'], [6,9, 'b']], // b: [[1,6, 'c']], // expected: [[1,3, 'ac'], [3,6, 'c'], [6,9, 'b']]}, // {a: [[1,3, 'a'], [3,8, 'b']], // b: [[1,6, 'c']], // expected: [[1,3, 'ac'], [3,8, 'bc'], [6,8, 'b']]}, // {a: [[1,3, 'a'], [3,4, 'b']], // b: [[1,2, 'c'], [1,5, 'd']], // expected: [[1,2, 'acd'], [2,3, 'ad'], [3,4, 'bd'], [4,5, 'd']]} ]; function merge(a,b) { return [Math.min(a[0], b[0]), Math.max(a[1], b[1]), a[2] + b[2]] } for (var i = 0; i < inputsAndExpected.length; i++) { var expected = inputsAndExpected[i].expected, a = inputsAndExpected[i].a, b = inputsAndExpected[i].b; expect(expected).to.eql(mergeOverlapping(a, b, merge),expected + ' not result of merge ' + a + ' vs ' + b); } // nothing happens without a merge func // this.assertEqualState([], Interval.mergeOverlapping([])); // this.assertEqualState([[1,2, 'a'], [1,2, 'b']], // Interval.mergeOverlapping([[1,2, 'a'], [1,2, 'b']])); // this.assertEqualState( // [[1,2, 'ab']], // Interval.mergeOverlapping( // [[1,2, 'a'], [1,2, 'b']], // function(a, b) { return [[a[0], a[1], a[2] + b[2]]]; })); // this.assertEqualState( // [[1,2, 'abc']], // Interval.mergeOverlapping( // [[1,2, 'a'], [1,2, 'b'], [1,2, 'c']], // function(a, b) { return [[a[0], a[1], a[2] + b[2]]]; })); // this.assertEqualState( // [[1,3, 'ab'], [3,6, 'b']], // Interval.mergeOverlapping( // [[1,3, 'a'], [1,6, 'b']], // function(a, b) { return [[a[0], a[1], a[2] + b[2]]]; })); // this.assertEqualState( // [[1,2, 'ac'], [2,3, 'abc'], [3, 4, 'bc'], [4, 6, 'c']], // Interval.mergeOverlapping( // [[1,3, 'a'], [2,4, 'b'], [1,6, 'c']], // function(a, b) { return [[a[0], a[1], a[2] + b[2]]]; })); // this.assertEqualState([[1, 5]], Interval.mergeOverlapping([[1,3], [2, 4], [2, 5]])); // this.assertEqualState( // [[1, 3], [5, 10]], // Interval.mergeOverlapping([[1,3], [5,9 ], [6, 10]])); // this.assertEqualState( // [[1, 8], [9, 10], [14, 21]], // Interval.mergeOverlapping([[9,10], [1,8], [3, 7], [15, 20], [14, 21]])); // // with merge func // var result = Interval.mergeOverlapping( // [[3,5, 'b'], [1,4, 'a'], [8, 10, 'c']], // function(a, b, merged) { merged.push(a[2] + b[2]) }); // this.assertEqualState([[1,5, 'ab'], [8, 10, 'c']], result); }); });