-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add "Crosses" specification (and tests)
- Loading branch information
1 parent
fede4e4
commit f764014
Showing
3 changed files
with
247 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
**New Features** | ||
|
||
* Added a `Changes` specification. | ||
* Added a `Crosses` specification. | ||
* Added a `Null` specification. | ||
* Added an `Undefined` specification. |
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,57 @@ | ||
const assert = require('./../lang/assert'); | ||
is = require('./../lang/is'); | ||
|
||
const Specification = require('./Specification'); | ||
|
||
module.exports = (() => { | ||
'use strict'; | ||
|
||
/** | ||
* A stateful {@link Specification} that passes when the value of the data item | ||
* crosses a value passed to the constructor. The specification will never pass | ||
* on the first evaluation. Instead, the first data item is used to determine | ||
* if the value is currently greater than (or less than) the threshold value | ||
* (passed to the constructor). This determines if the passing condition means | ||
* the value must be less than (or greater than) the threshold. | ||
* | ||
* @public | ||
* @extends {Specification} | ||
* @param {Number} threshold | ||
*/ | ||
class CrossesSpecification extends Specification { | ||
constructor(threshold) { | ||
super(); | ||
|
||
assert.argumentIsRequired(threshold, 'threshold', Number); | ||
|
||
this._threshold = threshold; | ||
|
||
this._previous = null; | ||
} | ||
|
||
_evaluate(data) { | ||
if (!is.number(data)) { | ||
return false; | ||
} | ||
|
||
const current = data; | ||
const previous = this._previous; | ||
|
||
const crossed = previous !== null && | ||
( | ||
(previous > this._threshold && !(current > this._threshold)) || | ||
(previous < this._threshold && !(current < this._threshold)) | ||
); | ||
|
||
this._previous = current; | ||
|
||
return crossed; | ||
} | ||
|
||
toString() { | ||
return '[CrossesSpecification]'; | ||
} | ||
} | ||
|
||
return CrossesSpecification; | ||
})(); |
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,189 @@ | ||
const Crosses = require('./../../../specifications/Crosses'); | ||
|
||
describe('When a Crosses specification is initialized with a threshold of 1000', () => { | ||
'use strict'; | ||
|
||
let specification; | ||
|
||
beforeEach(() => { | ||
specification = new Crosses(1000); | ||
}); | ||
|
||
describe('and the first value evaluated is 900', () => { | ||
let r1; | ||
|
||
beforeEach(() => { | ||
r1 = specification.evaluate(900); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r1).toEqual(false); | ||
}); | ||
|
||
describe('and the second value evaluated is 1100', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(1100); | ||
}); | ||
|
||
it('should pass', () => { | ||
expect(r2).toEqual(true); | ||
}); | ||
|
||
describe('and the third value evaluated is 999', () => { | ||
let r3; | ||
|
||
beforeEach(() => { | ||
r3 = specification.evaluate(999); | ||
}); | ||
|
||
it('should pass', () => { | ||
expect(r3).toEqual(true); | ||
}); | ||
}); | ||
|
||
describe('and the third value evaluated is 1001', () => { | ||
let r3; | ||
|
||
beforeEach(() => { | ||
r3 = specification.evaluate(1001); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r3).toEqual(false); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('and the second value evaluated is 950', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(950); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r2).toEqual(false); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('and the first value evaluated is 1200', () => { | ||
let r1; | ||
|
||
beforeEach(() => { | ||
r1 = specification.evaluate(1200); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r1).toEqual(false); | ||
}); | ||
|
||
describe('and the second value evaluated is 1100', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(1100); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r2).toEqual(false); | ||
}); | ||
}); | ||
|
||
describe('and the second value evaluated is 950', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(950); | ||
}); | ||
|
||
it('should pass', () => { | ||
expect(r2).toEqual(true); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('When a Crosses specification is initialized with a threshold of zero', () => { | ||
'use strict'; | ||
|
||
let specification; | ||
|
||
beforeEach(() => { | ||
specification = new Crosses(0); | ||
}); | ||
|
||
describe('and the first value evaluated is 1', () => { | ||
let r1; | ||
|
||
beforeEach(() => { | ||
r1 = specification.evaluate(1); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r1).toEqual(false); | ||
}); | ||
|
||
describe('and the second value evaluated is -1', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(-1); | ||
}); | ||
|
||
it('should pass', () => { | ||
expect(r2).toEqual(true); | ||
}); | ||
}); | ||
|
||
describe('and the second value evaluated is 0.5', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(0.5); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r2).toEqual(false); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('and the first value evaluated is -1', () => { | ||
let r1; | ||
|
||
beforeEach(() => { | ||
r1 = specification.evaluate(-1); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r1).toEqual(false); | ||
}); | ||
|
||
describe('and the second value evaluated is -0.5', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(-0.5); | ||
}); | ||
|
||
it('should not pass', () => { | ||
expect(r2).toEqual(false); | ||
}); | ||
}); | ||
|
||
describe('and the second value evaluated is 1', () => { | ||
let r2; | ||
|
||
beforeEach(() => { | ||
r2 = specification.evaluate(1); | ||
}); | ||
|
||
it('should pass', () => { | ||
expect(r2).toEqual(true); | ||
}); | ||
}); | ||
}); | ||
}); |