finitedomain
Version:
A fast feature rich finite domain solver
1,031 lines (835 loc) • 96.8 kB
JavaScript
// a domain, in this lib, is a set of numbers denoted by lo-hi range pairs (inclusive)
// for memory and performance reasons finitedomain has three different representations for a domain;
// - arrdom: an array with number pairs. mostly used by external apis because its easier to deal with. GC sensitive.
// - numdom: a 31bit field where each bit represents the inclusion of a value of its index (0 through 30). 31st bit unused
// - strdom: each value of an arrdom encoded as a double 16bit character. fixed range size (4 characters).
import expect from '../fixtures/mocha_proxy.fixt';
import {
fixt_arrdom_nums,
fixt_arrdom_range,
fixt_assertStrings,
fixt_dom_clone,
fixt_dom_empty,
fixt_dom_nums,
fixt_dom_range,
fixt_dom_solved,
fixt_domainEql,
fixt_numdom_empty,
fixt_numdom_nums,
fixt_numdom_range,
fixt_numdom_solved,
fixt_strdom_empty,
fixt_strdom_nums,
fixt_strdom_range,
fixt_strdom_ranges,
fixt_strdom_value,
} from '../fixtures/domain.fixt';
import {
NO_SUCH_VALUE,
SMALL_MAX_NUM,
SUP,
} from '../../src/helpers';
import {
EMPTY,
NOT_FOUND,
STR_RANGE_SIZE,
domain_arrToSmallest,
domain_str_closeGaps,
domain_containsValue,
domain_createRange,
domain_numnum_createRangeZeroToMax,
domain_createValue,
domain_divby,
domain_fromListToArrdom,
domain_getFirstIntersectingValue,
domain_getValue,
domain_hasNoZero,
domain_intersection,
domain_isSolved,
domain_isZero,
domain_max,
_domain_str_mergeOverlappingRanges,
//domain_middleElement,
domain_min,
domain_mul,
domain_numToStr,
domain_str_rangeIndexOf,
domain_removeGte,
domain_removeLte,
domain_removeValue,
domain_resolveAsBooly,
domain_sharesNoElements,
domain_str_simplify,
domain_size,
_domain_str_quickSortRanges,
domain_toArr,
domain_toList,
domain_toSmallest,
domain__debug,
} from '../../src/domain';
const FLOOR_FRACTIONS = true;
const CEIL_FRACTIONS = false;
describe('src/domain.spec', function() {
describe('EMPTY', function() {
it('should be empty', function() {
expect(EMPTY).to.eql(fixt_dom_empty());
});
});
describe('domain_createValue', function() {
it('should exist', function() {
expect(domain_createValue).to.be.a('function');
});
describe('numdoms', function() {
it('should convert small solved values to nums', function() {
fixt_domainEql(domain_createRange(0, 10), domain_createRange(0, 10));
fixt_domainEql(domain_createRange(20, SMALL_MAX_NUM), domain_createRange(20, SMALL_MAX_NUM));
fixt_domainEql(domain_createRange(0, SMALL_MAX_NUM), domain_createRange(0, SMALL_MAX_NUM));
});
it('should convert small solved values to nums', function() {
expect(domain_createValue(0)).to.eql(fixt_numdom_solved(0));
expect(domain_createValue(1)).to.eql(fixt_numdom_solved(1));
expect(domain_createValue(5)).to.eql(fixt_numdom_solved(5));
expect(domain_createValue(8)).to.eql(fixt_numdom_solved(8));
expect(domain_createValue(12)).to.eql(fixt_numdom_solved(12));
expect(domain_createValue(18)).to.eql(fixt_numdom_solved(18));
expect(domain_createValue(21)).to.eql(fixt_numdom_solved(21));
expect(domain_createValue(29)).to.eql(fixt_numdom_solved(29));
expect(domain_createValue(30)).to.eql(fixt_numdom_solved(30));
});
});
describe('strdoms', function() {
it('should convert small values to nums', function() {
expect(domain_createValue(31)).to.eql(fixt_numdom_solved(31));
expect(domain_createValue(32)).to.eql(fixt_numdom_solved(32));
expect(domain_createValue(100)).to.eql(fixt_numdom_solved(100));
expect(domain_createValue(56548)).to.eql(fixt_numdom_solved(56548));
expect(domain_createValue(447)).to.eql(fixt_numdom_solved(447));
expect(domain_createValue(SUP)).to.eql(fixt_numdom_solved(SUP));
expect(domain_createValue(SUP - 1)).to.eql(fixt_numdom_solved(SUP - 1));
});
});
});
describe('domain_createRange', function() {
it('should exist', function() {
expect(domain_createRange).to.be.a('function');
});
describe('numdoms', function() {
it('should convert small values to nums', function() {
expect(domain_createRange(0, 0)).to.eql(fixt_numdom_solved(0));
expect(domain_createRange(0, 1)).to.eql(fixt_numdom_range(0, 1));
expect(domain_createRange(0, 29)).to.eql(fixt_numdom_range(0, 29));
expect(domain_createRange(0, 30)).to.eql(fixt_numdom_range(0, 30));
expect(domain_createRange(29, 30)).to.eql(fixt_numdom_range(29, 30));
expect(domain_createRange(30, 30)).to.eql(fixt_numdom_solved(30));
expect(domain_createRange(8, 14)).to.eql(fixt_numdom_range(8, 14));
expect(domain_createRange(5, 21)).to.eql(fixt_numdom_range(5, 21));
expect(domain_createRange(24, 28)).to.eql(fixt_numdom_range(24, 28));
});
});
describe('strdoms', function() {
it('should convert small values to nums', function() {
fixt_assertStrings(domain_createRange(0, SUP), fixt_strdom_range(0, SUP));
expect(domain_createRange(SUP, SUP)).to.eql(fixt_numdom_solved(SUP));
fixt_assertStrings(domain_createRange(SUP - 1, SUP), fixt_strdom_range(SUP - 1, SUP));
fixt_assertStrings(domain_createRange(200, 2000), fixt_strdom_range(200, 2000));
expect(domain_createRange(SUP - 1, SUP - 1)).to.eql(fixt_numdom_solved(SUP - 1));
fixt_assertStrings(domain_createRange(0, SUP - 1), fixt_strdom_range(0, SUP - 1));
fixt_assertStrings(domain_createRange(5, 53243), fixt_strdom_range(5, 53243));
expect(domain_createRange(85755487, 85755487)).to.eql(fixt_numdom_solved(85755487));
});
});
});
describe('domain_createRangeZeroToMax', function() {
const ZERO = 1 << 0;
const ONE = 1 << 1;
const TWO = 1 << 2;
const THREE = 1 << 3;
const FOUR = 1 << 4;
const FIVE = 1 << 5;
const SIX = 1 << 6;
const SEVEN = 1 << 7;
const EIGHT = 1 << 8;
const NINE = 1 << 9;
const TEN = 1 << 10;
const ELEVEN = 1 << 11;
const TWELVE = 1 << 12;
const THIRTEEN = 1 << 13;
const FOURTEEN = 1 << 14;
const FIFTEEN = 1 << 15;
const SIXTEEN = 1 << 16;
const SEVENTEEN = 1 << 17;
const EIGHTEEN = 1 << 18;
const NINETEEN = 1 << 19;
const TWENTY = 1 << 20;
const TWENTYONE = 1 << 21;
const TWENTYTWO = 1 << 22;
const TWENTYTHREE = 1 << 23;
const TWENTYFOUR = 1 << 24;
const TWENTYFIVE = 1 << 25;
const TWENTYSIX = 1 << 26;
const TWENTYSEVEN = 1 << 27;
const TWENTYEIGHT = 1 << 28;
const TWENTYNINE = 1 << 29;
const THIRTY = 1 << 30;
it('should work', function() {
expect(_ => domain_numnum_createRangeZeroToMax(ZERO)).to.throw('INVALID INPUT');
expect(domain_numnum_createRangeZeroToMax(ONE)).to.eql(ZERO | ONE);
expect(domain_numnum_createRangeZeroToMax(TWO)).to.eql(ZERO | ONE | TWO);
expect(domain_numnum_createRangeZeroToMax(THREE)).to.eql(ZERO | ONE | TWO | THREE);
expect(domain_numnum_createRangeZeroToMax(FOUR)).to.eql(ZERO | ONE | TWO | THREE | FOUR);
expect(domain_numnum_createRangeZeroToMax(SIX)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX);
expect(domain_numnum_createRangeZeroToMax(SEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN);
expect(domain_numnum_createRangeZeroToMax(EIGHT)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT);
expect(domain_numnum_createRangeZeroToMax(NINE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE);
expect(domain_numnum_createRangeZeroToMax(TEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN);
expect(domain_numnum_createRangeZeroToMax(ELEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN);
expect(domain_numnum_createRangeZeroToMax(TWELVE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE);
expect(domain_numnum_createRangeZeroToMax(THIRTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN);
expect(domain_numnum_createRangeZeroToMax(FOURTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN);
expect(domain_numnum_createRangeZeroToMax(FIFTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN);
expect(domain_numnum_createRangeZeroToMax(SIXTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN);
expect(domain_numnum_createRangeZeroToMax(SEVENTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN);
expect(domain_numnum_createRangeZeroToMax(EIGHTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN);
expect(domain_numnum_createRangeZeroToMax(NINETEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN);
expect(domain_numnum_createRangeZeroToMax(TWENTY)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY);
expect(domain_numnum_createRangeZeroToMax(TWENTYONE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE);
expect(domain_numnum_createRangeZeroToMax(TWENTYTWO)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO);
expect(domain_numnum_createRangeZeroToMax(TWENTYTHREE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE);
expect(domain_numnum_createRangeZeroToMax(TWENTYFOUR)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR);
expect(domain_numnum_createRangeZeroToMax(TWENTYFIVE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE);
expect(domain_numnum_createRangeZeroToMax(TWENTYSIX)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX);
expect(domain_numnum_createRangeZeroToMax(TWENTYSEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN);
expect(domain_numnum_createRangeZeroToMax(TWENTYEIGHT)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT);
expect(domain_numnum_createRangeZeroToMax(TWENTYNINE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT | TWENTYNINE);
expect(domain_numnum_createRangeZeroToMax(THIRTY)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT | TWENTYNINE | THIRTY);
});
});
describe('fromListToArrdom', function() {
it('should exist', function() {
expect(domain_fromListToArrdom).to.be.a('function');
});
it('should return empty array for empty lists', function() {
expect(domain_fromListToArrdom([])).to.eql([]);
});
describe('numdoms', function() {
it('should work with [0,0]', function() {
expect(domain_fromListToArrdom([0])).to.eql(fixt_arrdom_nums(0));
expect(domain_fromListToArrdom([0, 0])).to.eql(fixt_arrdom_nums(0));
});
it('should work with [0,1]', function() {
expect(domain_fromListToArrdom([0, 1])).to.eql(fixt_arrdom_nums(0, 1));
expect(domain_fromListToArrdom([1, 0])).to.eql(fixt_arrdom_nums(0, 1));
expect(domain_fromListToArrdom([0, 0, 1, 1])).to.eql(fixt_arrdom_nums(0, 1));
expect(domain_fromListToArrdom([1, 1, 0, 0])).to.eql(fixt_arrdom_nums(0, 1));
});
it('should throw with negative elements', function() {
expect(() => domain_fromListToArrdom([10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG');
expect(() => domain_fromListToArrdom([10, 1, -1, 0, 10, 1, -1, 0, 10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG');
});
it('should not sort input array', function() {
let list = [4, 3, 8, 2];
domain_fromListToArrdom(list, true, true);
expect(list).to.eql([4, 3, 8, 2]);
});
});
describe('strdoms', function() {
it('should work with [SUP,SUP]', function() {
expect(domain_fromListToArrdom([SUP])).to.eql(fixt_arrdom_nums(SUP));
expect(domain_fromListToArrdom([SUP, SUP])).to.eql(fixt_arrdom_nums(SUP));
});
it('should work with [SUP-1,SUP]', function() {
expect(domain_fromListToArrdom([SUP - 1, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP));
expect(domain_fromListToArrdom([SUP, SUP - 1])).to.eql(fixt_arrdom_nums(SUP, SUP - 1));
expect(domain_fromListToArrdom([SUP - 1, SUP - 1, SUP, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP));
expect(domain_fromListToArrdom([SUP - 1, SUP - 1, SUP, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP));
});
it('should throw with negative elements', function() {
expect(() => domain_fromListToArrdom([SUP, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG');
expect(() => domain_fromListToArrdom([SUP, 1, -1, 0, 10, 1, -1, 0, 10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG');
});
it('should not sort input array', function() {
let list = [4, SUP, 3, 8, 2];
let domain = domain_fromListToArrdom(list);
expect(list).to.eql([4, SUP, 3, 8, 2]); // not changed
expect(domain).to.eql(fixt_arrdom_nums(2, SUP, 3, 4, 8));
});
});
});
describe('getValue', function() {
it('should exist', function() {
expect(domain_getValue).to.be.a('function');
});
describe('strdom', function() {
it('should return NOT_FOUND if the domain has more than two values', function() {
expect(domain_getValue(fixt_strdom_ranges([10, 20], [30, 40]))).to.equal(NOT_FOUND);
});
it('should return NOT_FOUND if the domain is empty', function() {
expect(domain_getValue(fixt_numdom_empty())).to.eql(NO_SUCH_VALUE);
});
it('should return NO_SUCH_VALUE if the two elements are not equal', function() {
expect(domain_getValue(fixt_strdom_nums(321, 1))).to.equal(NO_SUCH_VALUE);
});
it('should return value if both elements are same', function() {
expect(domain_getValue(fixt_strdom_nums(1700))).to.equal(1700);
expect(domain_getValue(fixt_strdom_nums(SUP))).to.equal(SUP);
expect(domain_getValue(fixt_strdom_nums(SUP - 1))).to.equal(SUP - 1);
expect(domain_getValue(fixt_strdom_nums(32))).to.equal(32);
expect(domain_getValue(fixt_strdom_nums(0))).to.equal(0);
});
});
describe('numdom', function() {
it('should return NOT_FOUND if the domain has more than two values', function() {
expect(domain_getValue(fixt_numdom_nums(10, 12))).to.equal(NOT_FOUND);
});
it('should return NOT_FOUND if the domain is empty', function() {
let A = fixt_numdom_empty();
expect(domain_getValue(A)).to.equal(NOT_FOUND);
});
it('should return 12 if it only contains 12', function() {
expect(domain_getValue(fixt_numdom_nums(12))).to.equal(12);
});
it('should return 0 if it only contains 0', function() {
expect(domain_getValue(fixt_numdom_nums(0))).to.equal(0);
});
});
describe('solved numdom', function() {
it('should work with solved numdoms', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
expect(domain_getValue(fixt_numdom_solved(i)), 'i=' + i).to.equal(i);
}
});
});
});
describe('toList', function() {
it('should exist', function() {
expect(domain_toList).to.be.a('function');
});
it('should require a domain', function() {
expect(() => domain_toList()).to.throw('ONLY_NORDOM');
});
describe('strdom', function() {
it('should work', function() {
expect(domain_toList(fixt_strdom_nums(SUP))).to.eql([SUP]);
expect(domain_toList(fixt_strdom_nums(SUP - 1, SUP))).to.eql([SUP - 1, SUP]);
expect(domain_toList(fixt_strdom_nums(32))).to.eql([32]);
expect(domain_toList(fixt_strdom_nums(0))).to.eql([0]);
});
});
describe('numdom', function() {
it('should accept empty domain', function() {
expect(domain_toList(fixt_numdom_empty())).to.eql([]);
});
it('[0,0]', function() {
expect(domain_toList(fixt_numdom_nums(0))).to.eql([0]);
});
it('[0,1]', function() {
expect(domain_toList(fixt_numdom_nums(0, 1))).to.eql([0, 1]);
});
it('[1,1]', function() {
expect(domain_toList(fixt_numdom_nums(1))).to.eql([1]);
});
});
describe('solved numdom', function() {
it('should work with solved numdoms', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
expect(domain_toList(fixt_numdom_solved(i)), 'i=' + i).to.eql([i]);
}
});
});
});
describe('getFirstIntersectingValue ', function() {
describe('strdom', function() {
it('should work with SUP range', function() {
let A = fixt_strdom_range(SUP - 3, SUP);
expect(domain_getFirstIntersectingValue(A, [SUP])).to.eql(SUP);
expect(domain_getFirstIntersectingValue(A, [SUP, 10, 9, 7]), '[0,10,9,7]').to.eql(SUP);
expect(domain_getFirstIntersectingValue(A, [10, 9, 7, SUP]), '[10,9,7,0]').to.eql(SUP);
expect(domain_getFirstIntersectingValue(A, [SUP - 1])).to.eql(SUP - 1);
expect(domain_getFirstIntersectingValue(A, [SUP - 2])).to.eql(SUP - 2);
expect(domain_getFirstIntersectingValue(A, [SUP - 3])).to.eql(SUP - 3);
expect(domain_getFirstIntersectingValue(A, [99, 100])).to.eql(NO_SUCH_VALUE);
});
it('should work with multiple ranges', function() {
let A = fixt_strdom_ranges([SUP - 14, SUP - 10], [SUP - 4, SUP]);
expect(domain_getFirstIntersectingValue(A, [SUP])).to.eql(SUP);
expect(domain_getFirstIntersectingValue(A, [SUP, SUP - 10, SUP - 11])).to.eql(SUP);
expect(domain_getFirstIntersectingValue(A, [SUP - 10, SUP - 11, SUP, SUP - 12])).to.eql(SUP - 10);
expect(domain_getFirstIntersectingValue(A, [SUP - 1])).to.eql(SUP - 1);
expect(domain_getFirstIntersectingValue(A, [SUP - 100, SUP - 12])).to.eql(SUP - 12);
expect(domain_getFirstIntersectingValue(A, [SUP - 12, SUP - 100])).to.eql(SUP - 12);
});
it('should return NO_SUCH_VALUE if the list not intersect with domain', function() {
let A = fixt_strdom_ranges([SUP - 24, SUP - 20], [SUP - 14, SUP - 10], [SUP - 4, SUP]);
expect(domain_getFirstIntersectingValue(A, [99, 5, SUP - 12, 11])).to.eql(SUP - 12);
expect(domain_getFirstIntersectingValue(A, [99, 5])).to.eql(NO_SUCH_VALUE);
});
it('should throw for negative values', function() {
let A = fixt_strdom_ranges([SUP - 24, SUP - 20], [SUP - 14, SUP - 10], [SUP - 4, SUP]);
expect(() => domain_getFirstIntersectingValue(A, [99, -1, SUP - 12, 11])).to.throw('A_OOB_INDICATES_BUG');
expect(() => domain_getFirstIntersectingValue(A, [99, -1])).to.throw('A_OOB_INDICATES_BUG');
});
});
describe('numdom', function() {
it('should work with single range', function() {
let A = fixt_numdom_range(0, 3);
expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [0, 10, 9, 7]), '[0,10,9,7]').to.eql(0);
expect(domain_getFirstIntersectingValue(A, [10, 9, 7, 0]), '[10,9,7,0]').to.eql(0);
expect(domain_getFirstIntersectingValue(A, [1])).to.eql(1);
expect(domain_getFirstIntersectingValue(A, [2])).to.eql(2);
expect(domain_getFirstIntersectingValue(A, [3])).to.eql(3);
expect(domain_getFirstIntersectingValue(A, [99, 100])).to.eql(NO_SUCH_VALUE);
});
it('should work with zero domain', function() {
let A = fixt_numdom_nums(0);
expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [0, 10, 11])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [10, 11, 0, 12])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [1])).to.eql(NO_SUCH_VALUE);
expect(domain_getFirstIntersectingValue(A, [1, 2, 3, 4, 5])).to.eql(NO_SUCH_VALUE);
});
it('should work with multiple ranges', function() {
let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14);
expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [0, 10, 11])).to.eql(0);
expect(domain_getFirstIntersectingValue(A, [10, 11, 0, 12])).to.eql(10);
expect(domain_getFirstIntersectingValue(A, [1])).to.eql(1);
expect(domain_getFirstIntersectingValue(A, [100, 12])).to.eql(12);
expect(domain_getFirstIntersectingValue(A, [12, 100])).to.eql(12);
});
it('should return NO_SUCH_VALUE if the list not intersect with domain', function() {
let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14);
expect(domain_getFirstIntersectingValue(A, [99, 5, 12, 11])).to.eql(12);
expect(domain_getFirstIntersectingValue(A, [99, 5])).to.eql(NO_SUCH_VALUE);
});
it('should throw for negative values', function() {
let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14);
expect(() => domain_getFirstIntersectingValue(A, [99, -1, 12, 11])).to.throw('A_OOB_INDICATES_BUG');
expect(() => domain_getFirstIntersectingValue(A, [99, -1])).to.throw('A_OOB_INDICATES_BUG');
});
});
describe('solved numdom', function() {
it('should work with solved numdoms', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
// test for list with target (i) as first, middle, last, and
// not-existing element. also empty list and only i.
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [i]), 'i=' + i).to.equal(i);
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [i, 500, SUP]), 'i=' + i).to.equal(i);
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, i, SUP]), 'i=' + i).to.equal(i);
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, SUP, i]), 'i=' + i).to.equal(i);
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, SUP]), 'i=' + i).to.equal(NO_SUCH_VALUE);
expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), []), 'i=' + i).to.equal(NO_SUCH_VALUE);
}
});
});
});
describe('containsValue', function() {
it('should exist', function() {
expect(domain_containsValue).to.be.a('function');
});
describe('arrdom', function() {
describe('should return true if domain contains given value', function() {
it('one range in domain', function() {
expect(domain_containsValue(fixt_strdom_range(SUP - 10, SUP), SUP - 5)).to.equal(true);
});
it('multiple ranges in domain', function() {
expect(domain_containsValue(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 25)).to.equal(true);
});
});
describe('should return false if domain does not contain value', function() {
it('empty array', function() {
expect(domain_containsValue(fixt_numdom_empty(), 0)).to.equal(false);
});
it('one range in domain', function() {
expect(domain_containsValue(fixt_strdom_range(SUP - 10, SUP), 25)).to.equal(false);
});
it('multiple ranges in domain', function() {
expect(domain_containsValue(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 15)).to.equal(false);
});
});
});
describe('numdom', function() {
describe('should return true if domain contains given value', function() {
it('one range in domain', function() {
expect(domain_containsValue(fixt_numdom_range(0, 10), 5)).to.equal(true);
});
it('multiple ranges in domain', function() {
expect(domain_containsValue(fixt_numdom_nums(0, 1, 2, 4, 5, 8, 9, 10, 11), 9)).to.equal(true);
});
});
describe('should return false if domain does not contain value', function() {
it('empty array', function() {
expect(domain_containsValue(fixt_numdom_empty(), 0)).to.equal(false);
});
it('one range in domain', function() {
expect(domain_containsValue(fixt_numdom_range(0, 10), 25)).to.equal(false);
});
it('multiple ranges in domain', function() {
expect(domain_containsValue(fixt_numdom_nums(0, 1, 2, 4, 5, 8, 9, 10, 11), 6)).to.equal(false);
});
});
});
describe('solved numdom', function() {
it('should work with solved numdoms', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
// do a search that passes, fails, and is oob
expect(domain_containsValue(fixt_numdom_solved(i), 0), 'i=' + i + ',q=0').to.equal(i === 0);
expect(domain_containsValue(fixt_numdom_solved(i), 1), 'i=' + i + ',q=1').to.equal(i === 1);
expect(domain_containsValue(fixt_numdom_solved(i), SUP), 'i=' + i + ',q=SUP').to.equal(false);
}
});
});
describe('large value in numdom range', function() {
it('should return false when numbers are oob for bitdom ranges', function() {
expect(domain_containsValue(fixt_numdom_range(0, 10), 10000)).to.equal(false);
expect(domain_containsValue(fixt_numdom_range(0, 10), 1760)).to.equal(false); // this value is a regression that uncovered a bug
expect(_ => domain_containsValue(fixt_numdom_range(0, 10), -1)).to.throw('OOB');
expect(_ => domain_containsValue(fixt_numdom_range(0, 10), -10000)).to.throw('OOB');
});
});
});
describe('domain_rangeIndexOf', function() {
it('should exist', function() {
expect(domain_str_rangeIndexOf).to.be.a('function');
});
describe('should return index of range offset that encloses value', function() {
// note: not range index, but index on the set of numbers which represents range pairs
it('one range in domain', function() {
expect(domain_str_rangeIndexOf(fixt_strdom_range(SUP - 10, SUP), SUP - 5)).to.eql(0);
});
it('multiple ranges in domain', function() {
expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 50)).to.eql(0);
expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 25)).to.eql(1 * STR_RANGE_SIZE);
expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 5)).to.eql(2 * STR_RANGE_SIZE);
});
});
describe('should return NOT_FOUND if domain does not contain value', function() {
it('empty array', function() {
expect(_ => domain_str_rangeIndexOf(fixt_strdom_empty(), 0)).to.throw('NOT_EMPTY_STR');
});
it('one range in domain', function() {
expect(domain_str_rangeIndexOf(fixt_strdom_range(SUP - 10, SUP), SUP - 25)).to.eql(NOT_FOUND);
});
it('multiple ranges in domain', function() {
expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 15)).to.eql(NOT_FOUND);
});
});
});
describe('domain_removeValue', function() {
it('should exist', function() {
expect(domain_removeValue).to.be.a('function');
});
it('should reject an invalid value', function() { // (only numbers are valid values)
expect(() => domain_removeValue(fixt_dom_nums(1, 2, 3), '15')).to.throw('VALUE_SHOULD_BE_VALID_DOMAIN_ELEMENT');
expect(() => domain_removeValue(fixt_dom_nums(1, 2, 3), ['15'])).to.throw('VALUE_SHOULD_BE_VALID_DOMAIN_ELEMENT');
});
describe('strdom', function() {
it('should require a domain', function() {
expect(() => domain_removeValue(null, 15)).to.throw('ONLY_NORDOM');
});
// target: 5
// 012 456 89 -> 012 4 6 89
// 012 567 -> 012 67
// 01 345 -> 01 34
// 01 345 89 -> 01 34 89
// 012 5 789 -> 012 789
// 5 789 -> 789
// 012 5 -> 012
// 789 -> 789
// 012 -> 012
// 5 -> empty
// empty -> empty
function test(domain, value, expectation) {
it(`should remove [${value}] from [${domain__debug(domain)}] resulting in [${domain__debug(expectation)}]`, function() {
let clone = fixt_dom_clone(domain);
let result = domain_removeValue(fixt_dom_clone(domain), value);
expect(domain, 'should not change').to.eql(clone);
if (typeof expectation === 'string') fixt_assertStrings(result, expectation);
else expect(result).to.equal(expectation); // output is a numdom
expect(result).to.eql(expectation);
});
}
test(fixt_strdom_ranges([100, 102], [104, 106], [108, 109]), 105, fixt_strdom_ranges([100, 102], [104, 104], [106, 106], [108, 109]));
test(fixt_strdom_ranges([100, 102], [104, 106]), 105, fixt_strdom_ranges([100, 102], [104, 104], [106, 106]));
test(fixt_strdom_ranges([100, 101], [103, 105]), 105, fixt_strdom_ranges([100, 101], [103, 104]));
test(fixt_strdom_ranges([100, 101], [103, 105], [108, 109]), 105, fixt_strdom_ranges([100, 101], [103, 104], [108, 109]));
test(fixt_strdom_ranges([100, 102], [105, 105], [107, 109]), 105, fixt_strdom_ranges([100, 102], [107, 109]));
test(fixt_strdom_ranges([105, 105], [107, 109]), 105, fixt_strdom_ranges([107, 109]));
test(fixt_strdom_ranges([100, 102], [105, 105]), 105, fixt_strdom_ranges([100, 102]));
test(fixt_strdom_ranges([107, 109]), 105, fixt_strdom_ranges([107, 109]));
test(fixt_strdom_ranges([100, 102]), 105, fixt_strdom_ranges([100, 102]));
test(fixt_strdom_ranges([105, 105]), 105, fixt_numdom_empty());
test(fixt_strdom_ranges([32, 32]), 32, fixt_numdom_empty());
test(fixt_strdom_ranges([SUP, SUP]), SUP, fixt_numdom_empty());
test(fixt_strdom_ranges([SUP - 1, SUP - 1]), SUP - 1, fixt_numdom_empty());
test(fixt_strdom_ranges([SUP - 1, SUP]), SUP, fixt_numdom_solved(SUP - 1));
});
describe('numdom', function() {
// target: 5
// 012 456 89 -> 012 4 6 89
// 012 567 -> 012 67
// 01 345 -> 01 34
// 01 345 89 -> 01 34 89
// 012 5 789 -> 012 789
// 5 789 -> 789
// 012 5 -> 012
// 789 -> 789
// 012 -> 012
// 5 -> empty
// empty -> empty
function test(domain, value, output) {
it(`should remove [${value}] from [${domain}] resulting in [${output}]`, function() {
expect(domain_removeValue(domain, value)).to.eql(output);
});
}
test(fixt_numdom_nums(0, 1, 2, 4, 5, 6, 8, 9), 5, fixt_numdom_nums(0, 1, 2, 4, 6, 8, 9));
test(fixt_numdom_nums(0, 1, 2, 4, 5, 6), 5, fixt_numdom_nums(0, 1, 2, 4, 6));
test(fixt_numdom_nums(0, 1, 3, 4, 5), 5, fixt_numdom_nums(0, 1, 3, 4));
test(fixt_numdom_nums(0, 1, 3, 4, 5, 8, 9), 5, fixt_numdom_nums(0, 1, 3, 4, 8, 9));
test(fixt_numdom_nums(0, 1, 2, 5, 7, 8, 9), 5, fixt_numdom_nums(0, 1, 2, 7, 8, 9));
test(fixt_numdom_nums(5, 7, 8, 9), 5, fixt_numdom_nums(7, 8, 9));
test(fixt_numdom_nums(0, 1, 2, 5), 5, fixt_numdom_nums(0, 1, 2));
test(fixt_numdom_nums(7, 8, 9), 5, fixt_numdom_nums(7, 8, 9));
test(fixt_numdom_nums(0, 1, 2), 5, fixt_numdom_nums(0, 1, 2));
test(fixt_numdom_nums(5), 5, fixt_numdom_nums());
});
describe('solved numdom', function() {
it('should work with solved numdoms', function() {
let nums = [0, 1, 10, 100, 1000, SUP - 1, SUP];
for (let i = 0; i < nums.length; ++i) {
let n = nums[i];
// do a search that passes and one that fails
expect(domain_removeValue(fixt_numdom_solved(n), n), 'n=' + n + ',q=' + n).to.equal(fixt_dom_empty());
expect(domain_removeValue(fixt_numdom_solved(n), 5), 'n=' + n + ',q=5').to.equal(fixt_numdom_solved(n));
}
});
});
});
describe('domain_sharesNoElements', function() {
it('should exist', function() {
expect(domain_sharesNoElements).to.be.a('function');
});
describe('strdom', function() {
it('unit tests', function() {
expect(domain_sharesNoElements(fixt_strdom_range(1, SUP), fixt_strdom_range(500, 600))).to.eql(false);
expect(domain_sharesNoElements(fixt_strdom_range(1, SUP - 10), fixt_strdom_range(SUP - 5, SUP))).to.eql(true);
expect(domain_sharesNoElements(fixt_strdom_range(500, 600), fixt_strdom_range(1, SUP))).to.eql(false);
expect(domain_sharesNoElements(fixt_strdom_range(SUP - 5, SUP), fixt_strdom_range(1, SUP - 10))).to.eql(true);
});
});
describe('numdom', function() {
it('unit tests', function() {
expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_range(15, 25))).to.eql(false);
expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_range(25, 27))).to.eql(true);
expect(domain_sharesNoElements(fixt_numdom_range(15, 25), fixt_numdom_range(1, 20))).to.eql(false);
expect(domain_sharesNoElements(fixt_numdom_range(25, 27), fixt_numdom_range(1, 20))).to.eql(true);
});
});
describe('soldom', function() {
it('unit tests', function() {
//expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_solved(15))).to.eql(false);
//expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_solved(25))).to.eql(true);
//expect(domain_sharesNoElements(fixt_numdom_solved(15), fixt_numdom_range(1, 20))).to.eql(false);
//expect(domain_sharesNoElements(fixt_numdom_solved(25), fixt_numdom_range(1, 20))).to.eql(true);
expect(domain_sharesNoElements(fixt_numdom_solved(500), fixt_strdom_range(1, SUP))).to.eql(false);
expect(domain_sharesNoElements(fixt_numdom_solved(SUP), fixt_strdom_range(1, SUP - 10))).to.eql(true);
expect(domain_sharesNoElements(fixt_numdom_solved(20), fixt_numdom_solved(20))).to.eql(false);
expect(domain_sharesNoElements(fixt_numdom_solved(20), fixt_numdom_solved(0))).to.eql(true);
expect(domain_sharesNoElements(fixt_numdom_solved(0), fixt_numdom_solved(20))).to.eql(true);
});
});
});
describe('domain_min', function() {
it('should exist', function() {
expect(domain_min).to.be.a('function');
});
it('arrdom', function() {
expect(domain_min(fixt_strdom_ranges([0, 10], [100, 300]))).to.eql(0);
expect(domain_min(fixt_strdom_ranges([0, 10], [100, SUP]))).to.eql(0);
expect(domain_min(fixt_strdom_ranges([1, 1], [100, SUP]))).to.eql(1);
expect(domain_min(fixt_strdom_ranges([100, 100]))).to.eql(100);
expect(domain_min(fixt_strdom_ranges([SUP, SUP]))).to.eql(SUP);
expect(domain_min(fixt_strdom_ranges([SUP - 1, SUP]))).to.eql(SUP - 1);
});
it('numdom', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
// basically trying each small domain range from [0,30] to [30,30]
expect(domain_min(fixt_numdom_nums(i)), i + ' | i').to.eql(i);
expect(domain_min(fixt_numdom_nums(i, 30)), i + ' | 30').to.eql(i);
}
});
});
describe('domain_max', function() {
it('should exist', function() {
expect(domain_max).to.be.a('function');
});
it('arrdom', function() {
expect(domain_max(fixt_strdom_ranges([0, 10], [100, 300]))).to.eql(300);
expect(domain_max(fixt_strdom_ranges([0, 10], [100, SUP]))).to.eql(SUP);
expect(domain_max(fixt_strdom_ranges([1, 1], [100, SUP]))).to.eql(SUP);
expect(domain_max(fixt_strdom_ranges([100, 100]))).to.eql(100);
expect(domain_max(fixt_strdom_ranges([SUP, SUP]))).to.eql(SUP);
expect(domain_max(fixt_strdom_ranges([SUP - 1, SUP]))).to.eql(SUP);
});
it('numdom', function() {
for (let i = 0; i <= SMALL_MAX_NUM; ++i) {
// basically trying each small domain range from [0,30] to [30,30]
expect(domain_max(fixt_numdom_nums(0, i)), '0 | ' + i).to.eql(i);
}
});
});
describe('domain_mergeOverlappingInline', function() {
it('should exist', function() {
expect(_domain_str_mergeOverlappingRanges).to.be.a('function');
});
it('should throw for domains as numbers', function() {
expect(_ => _domain_str_mergeOverlappingRanges(fixt_numdom_nums(1))).to.throw('ONLY_STRDOM');
});
it('should return empty domain for empty domain', function() {
expect(_domain_str_mergeOverlappingRanges(fixt_strdom_empty()), fixt_strdom_empty());
});
it('should return same range for single range domain', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(910, 9100)), fixt_strdom_range(910, 9100));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(930, 9213)), fixt_strdom_range(930, 9213));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(90, 91)), fixt_strdom_range(90, 91));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(SUP, SUP)), fixt_strdom_range(SUP, SUP));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(SUP - 1, SUP)), fixt_strdom_range(SUP - 1, SUP));
});
it('should return same if not overlapping', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([910, 9100], [9200, 9300])), fixt_strdom_ranges([910, 9100], [9200, 9300]));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [92, 92])), fixt_strdom_ranges([90, 90], [92, 92]));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [SUP, SUP])), fixt_strdom_ranges([90, 90], [SUP, SUP]));
});
it('should merge if two domains overlap', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [91, 92])), fixt_strdom_range(90, 92));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 950], [925, 975])), fixt_strdom_range(90, 975));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([9213, 9278], [9244, 9364])), fixt_strdom_range(9213, 9364));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([910, 920], [930, 940], [935, 945], [950, 960])), fixt_strdom_ranges([910, 920], [930, 945], [950, 960]));
});
it('should merge if two domains touch', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 91])), fixt_strdom_range(90, 91));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [92, 93])), fixt_strdom_range(90, 93));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 910], [910, 920])), fixt_strdom_range(90, 920));
});
it('should chain merges', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 91], [92, 92])), fixt_strdom_range(90, 92));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [91, 92], [92, 93])), fixt_strdom_range(90, 93));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 92], [92, 93])), fixt_strdom_range(90, 93));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([91, 92], [92, 93])), fixt_strdom_range(91, 93));
});
it('should make sure resulting range wraps both ranges', function() {
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [90, 91])), fixt_strdom_range(90, 91));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [90, 90])), fixt_strdom_range(90, 91));
fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 910], [914, 916], [915, 920], [916, 919], [917, 918])), fixt_strdom_ranges([90, 910], [914, 920]));
});
});
describe('domain_simplifyInline', function() {
it('should exist', function() {
expect(domain_str_simplify).to.be.a('function');
});
it('should throw for domains as numbers', function() {
expect(_ => domain_str_simplify(fixt_numdom_empty())).to.throw('ONLY_STRDOM');
expect(_ => domain_str_simplify(fixt_numdom_nums(1, 3, 9))).to.throw('ONLY_STRDOM');
expect(_ => domain_str_simplify()).to.throw('ONLY_STRDOM');
});
it('should work with empty domain', function() {
let arr = fixt_strdom_empty();
expect(domain_str_simplify(arr)).to.eql(fixt_dom_empty());
});
it('should return a solved domain if it has one range', function() {
fixt_assertStrings(domain_str_simplify(fixt_strdom_range(90, 91)), fixt_strdom_range(90, 91));
expect(domain_str_simplify(fixt_strdom_range(SUP, SUP))).to.eql(fixt_numdom_solved(SUP));
});
it('should work if domain is not changed', function() {
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [920, 930])), fixt_strdom_ranges([91, 92], [920, 930]));
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [920, SUP])), fixt_strdom_ranges([91, 92], [920, SUP]));
});
it('should simplify back-to-back domains', function() {
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [92, 93])), fixt_strdom_range(91, 93));
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [92, SUP])), fixt_strdom_range(91, SUP));
});
it('should simplify swapped back-to-back domains', function() {
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([92, 93], [91, 92])), fixt_strdom_range(91, 93));
fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([92, SUP], [91, 92])), fixt_strdom_range(91, SUP));
});
});
describe('intersection', function() {
it('should exist', function() {
expect(domain_intersection).to.be.a('function');
});
it('should require two domains', function() {
expect(() => domain_intersection()).to.throw('ONLY_NORDOM');
expect(() => domain_intersection(fixt_numdom_empty())).to.throw('ONLY_NORDOM');
expect(() => domain_intersection(null, fixt_numdom_empty())).to.throw('ONLY_NORDOM');
});
it('should return empty numdom', function() {
expect(domain_intersection(fixt_numdom_empty(), fixt_numdom_empty())).to.eql(fixt_dom_empty());
});
it('should throw for EMPTY_STR', function() {
expect(_ => domain_intersection(fixt_strdom_empty(), fixt_strdom_empty())).to.throw('empty domains are always numdoms');
expect(_ => domain_intersection(fixt_strdom_empty(), fixt_numdom_empty())).to.throw('empty domains are always numdoms');
expect(_ => domain_intersection(fixt_numdom_empty(), fixt_strdom_empty())).to.throw('empty domains are always numdoms');
});
describe('strdom', function() {
it('should handle empty domain with single element domain', function() {
expect(domain_intersection(fixt_numdom_empty(), fixt_strdom_range(90, 91))).to.eql(fixt_dom_empty());
});
it('should handle empty domain with multi element domain', function() {
expect(domain_intersection(fixt_numdom_empty(), fixt_strdom_ranges([90, 91], [93, 95]))).to.eql(fixt_dom_empty());
});
it('should handle single element domain with empty domain', function() {
expect(domain_intersection(fixt_strdom_range(90, 91), fixt_numdom_empty())).to.eql(fixt_dom_empty());
});
it('should handle single element domain with empty domain', function() {
expect(domain_intersection(fixt_strdom_ranges([90, 91], [93, 95]), fixt_numdom_empty())).to.eql(fixt_dom_empty());
});
it('should handle single element domains', function() {
expect(domain_intersection(fixt_strdom_range(90, 91), fixt_strdom_range(93, 95))).to.eql(fixt_dom_empty());
});
it('should intersect single element domains', function() {
fixt_assertStrings(domain_intersection(fixt_strdom_range(90, 95), fixt_strdom_range(93, 100)), fixt_strdom_range(93, 95));
});
it('should intersect single element domains reversed', function() {
fixt_assertStrings(domain_intersection(fixt_strdom_range(93, 100), fixt_strdom_range(90, 95)), fixt_strdom_range(93, 95));
});
it('should handle single element domain with multi element domain', function() {
expect(domain_intersection(fixt_strdom_range(90, 91), fixt_strdom_ranges([10, 20], [30, 40]))).to.eql(fixt_dom_empty());
});
it('should handle multi element domain with single element domain', function() {
expect(domain_intersection(fixt_strdom_ranges([0, 1], [10, 120]), fixt_strdom_range(130, 140))).to.eql(fixt_dom_empty());
});
it('should intersect single element domain with multi element domain', function() {
expect(domain_intersection(fixt_strdom_range(5, 16), fixt_strdom_ranges([10, 20], [30, 40]))).to.eql(fixt_numdom_range(10, 16));
});
it('should intersect multi element domain with single element domain', function() {
fixt_assertStrings(domain_intersection(fixt_strdom_ranges([0, 1], [25, 35]), fixt_strdom_range(30, 40)), fixt_strdom_range(30, 35));
});
it('should handle multi element domains', function() {
expect(domain_intersection(fixt_strdom_ranges([0, 1], [10, 120]), fixt_strdom_ranges([130, 140], [150, 160]))).to.eql(fixt_dom_empty());
});
it('should intersect multi element domains', function() {
fixt_assertStrings(domain_intersection(fixt_strdom_ranges([0, 1], [10, 35]), fixt_strdom_ranges([30, 40], [50, 60])), fixt_strdom_range(30, 35));
});
it('should return two ranges if a range in one domain intersects with two ranges of the other domain', function() {
fixt_assertStrings(domain_intersection(fixt_strdom_range(15, 35), fixt_strdom_ranges([10, 20], [30, 40])), fixt_strdom_ranges([15, 20], [30, 35]));
});
it('should divide and conquer some random tests 1', function() {
// copy(JSON.stringify(function f(n) {
// var arr = [];
// while (--n > 0) {
// var t = Math.floor(Math.random() * 100);
// arr.push(t, t+Math.floor(Math.random() * 20));
// }
// return arr;
// }(10).map(function(a){
// return [Math.min(a[0],a[1]), Math.max(a[0], a[1])];
// })).replace(/,/g, ', '))
let a = fixt_strdom_ranges([10, 23], [29, 38], [49, 49], [54, 68], [77, 78], [84, 100]);
let b = fixt_strdom_ranges([1, 1], [3, 21], [25, 38], [54, 67], [70, 84], [88, 107]);
fixt_assertStrings(domain_intersection(a, b), fixt_strdom_ranges([10, 21], [29, 38], [54, 67], [77, 78], [84, 84], [88, 100]));
});
it('should divide and conquer some random tests 2', function() {
let a = fixt_strdom_ranges([17, 23], [37, 78], [85, 104]);
let b = fixt_strdom_ranges([6, 25], [47, 56], [58, 60], [64, 67], [83, 103]);
fixt_assertStrings(domain_intersection(a, b), fixt_strdom_ranges([17, 23], [47, 56], [58, 60], [64, 67], [85, 103]));
});