-
-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
338db8b
commit 62fb107
Showing
4 changed files
with
237 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
const left = Symbol('left'); | ||
const right = Symbol('right'); | ||
|
||
class Range { | ||
static getOperator(side, exclusive) { | ||
if (side === 'left') { | ||
return exclusive ? '>' : '>='; | ||
} | ||
|
||
return exclusive ? '<' : '<='; | ||
} | ||
|
||
static formatRight(value, logic, exclusive) { | ||
if (logic === false) { | ||
return Range.formatLeft(value, !logic, !exclusive); | ||
} | ||
|
||
return `should be ${Range.getOperator('right', exclusive)} ${value}`; | ||
} | ||
|
||
static formatLeft(value, logic, exclusive) { | ||
if (logic === false) { | ||
return Range.formatRight(value, !logic, !exclusive); | ||
} | ||
|
||
return `should be ${Range.getOperator('left', exclusive)} ${value}`; | ||
} | ||
|
||
static formatRange(start, end, startExclusive, endExclusive, logic) { | ||
let result = 'should be'; | ||
|
||
result += ` ${Range.getOperator( | ||
logic ? 'left' : 'right', | ||
logic ? startExclusive : !startExclusive | ||
)} ${start} `; | ||
result += logic ? 'and' : 'or'; | ||
result += ` ${Range.getOperator( | ||
logic ? 'right' : 'left', | ||
logic ? endExclusive : !endExclusive | ||
)} ${end}`; | ||
|
||
return result; | ||
} | ||
|
||
static getRangeValue(values, logic) { | ||
let minMax = logic ? Infinity : -Infinity; | ||
let j = -1; | ||
const predicate = logic | ||
? ([value]) => value <= minMax | ||
: ([value]) => value >= minMax; | ||
|
||
for (let i = 0; i < values.length; i++) { | ||
if (predicate(values[i])) { | ||
minMax = values[i][0]; | ||
j = i; | ||
} | ||
} | ||
|
||
if (j > -1) { | ||
return values[j]; | ||
} | ||
|
||
return [Infinity, true]; | ||
} | ||
|
||
constructor() { | ||
this[left] = []; | ||
this[right] = []; | ||
} | ||
|
||
left(value, exclusive = false) { | ||
this[left].push([value, exclusive]); | ||
} | ||
|
||
right(value, exclusive = false) { | ||
this[right].push([value, exclusive]); | ||
} | ||
|
||
format(logic = true) { | ||
const [start, leftExclusive] = Range.getRangeValue(this[left], logic); | ||
const [end, rightExclusive] = Range.getRangeValue(this[right], !logic); | ||
|
||
if (!Number.isFinite(start) && !Number.isFinite(end)) { | ||
return ''; | ||
} | ||
|
||
if (leftExclusive === rightExclusive) { | ||
// e.g. 5 <= x <= 5 | ||
if (leftExclusive === false && start === end) { | ||
return `should be ${logic ? '' : '!'}= ${start}`; | ||
} | ||
|
||
// e.g. 4 < x < 6 | ||
if (leftExclusive === true && start + 1 === end - 1) { | ||
return `should be ${logic ? '' : '!'}= ${start + 1}`; | ||
} | ||
} | ||
|
||
if (Number.isFinite(start) && !Number.isFinite(end)) { | ||
return Range.formatLeft(start, logic, leftExclusive); | ||
} | ||
|
||
if (!Number.isFinite(start) && Number.isFinite(end)) { | ||
return Range.formatRight(end, logic, rightExclusive); | ||
} | ||
|
||
return Range.formatRange(start, end, leftExclusive, rightExclusive, logic); | ||
} | ||
} | ||
|
||
module.exports = Range; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import Range from '../src/util/Range'; | ||
|
||
it('5 <= x <= 5', () => { | ||
const range = new Range(); | ||
range.left(5); | ||
range.right(5); | ||
|
||
expect(range.format()).toEqual('should be = 5'); | ||
}); | ||
|
||
it('not 5 <= x <= 5', () => { | ||
const range = new Range(); | ||
range.left(5); | ||
range.right(5); | ||
|
||
expect(range.format(false)).toEqual('should be != 5'); | ||
}); | ||
|
||
it('-1 < x < 1', () => { | ||
const range = new Range(); | ||
range.left(-1, true); | ||
range.right(1, true); | ||
|
||
expect(range.format()).toEqual('should be = 0'); | ||
}); | ||
|
||
it('not -1 < x < 1', () => { | ||
const range = new Range(); | ||
range.left(-1, true); | ||
range.right(1, true); | ||
|
||
expect(range.format(false)).toEqual('should be != 0'); | ||
}); | ||
|
||
it('not 0 < x <= 10', () => { | ||
const range = new Range(); | ||
range.left(0, true); | ||
range.right(10, false); | ||
|
||
expect(range.format(false)).toEqual('should be <= 0 or > 10'); | ||
}); | ||
|
||
it('x > 1000', () => { | ||
const range = new Range(); | ||
range.left(10000, false); | ||
range.left(1000, true); | ||
|
||
expect(range.format(true)).toEqual('should be > 1000'); | ||
}); | ||
|
||
it('x < 0', () => { | ||
const range = new Range(); | ||
range.right(-1000, true); | ||
range.right(-0, true); | ||
|
||
expect(range.format()).toEqual('should be < 0'); | ||
}); | ||
|
||
it('x >= -1000', () => { | ||
const range = new Range(); | ||
range.right(-1000, true); | ||
range.right(0, false); | ||
|
||
// expect x >= -1000 since it covers bigger range. [-1000, Infinity] is greater than [0, Infinity] | ||
expect(range.format(false)).toEqual('should be >= -1000'); | ||
}); | ||
|
||
it('x <= 0', () => { | ||
const range = new Range(); | ||
range.left(0, true); | ||
range.left(-100, false); | ||
|
||
// expect x <= 0 since it covers bigger range. [-Infinity, 0] is greater than [-Infinity, -100] | ||
expect(range.format(false)).toEqual('should be <= 0'); | ||
}); | ||
|
||
it('Empty string for infinity range', () => { | ||
const range = new Range(); | ||
|
||
expect(range.format(false)).toEqual(''); | ||
}); | ||
|
||
it('0 < x < 122', () => { | ||
const range = new Range(); | ||
range.left(0, true); | ||
range.right(12, false); | ||
range.right(122, true); | ||
|
||
expect(range.format()).toEqual('should be > 0 and < 122'); | ||
}); | ||
|
||
it('-1 <= x < 10', () => { | ||
const range = new Range(); | ||
range.left(-1, false); | ||
range.left(10, true); | ||
range.right(10, true); | ||
|
||
expect(range.format()).toEqual('should be >= -1 and < 10'); | ||
}); | ||
|
||
it('not 10 < x < 10', () => { | ||
const range = new Range(); | ||
range.left(-1, false); | ||
range.left(10, true); | ||
range.right(10, true); | ||
|
||
// expect x <= 10 since it covers bigger range. [-Infinity, 10] is greater than [-Infinity, -1] | ||
expect(range.format(false)).toEqual('should be <= 10 or >= 10'); | ||
}); |