Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continued attempts to get new features to build in PR #14

Merged
merged 9 commits into from
Mar 26, 2019
5 changes: 0 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ jobs:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Set Up Environment
command: |
git submodule update --init --recursive
ci_scripts/ci_tool.sh --setup_npm
- persist_to_workspace:
root: ./
paths:
Expand Down
12 changes: 12 additions & 0 deletions lib/Blackboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@ import {BlackboardRef} from './BlackboardRef';

export interface Blackboard {
create<T>(ref: BlackboardRef<T>, value: T): void;
is<T>(ref: BlackboardRef<T>, value: T): boolean;
get<T>(ref: BlackboardRef<T>): T;
tryGet<T>(ref: BlackboardRef<T>): [true, T]|[false, undefined];
put<T>(ref: BlackboardRef<T>, value: T): void;
delete(ref: BlackboardRef<any>): boolean;
deleteAll(refs: BlackboardRef<any>[]): BlackboardRef<any>[];
}

function isFunction(maybeFunction: any): maybeFunction is Function {
return maybeFunction !== null && maybeFunction !== undefined && typeof maybeFunction === 'function';
}

export const BLACKBOARD_METHODS = Object.freeze(['create', 'get', 'tryGet', 'put', 'delete', 'deleteAll', 'is']);

export function isBlackboard(maybeBlackboard: any): maybeBlackboard is Blackboard {
return (maybeBlackboard !== null && maybeBlackboard !== undefined)
&& !BLACKBOARD_METHODS.some((m) => !isFunction(maybeBlackboard[m]));
}
4 changes: 4 additions & 0 deletions lib/InMemoryMapBlackboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import {BlackboardError} from './BlackboardError';
export class InMemoryMapBlackboard implements Blackboard {
private readonly state: Map<string, [BlackboardRef<any>, any]> = new Map();

public is<T>(ref: BlackboardRef<T>, value: T) {
return this.state.has(ref.uuid) && this.state.get(ref.uuid)![1] === value;
}

public get<T>(ref: BlackboardRef<T>) {
if (this.state.has(ref.uuid)) {
return InMemoryMapBlackboard.cloneObject(this.state.get(ref.uuid)![1]);
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions test/Blackboard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {assert} from 'chai';
import {isBlackboard, BLACKBOARD_METHODS} from '../lib/Blackboard';

function getMockBlackboard() {
return BLACKBOARD_METHODS.reduce((obj, meth) => (obj[meth] = () => ({}), obj), {} as any);
}

describe('Blackboard', function() {
context('user-defined type-guard', function() {
it('succeeds when all properties are present and functions', function() {
assert.isTrue(isBlackboard(getMockBlackboard()));
});
context('per-property checks', function() {
for (const prop of BLACKBOARD_METHODS) {
context(prop, function() {
it('fails if prop is missing', function() {
const bb: any = getMockBlackboard();
delete bb[prop];
assert.isFalse(isBlackboard(bb));
});
it('fails if prop is wrong', function() {
const bb: any = getMockBlackboard();
bb[prop] = 'not a function';
assert.isFalse(isBlackboard(bb));
});
});
}
});
});
});
57 changes: 57 additions & 0 deletions test/InMemoryMapBlackboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,63 @@ describe('InMemoryMapBlackboard', function() {
assert.isTrue(thrown);
});

context('is', function() {
let uut = new InMemoryMapBlackboard();
const bbRef = new BlackboardRef('test');
beforeEach(function() {
uut = new InMemoryMapBlackboard();
});
const refVals = [{}, [], new Map()];
const valVals = ['', 'test', 3, 0, -1, true, false];
const magicVals = [() => ({}), new Error('test')];
context('same as stored', function() {
const testTrue = (value: any) => () => {
uut.create(bbRef, value);
assert.isTrue(uut.is(bbRef, value));
};
context('reference types', function() {
for (const value of refVals) {
it(`works with ${value}`, testTrue(value));
}
});
context('value types', function() {
for (const value of valVals) {
it(`works with ${value}`, testTrue(value));
}
});
context('magic types', function() {
for (const value of magicVals) {
it(`works with ${value}`, testTrue(value));
}
});
});
context('get-clone', function() {
const testFalse = (value: any) => () => {
uut.create(bbRef, value);
assert.isFalse(uut.is(bbRef, uut.get(bbRef)));
};
const testTrue = (value: any) => () => {
uut.create(bbRef, value);
assert.isTrue(uut.is(bbRef, uut.get(bbRef)));
};
context('reference types', function() {
for (const value of refVals) {
it(`works with ${value}`, testFalse(value));
}
});
context('value types', function() {
for (const value of valVals) {
it(`works with ${value}`, testTrue(value));
}
});
context('magic types', function() {
for (const value of magicVals) {
it(`works with ${value}`, testTrue(value));
}
});
});
});

it('get', function() {
const uut = new InMemoryMapBlackboard();
const bbRef = new BlackboardRef('someName');
Expand Down