123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- // Copyright 2009 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- goog.provide('goog.math.RangeSetTest');
- goog.setTestOnly('goog.math.RangeSetTest');
- goog.require('goog.iter');
- goog.require('goog.math.Range');
- goog.require('goog.math.RangeSet');
- goog.require('goog.testing.jsunit');
- /**
- * Produce legible assertion results for comparing ranges. The expected range
- * may be defined as a goog.math.Range or as a two-element array of numbers. If
- * two ranges are not equal, the error message will be in the format:
- * "Expected <[1, 2]> (Object) but was <[3, 4]> (Object)"
- *
- * @param {!goog.math.Range|!Array<number>|string} a A descriptive string or
- * the expected range.
- * @param {!goog.math.Range|!Array<number>} b The expected range when a
- * descriptive string is present, or the range to compare.
- * @param {goog.math.Range=} opt_c The range to compare when a descriptive
- * string is present.
- */
- function assertRangesEqual(a, b, opt_c) {
- var message = opt_c ? a : '';
- var expected = opt_c ? b : a;
- var actual = opt_c ? opt_c : b;
- if (goog.isArray(expected)) {
- assertEquals(
- message + '\n' +
- 'Expected ranges must be specified as goog.math.Range ' +
- 'objects or as 2-element number arrays. Found [' +
- expected.join(', ') + ']',
- 2, expected.length);
- expected = new goog.math.Range(expected[0], expected[1]);
- }
- if (!goog.math.Range.equals(
- /** @type {!goog.math.Range} */ (expected),
- /** @type {!goog.math.Range} */ (actual))) {
- if (message) {
- assertEquals(message, expected, actual);
- } else {
- assertEquals(expected, actual);
- }
- }
- }
- /**
- * Produce legible assertion results for comparing two lists of ranges. Expected
- * lists may be specified as a list of goog.math.Ranges, or as a list of
- * two-element arrays of numbers.
- *
- * @param {Array<goog.math.Range|Array<number>>|string} a A help
- * string or the list of expected ranges.
- * @param {Array<goog.math.Range|Array<number>>} b The list of
- * expected ranges when a descriptive string is present, or the list of
- * ranges to compare.
- * @param {Array<goog.math.Range>=} opt_c The list of ranges to compare when a
- * descriptive string is present.
- */
- function assertRangeListsEqual(a, b, opt_c) {
- var message = opt_c ? a + '\n' : '';
- var expected = opt_c ? b : a;
- var actual = opt_c ? opt_c : b;
- assertEquals(
- message + 'Array lengths unequal.', expected.length, actual.length);
- for (var i = 0; i < expected.length; i++) {
- assertRangesEqual(
- message + 'Range ' + i + ' mismatch.', expected[i], actual[i]);
- }
- }
- function testClone() {
- var r = new goog.math.RangeSet();
- var test = new goog.math.RangeSet(r);
- assertRangeListsEqual([], test.ranges_);
- r.add(new goog.math.Range(-10, -2));
- r.add(new goog.math.Range(2.72, 3.14));
- r.add(new goog.math.Range(8, 11));
- test = r.clone();
- assertRangeListsEqual([[-10, -2], [2.72, 3.14], [8, 11]], test.ranges_);
- var test2 = r.clone();
- assertRangeListsEqual(test.ranges_, test2.ranges_);
- assertNotEquals(
- 'The clones should not share the same list reference.', test.ranges_,
- test2.ranges_);
- for (var i = 0; i < test.ranges_.length; i++) {
- assertNotEquals(
- 'The clones should not share references to ranges.', test.ranges_[i],
- test2.ranges_[i]);
- }
- }
- function testAddNoCorruption() {
- var r = new goog.math.RangeSet();
- var range = new goog.math.Range(1, 2);
- r.add(range);
- assertNotEquals(
- 'Only a copy of the input range should be stored.', range, r.ranges_[0]);
- range.end = 5;
- assertRangeListsEqual(
- 'Modifying an input range after use should not ' +
- 'affect the set.',
- [[1, 2]], r.ranges_);
- }
- function testAdd() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(7, 12));
- assertRangeListsEqual([[7, 12]], r.ranges_);
- r.add(new goog.math.Range(1, 3));
- assertRangeListsEqual([[1, 3], [7, 12]], r.ranges_);
- r.add(new goog.math.Range(13, 18));
- assertRangeListsEqual([[1, 3], [7, 12], [13, 18]], r.ranges_);
- r.add(new goog.math.Range(5, 5));
- assertRangeListsEqual(
- 'Zero length ranges should be ignored.', [[1, 3], [7, 12], [13, 18]],
- r.ranges_);
- var badRange = new goog.math.Range(5, 5);
- badRange.end = 4;
- r.add(badRange);
- assertRangeListsEqual(
- 'Negative length ranges should be ignored.', [[1, 3], [7, 12], [13, 18]],
- r.ranges_);
- r.add(new goog.math.Range(-22, -15));
- assertRangeListsEqual(
- 'Negative ranges should work fine.',
- [[-22, -15], [1, 3], [7, 12], [13, 18]], r.ranges_);
- r.add(new goog.math.Range(3.1, 6.9));
- assertRangeListsEqual(
- 'Non-integer ranges should work fine.',
- [[-22, -15], [1, 3], [3.1, 6.9], [7, 12], [13, 18]], r.ranges_);
- }
- function testAddWithOverlaps() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(7, 12));
- r.add(new goog.math.Range(5, 8));
- assertRangeListsEqual([[5, 12]], r.ranges_);
- r.add(new goog.math.Range(15, 20));
- r.add(new goog.math.Range(18, 25));
- assertRangeListsEqual([[5, 12], [15, 25]], r.ranges_);
- r.add(new goog.math.Range(10, 17));
- assertRangeListsEqual([[5, 25]], r.ranges_);
- r.add(new goog.math.Range(-4, 4.5));
- assertRangeListsEqual([[-4, 4.5], [5, 25]], r.ranges_);
- r.add(new goog.math.Range(4.2, 5.3));
- assertRangeListsEqual([[-4, 25]], r.ranges_);
- }
- function testAddWithAdjacentSpans() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(7, 12));
- r.add(new goog.math.Range(13, 19));
- assertRangeListsEqual([[7, 12], [13, 19]], r.ranges_);
- r.add(new goog.math.Range(4, 6));
- assertRangeListsEqual([[4, 6], [7, 12], [13, 19]], r.ranges_);
- r.add(new goog.math.Range(6, 7));
- assertRangeListsEqual([[4, 12], [13, 19]], r.ranges_);
- r.add(new goog.math.Range(12, 13));
- assertRangeListsEqual([[4, 19]], r.ranges_);
- r.add(new goog.math.Range(19.1, 22));
- assertRangeListsEqual([[4, 19], [19.1, 22]], r.ranges_);
- r.add(new goog.math.Range(19, 19.1));
- assertRangeListsEqual([[4, 22]], r.ranges_);
- r.add(new goog.math.Range(-3, -2));
- assertRangeListsEqual([[-3, -2], [4, 22]], r.ranges_);
- r.add(new goog.math.Range(-2, 4));
- assertRangeListsEqual([[-3, 22]], r.ranges_);
- }
- function testAddWithSubsets() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(7, 12));
- assertRangeListsEqual([[7, 12]], r.ranges_);
- r.add(new goog.math.Range(7, 12));
- assertRangeListsEqual([[7, 12]], r.ranges_);
- r.add(new goog.math.Range(8, 11));
- assertRangeListsEqual([[7, 12]], r.ranges_);
- for (var i = 20; i < 30; i += 2) {
- r.add(new goog.math.Range(i, i + 1));
- }
- assertRangeListsEqual(
- [[7, 12], [20, 21], [22, 23], [24, 25], [26, 27], [28, 29]], r.ranges_);
- r.add(new goog.math.Range(1, 30));
- assertRangeListsEqual([[1, 30]], r.ranges_);
- }
- function testRemove() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(1, 3));
- r.add(new goog.math.Range(7, 8));
- r.add(new goog.math.Range(10, 20));
- r.remove(new goog.math.Range(3, 6));
- assertRangeListsEqual([[1, 3], [7, 8], [10, 20]], r.ranges_);
- r.remove(new goog.math.Range(7, 8));
- assertRangeListsEqual([[1, 3], [10, 20]], r.ranges_);
- r.remove(new goog.math.Range(1, 3));
- assertRangeListsEqual([[10, 20]], r.ranges_);
- r.remove(new goog.math.Range(8, 11));
- assertRangeListsEqual([[11, 20]], r.ranges_);
- r.remove(new goog.math.Range(18, 25));
- assertRangeListsEqual([[11, 18]], r.ranges_);
- r.remove(new goog.math.Range(15, 16));
- assertRangeListsEqual([[11, 15], [16, 18]], r.ranges_);
- r.remove(new goog.math.Range(11, 15));
- assertRangeListsEqual([[16, 18]], r.ranges_);
- r.remove(new goog.math.Range(16, 16));
- assertRangeListsEqual(
- 'Empty ranges should be ignored.', [[16, 18]], r.ranges_);
- r.remove(new goog.math.Range(16, 17));
- assertRangeListsEqual([[17, 18]], r.ranges_);
- r.remove(new goog.math.Range(17, 18));
- assertRangeListsEqual([], r.ranges_);
- }
- function testRemoveWithNonOverlappingRanges() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(10, 20));
- r.remove(new goog.math.Range(5, 8));
- assertRangeListsEqual(
- 'Non-overlapping ranges should be ignored.', [[10, 20]], r.ranges_);
- r.remove(new goog.math.Range(20, 30));
- assertRangeListsEqual(
- 'Non-overlapping ranges should be ignored.', [[10, 20]], r.ranges_);
- r.remove(new goog.math.Range(15, 15));
- assertRangeListsEqual(
- 'Zero-length ranges should be ignored.', [[10, 20]], r.ranges_);
- }
- function testRemoveWithIdenticalRanges() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(10, 20));
- r.add(new goog.math.Range(30, 40));
- r.add(new goog.math.Range(50, 60));
- assertRangeListsEqual([[10, 20], [30, 40], [50, 60]], r.ranges_);
- r.remove(new goog.math.Range(30, 40));
- assertRangeListsEqual([[10, 20], [50, 60]], r.ranges_);
- r.remove(new goog.math.Range(50, 60));
- assertRangeListsEqual([[10, 20]], r.ranges_);
- r.remove(new goog.math.Range(10, 20));
- assertRangeListsEqual([], r.ranges_);
- }
- function testRemoveWithOverlappingSubsets() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(1, 10));
- r.remove(new goog.math.Range(1, 4));
- assertRangeListsEqual([[4, 10]], r.ranges_);
- r.remove(new goog.math.Range(8, 10));
- assertRangeListsEqual([[4, 8]], r.ranges_);
- }
- function testRemoveMultiple() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(5, 8));
- r.add(new goog.math.Range(10, 20));
- r.add(new goog.math.Range(30, 35));
- for (var i = 20; i < 30; i += 2) {
- r.add(new goog.math.Range(i, i + 1));
- }
- assertRangeListsEqual(
- 'Setting up the test data seems to have failed, how embarrassing.',
- [[5, 8], [10, 21], [22, 23], [24, 25], [26, 27], [28, 29], [30, 35]],
- r.ranges_);
- r.remove(new goog.math.Range(15, 32));
- assertRangeListsEqual([[5, 8], [10, 15], [32, 35]], r.ranges_);
- }
- function testRemoveWithRealNumbers() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(2, 4));
- r.remove(new goog.math.Range(1.1, 2.72));
- assertRangeListsEqual([[2.72, 4]], r.ranges_);
- r.remove(new goog.math.Range(3.14, 5));
- assertRangeListsEqual([[2.72, 3.14]], r.ranges_);
- r.remove(new goog.math.Range(2.8, 3));
- assertRangeListsEqual([[2.72, 2.8], [3, 3.14]], r.ranges_);
- }
- function testEquals() {
- var a = new goog.math.RangeSet();
- var b = new goog.math.RangeSet();
- assertTrue(goog.math.RangeSet.equals(a, b));
- a.add(new goog.math.Range(3, 9));
- assertFalse(goog.math.RangeSet.equals(a, b));
- b.add(new goog.math.Range(4, 9));
- assertFalse(goog.math.RangeSet.equals(a, b));
- b.add(new goog.math.Range(3, 4));
- assertTrue(goog.math.RangeSet.equals(a, b));
- a.add(new goog.math.Range(12, 14));
- b.add(new goog.math.Range(11, 14));
- assertFalse(goog.math.RangeSet.equals(a, b));
- a.add(new goog.math.Range(11, 12));
- assertTrue(goog.math.RangeSet.equals(a, b));
- }
- function testContains() {
- var r = new goog.math.RangeSet();
- assertFalse(r.contains(7, 9));
- r.add(new goog.math.Range(5, 6));
- r.add(new goog.math.Range(10, 20));
- assertFalse(r.contains(new goog.math.Range(7, 9)));
- assertFalse(r.contains(new goog.math.Range(9, 11)));
- assertFalse(r.contains(new goog.math.Range(18, 22)));
- assertTrue(r.contains(new goog.math.Range(17, 19)));
- assertTrue(r.contains(new goog.math.Range(5, 6)));
- assertTrue(r.contains(new goog.math.Range(5.9, 5.999)));
- assertFalse(
- 'An empty input range should always return false.',
- r.contains(new goog.math.Range(15, 15)));
- var badRange = new goog.math.Range(15, 15);
- badRange.end = 14;
- assertFalse(
- 'An invalid range should always return false.', r.contains(badRange));
- }
- function testContainsValue() {
- var r = new goog.math.RangeSet();
- assertFalse(r.containsValue(5));
- r.add(new goog.math.Range(1, 4));
- r.add(new goog.math.Range(10, 20));
- assertFalse(r.containsValue(0));
- assertFalse(r.containsValue(0.999));
- assertFalse(r.containsValue(5));
- assertFalse(r.containsValue(25));
- assertFalse(r.containsValue(20));
- assertTrue(r.containsValue(3));
- assertTrue(r.containsValue(10));
- assertTrue(r.containsValue(19));
- assertTrue(r.containsValue(19.999));
- }
- function testUnion() {
- var a = new goog.math.RangeSet();
- a.add(new goog.math.Range(1, 5));
- a.add(new goog.math.Range(10, 11));
- a.add(new goog.math.Range(15, 20));
- var b = new goog.math.RangeSet();
- b.add(new goog.math.Range(0, 5));
- b.add(new goog.math.Range(8, 18));
- var test = a.union(b);
- assertRangeListsEqual([[0, 5], [8, 20]], test.ranges_);
- var test = b.union(a);
- assertRangeListsEqual([[0, 5], [8, 20]], test.ranges_);
- var test = a.union(a);
- assertRangeListsEqual(a.ranges_, test.ranges_);
- }
- function testDifference() {
- var a = new goog.math.RangeSet();
- a.add(new goog.math.Range(1, 5));
- a.add(new goog.math.Range(10, 11));
- a.add(new goog.math.Range(15, 20));
- var b = new goog.math.RangeSet();
- b.add(new goog.math.Range(0, 5));
- b.add(new goog.math.Range(8, 18));
- var test = a.difference(b);
- assertRangeListsEqual([[18, 20]], test.ranges_);
- var test = b.difference(a);
- assertRangeListsEqual([[0, 1], [8, 10], [11, 15]], test.ranges_);
- var test = a.difference(a);
- assertRangeListsEqual([], test.ranges_);
- var test = b.difference(b);
- assertRangeListsEqual([], test.ranges_);
- }
- function testIntersection() {
- var a = new goog.math.RangeSet();
- a.add(new goog.math.Range(1, 5));
- a.add(new goog.math.Range(10, 11));
- a.add(new goog.math.Range(15, 20));
- var b = new goog.math.RangeSet();
- b.add(new goog.math.Range(0, 5));
- b.add(new goog.math.Range(8, 18));
- var test = a.intersection(b);
- assertRangeListsEqual([[1, 5], [10, 11], [15, 18]], test.ranges_);
- var test = b.intersection(a);
- assertRangeListsEqual([[1, 5], [10, 11], [15, 18]], test.ranges_);
- var test = a.intersection(a);
- assertRangeListsEqual(a.ranges_, test.ranges_);
- }
- function testSlice() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(2, 4));
- r.add(new goog.math.Range(5, 6));
- r.add(new goog.math.Range(9, 15));
- var test = r.slice(new goog.math.Range(0, 2));
- assertRangeListsEqual([], test.ranges_);
- test = r.slice(new goog.math.Range(2, 4));
- assertRangeListsEqual([[2, 4]], test.ranges_);
- test = r.slice(new goog.math.Range(7, 20));
- assertRangeListsEqual([[9, 15]], test.ranges_);
- test = r.slice(new goog.math.Range(4, 30));
- assertRangeListsEqual([[5, 6], [9, 15]], test.ranges_);
- test = r.slice(new goog.math.Range(2, 15));
- assertRangeListsEqual([[2, 4], [5, 6], [9, 15]], test.ranges_);
- test = r.slice(new goog.math.Range(10, 10));
- assertRangeListsEqual(
- 'An empty range should produce an empty set.', [], test.ranges_);
- var badRange = new goog.math.Range(10, 10);
- badRange.end = 9;
- test = r.slice(badRange);
- assertRangeListsEqual(
- 'An invalid range should produce an empty set.', [], test.ranges_);
- }
- function testInverse() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(1, 3));
- r.add(new goog.math.Range(5, 6));
- r.add(new goog.math.Range(8, 10));
- var test = r.inverse(new goog.math.Range(10, 20));
- assertRangeListsEqual([[10, 20]], test.ranges_);
- test = r.inverse(new goog.math.Range(1, 3));
- assertRangeListsEqual([], test.ranges_);
- test = r.inverse(new goog.math.Range(0, 2));
- assertRangeListsEqual([[0, 1]], test.ranges_);
- test = r.inverse(new goog.math.Range(9, 12));
- assertRangeListsEqual([[10, 12]], test.ranges_);
- test = r.inverse(new goog.math.Range(2, 9));
- assertRangeListsEqual([[3, 5], [6, 8]], test.ranges_);
- test = r.inverse(new goog.math.Range(4, 9));
- assertRangeListsEqual([[4, 5], [6, 8]], test.ranges_);
- test = r.inverse(new goog.math.Range(9, 9));
- assertRangeListsEqual(
- 'An empty range should produce an empty set.', [], test.ranges_);
- var badRange = new goog.math.Range(9, 9);
- badRange.end = 8;
- test = r.inverse(badRange);
- assertRangeListsEqual(
- 'An invalid range should produce an empty set.', [], test.ranges_);
- }
- function testCoveredLength() {
- var r = new goog.math.RangeSet();
- assertEquals(0, r.coveredLength());
- r.add(new goog.math.Range(5, 9));
- assertEquals(4, r.coveredLength());
- r.add(new goog.math.Range(0, 3));
- r.add(new goog.math.Range(12, 13));
- assertEquals(8, r.coveredLength());
- r.add(new goog.math.Range(-1, 13));
- assertEquals(14, r.coveredLength());
- r.add(new goog.math.Range(13, 13.5));
- assertEquals(14.5, r.coveredLength());
- }
- function testGetBounds() {
- var r = new goog.math.RangeSet();
- assertNull(r.getBounds());
- r.add(new goog.math.Range(12, 54));
- assertRangesEqual([12, 54], r.getBounds());
- r.add(new goog.math.Range(108, 139));
- assertRangesEqual([12, 139], r.getBounds());
- }
- function testIsEmpty() {
- var r = new goog.math.RangeSet();
- assertTrue(r.isEmpty());
- r.add(new goog.math.Range(0, 1));
- assertFalse(r.isEmpty());
- r.remove(new goog.math.Range(0, 1));
- assertTrue(r.isEmpty());
- }
- function testClear() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(1, 2));
- r.add(new goog.math.Range(3, 5));
- r.add(new goog.math.Range(8, 13));
- assertFalse(r.isEmpty());
- r.clear();
- assertTrue(r.isEmpty());
- }
- function testIter() {
- var r = new goog.math.RangeSet();
- r.add(new goog.math.Range(1, 3));
- r.add(new goog.math.Range(5, 6));
- r.add(new goog.math.Range(8, 10));
- assertRangeListsEqual([[1, 3], [5, 6], [8, 10]], goog.iter.toArray(r));
- var i = 0;
- goog.iter.forEach(r, function(testRange) {
- assertRangesEqual(
- 'Iterated set values should match the originals.', r.ranges_[i],
- testRange);
- assertNotEquals(
- 'Iterated range should not be a reference to the original.',
- r.ranges_[i], testRange);
- i++;
- });
- }
|