Skip to content

Commit

Permalink
Add "Crosses" specification (and tests)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryaningl3 committed Jan 27, 2022
1 parent fede4e4 commit f764014
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 0 deletions.
1 change: 1 addition & 0 deletions .releases/4.18.0.md
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.
57 changes: 57 additions & 0 deletions specifications/Crosses.js
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;
})();
189 changes: 189 additions & 0 deletions test/specs/specifications/CrossesSpec.js
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);
});
});
});
});

0 comments on commit f764014

Please sign in to comment.