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

Create mutation APIs #230

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions __tests__/HierarchicalSingleEvent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
Parameter,
OutPort,
InPort,
TimeValue
TimeValue,
CanConnectResult
} from "../src/core/internal";

import {SingleEvent} from "../src/share/SingleEvent";
Expand Down Expand Up @@ -93,7 +94,7 @@ describe("HierarchicalSingleEvent", function () {
seTest.seContainer.child.o,
seTest.logContainer.child.i
)
).toBe(false);
).toBe(CanConnectResult.NOT_IN_SCOPE);

seTest._start();
});
Expand Down
11 changes: 3 additions & 8 deletions __tests__/InvalidMutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,20 @@ class R1 extends Reactor {
[this.in1],
[this.in1, this.in2, this.out1, this.out2],
function (this, __in1, __in2, __out1, __out2) {
test("expect error on creating creating direct feed through", () => {
expect(() => {
this.connect(__in2, __out2);
}).toThrowError("New connection introduces direct feed through.");
});
test("expect error when creating connection outside container", () => {
expect(() => {
this.connect(__out2, __in2);
this.connect(__out2.asConnectable(), __in2.asConnectable());
}).toThrowError("New connection is outside of container.");
});
const R2 = new R1(this.getReactor());
test("expect error on mutation creating race condition on an output port", () => {
expect(() => {
this.connect(R2.out1, __out1);
this.connect(R2.out1.asConnectable(), __out1.asConnectable());
}).toThrowError("Destination port is already occupied.");
});
test("expect error on spawning and creating loop within a reactor", () => {
expect(() => {
this.connect(R2.out1, R2.in1);
this.connect(R2.out1.asConnectable(), R2.in1.asConnectable());
}).toThrowError("New connection introduces cycle.");
});
}
Expand Down
2 changes: 1 addition & 1 deletion __tests__/SimpleMutation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class R2 extends Reactor {
function (this, __in, __out) {
test("expect error to be thrown", () => {
expect(() => {
this.connect(__out, __in);
this.connect(__out.asConnectable(), __in.asConnectable());
}).toThrowError("New connection is outside of container.");
});
}
Expand Down
8 changes: 2 additions & 6 deletions __tests__/SingleEvent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,8 @@ describe("SingleEvent", function () {
expect(expect(seTest.singleEvent).toBeInstanceOf(SingleEvent));
expect(expect(seTest.logger).toBeInstanceOf(Logger));

expect(function () {
seTest.canConnect(seTest.singleEvent.o, seTest.logger.i);
}).toThrow(new Error("Destination port is already occupied."));
expect(seTest.canConnect(seTest.logger.i, seTest.singleEvent.o)).toBe(
false
);
expect(seTest.canConnect(seTest.singleEvent.o, seTest.logger.i)).toBeTruthy();
expect(seTest.canConnect(seTest.logger.i, seTest.singleEvent.o)).toBeTruthy();

seTest._start();
});
Expand Down
99 changes: 99 additions & 0 deletions __tests__/connection.bonus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {App, InPort, OutPort, Reactor} from "../src/core/internal";

// Readers might wonder why this test case exist;
// This is mainly because in the past, we assume direct feedthrough is forbidden, and will not establish the connection if we try to do so. However, it is possible that such a thing happen without introducing any causality issue.
describe("Direct feedthrough without causality issue", () => {
class BigReactor extends App {
public children: SmallReactor;

constructor() {
super(undefined, false, false);
this.children = new SmallReactor(this);
}
}

class SmallReactor extends Reactor {
public inp: InPort<number>;
public outp: OutPort<number>;

constructor(parent: Reactor) {
super(parent);
this.inp = new InPort(this);
this.outp = new OutPort(this);
this.addMutation(
[this.startup],
[this.inp, this.outp],
function (this, inp, outp) {
it("test", () => {
expect(this.getReactor().canConnect(inp, outp)).toBeFalsy();
});
}
);
}
}

const root = new BigReactor();
root._start();
});

describe("Causality loop that can't be detected by only checking local graph", () => {
class FeedThrougher extends Reactor {
public inp = new InPort(this);
public outp = new OutPort(this);

constructor(parent: Reactor) {
super(parent);
this.addReaction(
[this.inp],
[this.inp, this.writable(this.outp)],
function (this, inp, outp) {
// nop troll
}
);
}
}

class Looper extends Reactor {
public leftChild = new FeedThrougher(this);
public rightChild = new FeedThrougher(this);

public inp = new InPort(this);
public outp = new OutPort(this);

constructor(parent: Reactor) {
super(parent);
this.addMutation(
[this.startup],
[
this.inp.asConnectable(),
this.outp.asConnectable(),
this.leftChild.inp.asConnectable(),
this.leftChild.outp.asConnectable(),
this.rightChild.inp.asConnectable(),
this.rightChild.outp.asConnectable()
],
function (this, inp, outp, inp_lc, outp_lc, inp_rc, outp_rc) {
this.connect(inp, inp_lc);
this.connect(outp_rc, outp);
}
);
}
}

class TestApp extends App {
public child = new Looper(this);

constructor() {
super(undefined, undefined, undefined, () => {});
this._connect(this.child.outp, this.child.inp);
it("Test a connection that would create zero delay loop cannot be made", () => {
expect(
this.canConnect(this.child.leftChild.outp, this.child.rightChild.inp)
).toBeTruthy();
});
}
}

const app = new TestApp();
app._start();
});
9 changes: 5 additions & 4 deletions __tests__/connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
OutPort,
InPort,
TimeUnit,
TimeValue
TimeValue,
CanConnectResult
} from "../src/core/internal";

describe("Check canConnect", () => {
Expand All @@ -30,19 +31,19 @@ describe("Check canConnect", () => {

it("canConnect success out->in", () => {
expect(this.canConnect(this.source.out, this.destination.in)).toBe(
true
CanConnectResult.SUCCESS
);
});

it("canConnect success out->out", () => {
expect(this.canConnect(this.source.out, this.destination.out)).toBe(
true
CanConnectResult.SUCCESS
);
});

it("canConnect failure", () => {
expect(this.canConnect(this.destination.in, this.source.out)).toBe(
false
CanConnectResult.NOT_IN_SCOPE
);
});
}
Expand Down
6 changes: 3 additions & 3 deletions __tests__/disconnect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ class R1 extends Reactor {
const R2 = new R1(this.getReactor());
test("expect that disconnecting an existing connection will not result in an error being thrown", () => {
expect(() => {
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
this.disconnect(R2.out2, R2.in2);
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
this.disconnect(R2.out2);
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
}).not.toThrow();
});
}
Expand Down
64 changes: 28 additions & 36 deletions __tests__/hierarchy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Reactor, App, InPort, OutPort} from "../src/core/internal";
import {Reactor, App, InPort, OutPort, CanConnectResult} from "../src/core/internal";

class InOut extends Reactor {
a = new InPort<string>(this);
Expand Down Expand Up @@ -36,65 +36,57 @@ describe("Container to Contained", () => {
it("testing canConnect", () => {
expect(
app.container.canConnect(app.container.a, app.container.contained.a)
).toBe(true);
).toBe(CanConnectResult.SUCCESS);
expect(
app.container.canConnect(app.container.contained.a, app.container.a)
).toBe(false);
).toBe(CanConnectResult.NOT_IN_SCOPE);
expect(
app.container.canConnect(
app.container.a,
app.container.b
)
).toBe(true);
).toBe(CanConnectResult.SUCCESS);
expect(
app.container.canConnect(
app.container.contained.a,
app.container.contained.b
)
).toBe(false);
).toBeTruthy();
expect(
app.container.canConnect(
app.container.contained.b,
app.container.contained.a
)
).toBe(true);
).toBeFalsy();

expect(
app.container.canConnect(app.container.a, app.container.contained.b)
).toBe(false);
).toBeTruthy();
expect(
app.container.canConnect(app.container.contained.b, app.container.a)
).toBe(false);
).toBeTruthy();

expect(
app.container.canConnect(app.container.b, app.container.contained.a)
).toBe(false);
).toBeTruthy();
expect(
app.container.canConnect(app.container.contained.a, app.container.b)
).toBe(false);
).toBeTruthy();

expect(
app.container.canConnect(app.container.b, app.container.contained.b)
).toBe(false);
).toBeTruthy();
expect(
app.container.canConnect(app.container.contained.b, app.container.b)
).toBe(true);

expect(app.container.canConnect(app.container.contained.a, app.foo.a)).toBe(
false
);
expect(app.container.canConnect(app.container.contained.a, app.foo.b)).toBe(
false
);
expect(app.container.canConnect(app.foo.a, app.container.contained.a)).toBe(
false
);
expect(app.container.canConnect(app.foo.a, app.container.contained.a)).toBe(
false
);

expect(app.container.canConnect(app.foo.a, app.container.b)).toBe(false);
expect(app.container.canConnect(app.foo.a, app.container.a)).toBe(false);
).toBeFalsy();

expect(app.container.canConnect(app.container.contained.a, app.foo.a)).toBeTruthy();
expect(app.container.canConnect(app.container.contained.a, app.foo.b)).toBeTruthy();
expect(app.container.canConnect(app.foo.a, app.container.contained.a)).toBeTruthy();
expect(app.container.canConnect(app.foo.a, app.container.contained.a)).toBeTruthy();

expect(app.container.canConnect(app.foo.a, app.container.b)).toBeTruthy();
expect(app.container.canConnect(app.foo.a, app.container.a)).toBeTruthy();

// expect(app.container.contained).toBeDefined();

Expand All @@ -104,49 +96,49 @@ describe("Container to Contained", () => {
app.container.contained.containedAgain.a,
app.container.contained.a
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.b,
app.container.contained.b
)
).toBe(true);
).toBeFalsy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.a,
app.container.a
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.b,
app.container.b
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.a,
app.foo.a
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.b,
app.foo.b
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.a,
app.foo.a
)
).toBe(false);
).toBeTruthy();
expect(
app.container.contained.canConnect(
app.container.contained.containedAgain.b,
app.foo.b
)
).toBe(false);
).toBeTruthy();
// }
});
});
Loading
Loading