| @@ -0,0 +1,17 | |||||
|
|
1 | <?xml version="1.0" encoding="UTF-8"?> | |||
|
|
2 | <projectDescription> | |||
|
|
3 | <name>core</name> | |||
|
|
4 | <comment>Project implabjs-core created by Buildship.</comment> | |||
|
|
5 | <projects> | |||
|
|
6 | </projects> | |||
|
|
7 | <buildSpec> | |||
|
|
8 | <buildCommand> | |||
|
|
9 | <name>org.eclipse.buildship.core.gradleprojectbuilder</name> | |||
|
|
10 | <arguments> | |||
|
|
11 | </arguments> | |||
|
|
12 | </buildCommand> | |||
|
|
13 | </buildSpec> | |||
|
|
14 | <natures> | |||
|
|
15 | <nature>org.eclipse.buildship.core.gradleprojectnature</nature> | |||
|
|
16 | </natures> | |||
|
|
17 | </projectDescription> | |||
| @@ -0,0 +1,54 | |||||
|
|
1 | import { MockActivationController } from "../mock/MockActivationController"; | |||
|
|
2 | import { SimpleActivatable } from "../mock/SimpleActivatable"; | |||
|
|
3 | import { test } from "./TestTraits"; | |||
|
|
4 | ||||
|
|
5 | test("simple activation", async t => { | |||
|
|
6 | ||||
|
|
7 | const a = new SimpleActivatable(); | |||
|
|
8 | t.false(a.isActive()); | |||
|
|
9 | ||||
|
|
10 | await a.activate(); | |||
|
|
11 | t.true(a.isActive()); | |||
|
|
12 | ||||
|
|
13 | await a.deactivate(); | |||
|
|
14 | t.false(a.isActive()); | |||
|
|
15 | }); | |||
|
|
16 | ||||
|
|
17 | test("controller activation", async t => { | |||
|
|
18 | ||||
|
|
19 | const a = new SimpleActivatable(); | |||
|
|
20 | const c = new MockActivationController(); | |||
|
|
21 | ||||
|
|
22 | t.false(a.isActive(), "the component is not active by default"); | |||
|
|
23 | t.assert(c.getActive() == null, "the activation controller doesn't have an active component by default"); | |||
|
|
24 | t.assert(a.getActivationController() == null, "the component doesn't have an activation controller by default"); | |||
|
|
25 | ||||
|
|
26 | t.comment("Active the component through the controller"); | |||
|
|
27 | await c.activate(a); | |||
|
|
28 | t.true(a.isActive(), "The component should successfully activate"); | |||
|
|
29 | t.equal(c.getActive(), a, "The controller should point to the activated component"); | |||
|
|
30 | t.equal(a.getActivationController(), c, "The component should point to the controller"); | |||
|
|
31 | ||||
|
|
32 | t.comment("Deactive the component throug the controller"); | |||
|
|
33 | await c.deactivate(); | |||
|
|
34 | ||||
|
|
35 | t.false(a.isActive(), "The component should successfully deactivate"); | |||
|
|
36 | t.equal(c.getActive(), null, "The controller shouldn't point to any component"); | |||
|
|
37 | t.equal(a.getActivationController(), c, "The componet should point to it's controller"); | |||
|
|
38 | }); | |||
|
|
39 | ||||
|
|
40 | test("handle error in onActivating", async t => { | |||
|
|
41 | const a = new SimpleActivatable(); | |||
|
|
42 | ||||
|
|
43 | a.onActivating = async () => { | |||
|
|
44 | throw new Error("Should fail"); | |||
|
|
45 | }; | |||
|
|
46 | ||||
|
|
47 | try { | |||
|
|
48 | await a.activate(); | |||
|
|
49 | t.fail("activation should fail"); | |||
|
|
50 | } catch { | |||
|
|
51 | } | |||
|
|
52 | ||||
|
|
53 | t.false(a.isActive(), "the component should remain inactive"); | |||
|
|
54 | }); | |||
| @@ -0,0 +1,88 | |||||
|
|
1 | import { Cancellation } from "../Cancellation"; | |||
|
|
2 | import { delay } from "../safe"; | |||
|
|
3 | import { test } from "./TestTraits"; | |||
|
|
4 | ||||
|
|
5 | test("standalone cancellation", async t => { | |||
|
|
6 | ||||
|
|
7 | let doCancel: (e) => void; | |||
|
|
8 | ||||
|
|
9 | const ct = new Cancellation(cancel => { | |||
|
|
10 | doCancel = cancel; | |||
|
|
11 | }); | |||
|
|
12 | ||||
|
|
13 | let counter = 0; | |||
|
|
14 | const reason = "BILL"; | |||
|
|
15 | ||||
|
|
16 | t.true(ct.isSupported(), "Cancellation must be supported"); | |||
|
|
17 | t.false(ct.isRequested(), "Cancellation shouldn't be requested"); | |||
|
|
18 | ct.throwIfRequested(); | |||
|
|
19 | t.pass("The exception shouldn't be thrown unless the cancellation is requested"); | |||
|
|
20 | ||||
|
|
21 | ct.register(() => counter++); | |||
|
|
22 | t.equals(counter, 0, "counter should be zero"); | |||
|
|
23 | ||||
|
|
24 | ct.register(() => counter++).destroy(); | |||
|
|
25 | ||||
|
|
26 | doCancel(reason); | |||
|
|
27 | ||||
|
|
28 | t.true(ct.isRequested(), "Cancellation should be requested"); | |||
|
|
29 | t.equals(counter, 1, "The registered callback should be triggered"); | |||
|
|
30 | ||||
|
|
31 | ct.register(() => counter++); | |||
|
|
32 | t.equals(counter, 2, "The callback should be triggered immediately"); | |||
|
|
33 | ||||
|
|
34 | let msg; | |||
|
|
35 | ct.register(e => msg = e); | |||
|
|
36 | t.equals(msg, reason, "The cancellation reason should be passed to callback"); | |||
|
|
37 | ||||
|
|
38 | try { | |||
|
|
39 | msg = null; | |||
|
|
40 | ct.throwIfRequested(); | |||
|
|
41 | t.fail("The exception should be thrown"); | |||
|
|
42 | } catch (e) { | |||
|
|
43 | msg = e; | |||
|
|
44 | } | |||
|
|
45 | t.equals(msg, reason, "The cancellation reason should be catched"); | |||
|
|
46 | }); | |||
|
|
47 | ||||
|
|
48 | test("async cancellation", async t => { | |||
|
|
49 | ||||
|
|
50 | const ct = new Cancellation(cancel => { | |||
|
|
51 | cancel("STOP!"); | |||
|
|
52 | }); | |||
|
|
53 | ||||
|
|
54 | try { | |||
|
|
55 | await delay(0, ct); | |||
|
|
56 | t.fail("Should thow the exception"); | |||
|
|
57 | } catch (e) { | |||
|
|
58 | t.equals(e, "STOP!", "Should throw the cancellation reason"); | |||
|
|
59 | } | |||
|
|
60 | }); | |||
|
|
61 | ||||
|
|
62 | test("cancel with external event", async t => { | |||
|
|
63 | const ct = new Cancellation(cancel => { | |||
|
|
64 | setTimeout(x => cancel("STOP!"), 0); | |||
|
|
65 | }); | |||
|
|
66 | ||||
|
|
67 | try { | |||
|
|
68 | await delay(10000, ct); | |||
|
|
69 | t.fail("Should thow the exception"); | |||
|
|
70 | } catch (e) { | |||
|
|
71 | t.equals(e, "STOP!", "Should throw the cancellation reason"); | |||
|
|
72 | } | |||
|
|
73 | }); | |||
|
|
74 | ||||
|
|
75 | test("operation normal flow", async t => { | |||
|
|
76 | ||||
|
|
77 | let htimeout; | |||
|
|
78 | const ct = new Cancellation(cancel => { | |||
|
|
79 | htimeout = setTimeout(() => cancel("STOP!"), 1000); | |||
|
|
80 | }); | |||
|
|
81 | ||||
|
|
82 | try { | |||
|
|
83 | await delay(0, ct); | |||
|
|
84 | t.pass("Should pass"); | |||
|
|
85 | } finally { | |||
|
|
86 | clearTimeout(htimeout); | |||
|
|
87 | } | |||
|
|
88 | }); | |||
| @@ -0,0 +1,93 | |||||
|
|
1 | import { test } from "./TestTraits"; | |||
|
|
2 | import { Container } from "../di/Container"; | |||
|
|
3 | import { ReferenceDescriptor } from "../di/ReferenceDescriptor"; | |||
|
|
4 | import { AggregateDescriptor } from "../di/AggregateDescriptor"; | |||
|
|
5 | import { ValueDescriptor } from "../di/ValueDescriptor"; | |||
|
|
6 | import { Foo } from "../mock/Foo"; | |||
|
|
7 | import { Bar } from "../mock/Bar"; | |||
|
|
8 | import { isNull } from "../safe"; | |||
|
|
9 | ||||
|
|
10 | test("Container register/resolve tests", async t => { | |||
|
|
11 | const container = new Container(); | |||
|
|
12 | ||||
|
|
13 | const connection1 = "db://localhost"; | |||
|
|
14 | ||||
|
|
15 | t.throws( | |||
|
|
16 | () => container.register("bla-bla", "bla-bla"), | |||
|
|
17 | "Do not allow to register anything other than descriptors" | |||
|
|
18 | ); | |||
|
|
19 | ||||
|
|
20 | t.doesNotThrow( | |||
|
|
21 | () => container.register("connection", new ValueDescriptor(connection1)), | |||
|
|
22 | "register ValueDescriptor" | |||
|
|
23 | ); | |||
|
|
24 | ||||
|
|
25 | t.equals(container.resolve("connection"), connection1, "resolve string value"); | |||
|
|
26 | ||||
|
|
27 | t.doesNotThrow( | |||
|
|
28 | () => container.register( | |||
|
|
29 | "dbParams", | |||
|
|
30 | new AggregateDescriptor({ | |||
|
|
31 | timeout: 10, | |||
|
|
32 | connection: new ReferenceDescriptor({ name: "connection" }) | |||
|
|
33 | }) | |||
|
|
34 | ), | |||
|
|
35 | "register AggregateDescriptor" | |||
|
|
36 | ); | |||
|
|
37 | ||||
|
|
38 | const dbParams = container.resolve("dbParams"); | |||
|
|
39 | t.equals(dbParams.connection, connection1, "should get string value 'dbParams.connection'"); | |||
|
|
40 | }); | |||
|
|
41 | ||||
|
|
42 | test("Container configure/resolve tests", async t => { | |||
|
|
43 | ||||
|
|
44 | const container = new Container(); | |||
|
|
45 | ||||
|
|
46 | await container.configure({ | |||
|
|
47 | foo: { | |||
|
|
48 | $type: Foo | |||
|
|
49 | }, | |||
|
|
50 | ||||
|
|
51 | box: { | |||
|
|
52 | $type: Bar, | |||
|
|
53 | params: { | |||
|
|
54 | $dependency: "foo" | |||
|
|
55 | } | |||
|
|
56 | }, | |||
|
|
57 | ||||
|
|
58 | bar: { | |||
|
|
59 | $type: Bar, | |||
|
|
60 | params: { | |||
|
|
61 | db: { | |||
|
|
62 | provider: { | |||
|
|
63 | $dependency: "db" | |||
|
|
64 | } | |||
|
|
65 | } | |||
|
|
66 | } | |||
|
|
67 | } | |||
|
|
68 | }); | |||
|
|
69 | t.pass("should configure from js object"); | |||
|
|
70 | ||||
|
|
71 | const f1 = container.resolve("foo"); | |||
|
|
72 | ||||
|
|
73 | t.assert(!isNull(f1), "foo should be not null"); | |||
|
|
74 | ||||
|
|
75 | t.throws(() => container.resolve("bar"), "should not resolve dependency 'db'"); | |||
|
|
76 | ||||
|
|
77 | }); | |||
|
|
78 | ||||
|
|
79 | test("Load configuration from module", async t => { | |||
|
|
80 | const container = new Container(); | |||
|
|
81 | ||||
|
|
82 | await container.configure("./mock/config1", { contextRequire: require }); | |||
|
|
83 | t.pass("The configuration should load"); | |||
|
|
84 | ||||
|
|
85 | const f1 = container.resolve("foo"); | |||
|
|
86 | ||||
|
|
87 | t.assert(!isNull(f1), "foo should be not null"); | |||
|
|
88 | ||||
|
|
89 | const b1 = container.resolve("bar") as Bar; | |||
|
|
90 | ||||
|
|
91 | t.assert(!isNull(b1), "bar should not be null"); | |||
|
|
92 | t.assert(!isNull(b1.foo), "bar.foo should not be null"); | |||
|
|
93 | }); | |||
| @@ -0,0 +1,69 | |||||
|
|
1 | import { TraceSource } from "../log/TraceSource"; | |||
|
|
2 | import { Observable } from "../Observable"; | |||
|
|
3 | import { IObservable } from "../interfaces"; | |||
|
|
4 | import { delay } from "../safe"; | |||
|
|
5 | import { test } from "./TestTraits"; | |||
|
|
6 | ||||
|
|
7 | const trace = TraceSource.get("ObservableTests"); | |||
|
|
8 | ||||
|
|
9 | test("events sequence example", async t => { | |||
|
|
10 | ||||
|
|
11 | let events: IObservable<number>; | |||
|
|
12 | ||||
|
|
13 | const done = new Promise<void>(resolve => { | |||
|
|
14 | events = new Observable<number>(async (notify, fail, finish) => { | |||
|
|
15 | for (let i = 0; i < 10; i++) { | |||
|
|
16 | await delay(0); | |||
|
|
17 | notify(i); | |||
|
|
18 | } | |||
|
|
19 | finish(); | |||
|
|
20 | resolve(); | |||
|
|
21 | }); | |||
|
|
22 | }); | |||
|
|
23 | ||||
|
|
24 | let count = 0; | |||
|
|
25 | let complete = false; | |||
|
|
26 | events.on(x => count = count + x, null, () => complete = true); | |||
|
|
27 | ||||
|
|
28 | const first = await events.next(); | |||
|
|
29 | ||||
|
|
30 | t.equals(first, 0, "the first event"); | |||
|
|
31 | t.false(complete, "the sequence is not complete"); | |||
|
|
32 | ||||
|
|
33 | await done; | |||
|
|
34 | ||||
|
|
35 | t.equals(count, 45, "the summ of the evetns"); | |||
|
|
36 | t.true(complete, "the sequence is complete"); | |||
|
|
37 | }); | |||
|
|
38 | ||||
|
|
39 | test("event sequence termination", async t => { | |||
|
|
40 | let events: IObservable<number>; | |||
|
|
41 | ||||
|
|
42 | const done = new Promise<void>(resolve => { | |||
|
|
43 | events = new Observable<number>(async (notify, fail, complete) => { | |||
|
|
44 | await delay(0); | |||
|
|
45 | notify(1); | |||
|
|
46 | complete(); | |||
|
|
47 | notify(2); | |||
|
|
48 | complete(); | |||
|
|
49 | fail("Sequence terminated"); | |||
|
|
50 | resolve(); | |||
|
|
51 | }); | |||
|
|
52 | }); | |||
|
|
53 | ||||
|
|
54 | let count = 0; | |||
|
|
55 | events.on(() => {}, e => count++, () => count++); | |||
|
|
56 | ||||
|
|
57 | const first = await events.next(); | |||
|
|
58 | t.equals(first, 1, "the first message"); | |||
|
|
59 | try { | |||
|
|
60 | await events.next(); | |||
|
|
61 | t.fail("shoud throw an exception"); | |||
|
|
62 | } catch (e) { | |||
|
|
63 | t.pass("the sequence is terminated"); | |||
|
|
64 | } | |||
|
|
65 | ||||
|
|
66 | await done; | |||
|
|
67 | ||||
|
|
68 | t.equals(count, 1, "the sequence must be terminated once"); | |||
|
|
69 | }); | |||
| @@ -0,0 +1,95 | |||||
|
|
1 | import { Cancellation } from "../Cancellation"; | |||
|
|
2 | import { first, isPromise, firstWhere, delay, nowait } from "../safe"; | |||
|
|
3 | import { test } from "./TestTraits"; | |||
|
|
4 | ||||
|
|
5 | test("await delay test", async t => { | |||
|
|
6 | // schedule delay | |||
|
|
7 | let resolved = false; | |||
|
|
8 | let res = delay(0).then(() => resolved = true); | |||
|
|
9 | ||||
|
|
10 | t.false(resolved, "the delay should be async"); | |||
|
|
11 | ||||
|
|
12 | await res; | |||
|
|
13 | t.pass("await delay"); | |||
|
|
14 | ||||
|
|
15 | // create cancellation token | |||
|
|
16 | let cancel: (e?: any) => void; | |||
|
|
17 | const ct = new Cancellation(c => cancel = c); | |||
|
|
18 | ||||
|
|
19 | // schedule delay | |||
|
|
20 | resolved = false; | |||
|
|
21 | res = delay(0, ct).then(() => resolved = true); | |||
|
|
22 | ||||
|
|
23 | t.false(resolved, "created delay with ct"); | |||
|
|
24 | ||||
|
|
25 | // cancel | |||
|
|
26 | cancel(); | |||
|
|
27 | ||||
|
|
28 | try { | |||
|
|
29 | await res; | |||
|
|
30 | t.fail("the delay should fail when it is cancelled"); | |||
|
|
31 | } catch { | |||
|
|
32 | t.pass("the delay is cancelled"); | |||
|
|
33 | } | |||
|
|
34 | ||||
|
|
35 | t.throws(() => { | |||
|
|
36 | // try schedule delay after the cancellation is requested | |||
|
|
37 | nowait(delay(0, ct)); | |||
|
|
38 | }, "Should throw if cancelled before start"); | |||
|
|
39 | }); | |||
|
|
40 | ||||
|
|
41 | test("sequemce test", async t => { | |||
|
|
42 | const sequence = ["a", "b", "c"]; | |||
|
|
43 | const empty = []; | |||
|
|
44 | ||||
|
|
45 | // synchronous tests | |||
|
|
46 | t.equals(first(sequence), "a", "Should return the first element"); | |||
|
|
47 | t.equals(firstWhere(sequence, x => x === "b"), "b", "Should get the second element"); | |||
|
|
48 | ||||
|
|
49 | let v: string; | |||
|
|
50 | let e: Error; | |||
|
|
51 | first(sequence, x => v = x); | |||
|
|
52 | t.equal(v, "a", "The callback should be called for the first element"); | |||
|
|
53 | firstWhere(sequence, x => x === "b", x => v = x); | |||
|
|
54 | t.equal(v, "b", "The callback should be called for the second element"); | |||
|
|
55 | ||||
|
|
56 | t.throws(() => { | |||
|
|
57 | first(empty); | |||
|
|
58 | }, "Should throw when the sequence is empty"); | |||
|
|
59 | ||||
|
|
60 | t.throws(() => { | |||
|
|
61 | firstWhere(empty, x => x === "b"); | |||
|
|
62 | }, "Should throw when the sequence is empty"); | |||
|
|
63 | ||||
|
|
64 | t.throws(() => { | |||
|
|
65 | first(empty, x => v = x); | |||
|
|
66 | }, "Should throw when the sequence is empty"); | |||
|
|
67 | ||||
|
|
68 | t.throws(() => { | |||
|
|
69 | firstWhere(empty, x => x === "b", x => v = x); | |||
|
|
70 | }, "Should throw when the sequence is empty"); | |||
|
|
71 | ||||
|
|
72 | t.throws(() => { | |||
|
|
73 | firstWhere(sequence, x => x === "z"); | |||
|
|
74 | }, "Should throw when the element isn't found"); | |||
|
|
75 | ||||
|
|
76 | t.throws(() => { | |||
|
|
77 | firstWhere(sequence, x => x === "z", x => v = x); | |||
|
|
78 | }, "Should throw when the element isn't found"); | |||
|
|
79 | ||||
|
|
80 | first(empty, null, x => e = x); | |||
|
|
81 | t.true(e, "The errorback should be called for the empty sequence"); | |||
|
|
82 | ||||
|
|
83 | // async tests | |||
|
|
84 | const asyncSequence = Promise.resolve(sequence); | |||
|
|
85 | const asyncEmptySequence = Promise.resolve(empty); | |||
|
|
86 | ||||
|
|
87 | const promise = first(asyncSequence); | |||
|
|
88 | t.true(isPromise(promise), "Should return promise"); | |||
|
|
89 | ||||
|
|
90 | v = await promise; | |||
|
|
91 | t.equal(v, "a", "Should return the first element"); | |||
|
|
92 | ||||
|
|
93 | v = await new Promise(resolve => first(asyncSequence, resolve)); | |||
|
|
94 | t.equal(v, "a", "The callback should be called for the first element"); | |||
|
|
95 | }); | |||
| @@ -0,0 +1,74 | |||||
|
|
1 | import { IObservable, ICancellation, IDestroyable } from "../interfaces"; | |||
|
|
2 | import { Cancellation } from "../Cancellation"; | |||
|
|
3 | import { TraceEvent, LogLevel, WarnLevel, DebugLevel, TraceSource } from "../log/TraceSource"; | |||
|
|
4 | import * as tape from "tape"; | |||
|
|
5 | import { argumentNotNull, destroy } from "../safe"; | |||
|
|
6 | ||||
|
|
7 | export class TapeWriter implements IDestroyable { | |||
|
|
8 | private readonly _tape: tape.Test; | |||
|
|
9 | ||||
|
|
10 | private readonly _subscriptions = new Array<IDestroyable>(); | |||
|
|
11 | private _destroyed; | |||
|
|
12 | ||||
|
|
13 | constructor(t: tape.Test) { | |||
|
|
14 | argumentNotNull(t, "tape"); | |||
|
|
15 | this._tape = t; | |||
|
|
16 | } | |||
|
|
17 | ||||
|
|
18 | writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) { | |||
|
|
19 | if (!this._destroyed) { | |||
|
|
20 | const subscription = source.on(this.writeEvent.bind(this)); | |||
|
|
21 | if (ct.isSupported()) { | |||
|
|
22 | ct.register(subscription.destroy.bind(subscription)); | |||
|
|
23 | } | |||
|
|
24 | this._subscriptions.push(subscription); | |||
|
|
25 | } | |||
|
|
26 | } | |||
|
|
27 | ||||
|
|
28 | writeEvent(next: TraceEvent) { | |||
|
|
29 | if (next.level >= DebugLevel) { | |||
|
|
30 | this._tape.comment(`DEBUG ${next.source.id} ${next}`); | |||
|
|
31 | } else if (next.level >= LogLevel) { | |||
|
|
32 | this._tape.comment(`LOG ${next.source.id} ${next}`); | |||
|
|
33 | } else if (next.level >= WarnLevel) { | |||
|
|
34 | this._tape.comment(`WARN ${next.source.id} ${next}`); | |||
|
|
35 | } else { | |||
|
|
36 | this._tape.comment(`ERROR ${next.source.id} ${next}`); | |||
|
|
37 | } | |||
|
|
38 | } | |||
|
|
39 | ||||
|
|
40 | destroy() { | |||
|
|
41 | this._subscriptions.forEach(destroy); | |||
|
|
42 | } | |||
|
|
43 | } | |||
|
|
44 | ||||
|
|
45 | export function test(name: string, cb: (t: tape.Test, trace: TraceSource) => any) { | |||
|
|
46 | tape(name, async t => { | |||
|
|
47 | const writer = new TapeWriter(t); | |||
|
|
48 | ||||
|
|
49 | // this trace is not announced through the TraceSource global registry | |||
|
|
50 | const trace = new TraceSource(name); | |||
|
|
51 | trace.level = DebugLevel; | |||
|
|
52 | writer.writeEvents(trace.events); | |||
|
|
53 | ||||
|
|
54 | const h = TraceSource.on(ts => { | |||
|
|
55 | ts.level = DebugLevel; | |||
|
|
56 | writer.writeEvents(ts.events); | |||
|
|
57 | }); | |||
|
|
58 | ||||
|
|
59 | try { | |||
|
|
60 | await cb(t, trace); | |||
|
|
61 | } catch (e) { | |||
|
|
62 | ||||
|
|
63 | // verbose error information | |||
|
|
64 | // tslint:disable-next-line | |||
|
|
65 | console.error(e); | |||
|
|
66 | t.fail(e); | |||
|
|
67 | ||||
|
|
68 | } finally { | |||
|
|
69 | t.end(); | |||
|
|
70 | destroy(writer); | |||
|
|
71 | destroy(h); | |||
|
|
72 | } | |||
|
|
73 | }); | |||
|
|
74 | } | |||
| @@ -0,0 +1,86 | |||||
|
|
1 | import { StringBuilder } from "../text/StringBuilder"; | |||
|
|
2 | import { test } from "./TestTraits"; | |||
|
|
3 | import { MockConsole } from "../mock/MockConsole"; | |||
|
|
4 | import { ConsoleWriter } from "../log/ConsoleWriter"; | |||
|
|
5 | ||||
|
|
6 | test("String builder", async t => { | |||
|
|
7 | const sb = new StringBuilder(); | |||
|
|
8 | ||||
|
|
9 | sb.write("hello"); | |||
|
|
10 | t.equals(sb.toString(), "hello", "Write simple text"); | |||
|
|
11 | ||||
|
|
12 | sb.write(", "); | |||
|
|
13 | sb.write("world!"); | |||
|
|
14 | t.equals(sb.toString(), "hello, world!", "Append text"); | |||
|
|
15 | ||||
|
|
16 | sb.clear(); | |||
|
|
17 | t.equals(sb.toString(), "", "Clear"); | |||
|
|
18 | ||||
|
|
19 | sb.write(1); | |||
|
|
20 | t.equals(sb.toString(), "1", "Write number"); | |||
|
|
21 | ||||
|
|
22 | sb.clear(); | |||
|
|
23 | sb.writeValue(0.123); | |||
|
|
24 | t.equals(sb.toString(), "0.123", "Format number"); | |||
|
|
25 | ||||
|
|
26 | sb.clear(); | |||
|
|
27 | sb.writeValue(new Date("2019-01-02T00:00:00.000Z")); | |||
|
|
28 | t.equals(sb.toString(), "2019-01-02T00:00:00.000Z", "Format date (ISO)"); | |||
|
|
29 | ||||
|
|
30 | sb.clear(); | |||
|
|
31 | sb.write("{0}", "hello"); | |||
|
|
32 | t.equals(sb.toString(), "hello", "Simple format text"); | |||
|
|
33 | ||||
|
|
34 | sb.write(", {0}!", "world"); | |||
|
|
35 | t.equals(sb.toString(), "hello, world!", "Append formatted text"); | |||
|
|
36 | ||||
|
|
37 | sb.clear(); | |||
|
|
38 | sb.write("abc: {0:json}; {0.length}; {0.1} {{olo}}", ["a", "b", "c"]); | |||
|
|
39 | t.equals(sb.toString(), 'abc: [\n "a",\n "b",\n "c"\n]; 3; b {olo}', "Format string with spec"); | |||
|
|
40 | ||||
|
|
41 | sb.clear(); | |||
|
|
42 | t.throws(() => sb.write("}", 0), "Should die on bad format: '}'"); | |||
|
|
43 | t.throws(() => sb.write("{", 0), "Should die on bad format: '{'"); | |||
|
|
44 | t.throws(() => sb.write("{}", 0), "Should die on bad format: '{}'"); | |||
|
|
45 | t.throws(() => sb.write("{:}", 0), "Should die on bad format: '{:}'"); | |||
|
|
46 | t.throws(() => sb.write("{{0}", 0), "Should die on bad format: '{{0}'"); | |||
|
|
47 | ||||
|
|
48 | }); | |||
|
|
49 | ||||
|
|
50 | test("ConsoleWriter", t => { | |||
|
|
51 | const mockConsole = new MockConsole(); | |||
|
|
52 | const writer = new ConsoleWriter(mockConsole); | |||
|
|
53 | ||||
|
|
54 | writer.setLogLevel("log"); | |||
|
|
55 | ||||
|
|
56 | writer.writeLine("Hello, world!"); | |||
|
|
57 | ||||
|
|
58 | t.equals(mockConsole.getBuffer().length, 1, "One line should be written"); | |||
|
|
59 | t.equals(mockConsole.getBuffer()[0].level, "log", "LogLevel should be 'log'"); | |||
|
|
60 | t.deepEqual(mockConsole.getBuffer()[0].data, ["Hello, world!"], "The buffer should contain single string"); | |||
|
|
61 | ||||
|
|
62 | mockConsole.clear(); | |||
|
|
63 | writer.setLogLevel("debug"); | |||
|
|
64 | writer.write("Bring "); | |||
|
|
65 | writer.write("the {0}!", "light"); | |||
|
|
66 | t.equals(mockConsole.getBuffer().length, 0, "No line should be written"); | |||
|
|
67 | writer.writeLine(); | |||
|
|
68 | ||||
|
|
69 | t.equals(mockConsole.getBuffer().length, 1, "One line should be written"); | |||
|
|
70 | t.equals(mockConsole.getBuffer()[0].level, "debug", "LogLevel should be 'log'"); | |||
|
|
71 | t.deepEqual(mockConsole.getBuffer()[0].data, ["Bring the light!"], "Should concatenate string parts together"); | |||
|
|
72 | ||||
|
|
73 | mockConsole.clear(); | |||
|
|
74 | writer.writeLine("It's {0} o'clock, lets have some {1}!", { h: 5}, { title: "tee" }); | |||
|
|
75 | ||||
|
|
76 | t.deepEqual(mockConsole.getBuffer()[0].data, ["It's ", { h: 5}, " o'clock, lets have some ", { title: "tee" }, "!"], "Non string parts should be psassed as is"); | |||
|
|
77 | ||||
|
|
78 | mockConsole.clear(); | |||
|
|
79 | writer.writeLine("{0} or {1} to {2}", {i: 25}, 6, 4); | |||
|
|
80 | t.deepEqual(mockConsole.getBuffer()[0].data, [{i: 25}, " or 6 to 4"], "25 or 6 to 4"); | |||
|
|
81 | ||||
|
|
82 | mockConsole.clear(); | |||
|
|
83 | writer.writeLine("{0} or {1} to {2}! Let's have some {3}", 25, 6, 4, { product: "tee" } ); | |||
|
|
84 | t.deepEqual(mockConsole.getBuffer()[0].data, ["25 or 6 to 4! Let's have some ", { product: "tee" }], "Should handle many text chunks and object at the end"); | |||
|
|
85 | ||||
|
|
86 | }); | |||
| @@ -0,0 +1,89 | |||||
|
|
1 | import { TraceSource, DebugLevel } from "../log/TraceSource"; | |||
|
|
2 | import * as tape from "tape"; | |||
|
|
3 | import { TapeWriter, test } from "./TestTraits"; | |||
|
|
4 | import { MockConsole } from "../mock/MockConsole"; | |||
|
|
5 | import { ConsoleLogger } from "../log/writers/ConsoleLogger"; | |||
|
|
6 | import { ConsoleWriter } from "../log/ConsoleWriter"; | |||
|
|
7 | ||||
|
|
8 | const sourceId = "test/TraceSourceTests"; | |||
|
|
9 | ||||
|
|
10 | tape("trace message", t => { | |||
|
|
11 | const trace = TraceSource.get(sourceId); | |||
|
|
12 | ||||
|
|
13 | trace.level = DebugLevel; | |||
|
|
14 | ||||
|
|
15 | const h = trace.events.on(ev => { | |||
|
|
16 | t.equal(ev.source, trace, "sender should be the current trace source"); | |||
|
|
17 | t.equal(ev.level, DebugLevel, "level should be debug level"); | |||
|
|
18 | t.equal(ev.toString(), "Hello, World!", "The message should be a formatted message"); | |||
|
|
19 | ||||
|
|
20 | t.end(); | |||
|
|
21 | }); | |||
|
|
22 | ||||
|
|
23 | trace.debug("Hello, {0}!", "World"); | |||
|
|
24 | ||||
|
|
25 | h.destroy(); | |||
|
|
26 | }); | |||
|
|
27 | ||||
|
|
28 | tape("trace event", t => { | |||
|
|
29 | const trace = TraceSource.get(sourceId); | |||
|
|
30 | ||||
|
|
31 | trace.level = DebugLevel; | |||
|
|
32 | ||||
|
|
33 | const event = { | |||
|
|
34 | name: "custom event" | |||
|
|
35 | }; | |||
|
|
36 | ||||
|
|
37 | const h = trace.events.on(ev => { | |||
|
|
38 | t.equal(ev.source, trace, "sender should be the current trace source"); | |||
|
|
39 | t.equal(ev.level, DebugLevel, "level should be debug level"); | |||
|
|
40 | t.equal(ev.message, event, "The message should be the specified object"); | |||
|
|
41 | ||||
|
|
42 | t.end(); | |||
|
|
43 | }); | |||
|
|
44 | ||||
|
|
45 | trace.traceEvent(DebugLevel, event); | |||
|
|
46 | ||||
|
|
47 | h.destroy(); | |||
|
|
48 | }); | |||
|
|
49 | ||||
|
|
50 | tape("tape comment writer", async t => { | |||
|
|
51 | const writer = new TapeWriter(t); | |||
|
|
52 | ||||
|
|
53 | TraceSource.on(ts => { | |||
|
|
54 | writer.writeEvents(ts.events); | |||
|
|
55 | }); | |||
|
|
56 | ||||
|
|
57 | const trace = TraceSource.get(sourceId); | |||
|
|
58 | trace.level = DebugLevel; | |||
|
|
59 | ||||
|
|
60 | trace.log("Hello, {0}!", "World"); | |||
|
|
61 | trace.log("Multi\n line"); | |||
|
|
62 | trace.warn("Look at me!"); | |||
|
|
63 | trace.error("DIE!"); | |||
|
|
64 | ||||
|
|
65 | writer.destroy(); | |||
|
|
66 | ||||
|
|
67 | trace.log("You shouldn't see it!"); | |||
|
|
68 | ||||
|
|
69 | t.comment("DONE"); | |||
|
|
70 | ||||
|
|
71 | t.end(); | |||
|
|
72 | }); | |||
|
|
73 | ||||
|
|
74 | test("console writer", (t, trace) => { | |||
|
|
75 | ||||
|
|
76 | const mockConsole = new MockConsole(); | |||
|
|
77 | const writer = new ConsoleWriter(mockConsole); | |||
|
|
78 | const consoleLog = new ConsoleLogger(writer); | |||
|
|
79 | consoleLog.writeEvents(trace.events); | |||
|
|
80 | ||||
|
|
81 | trace.log("Hello, world!"); | |||
|
|
82 | t.deepEqual(mockConsole.getLine(0), ["console writer: Hello, world!"], "Log one string"); | |||
|
|
83 | ||||
|
|
84 | trace.log({ foo: "bar" }); | |||
|
|
85 | t.deepEqual(mockConsole.getLine(1), ["console writer: ", { foo: "bar" }], "Log an object"); | |||
|
|
86 | ||||
|
|
87 | trace.log("json: {0:json}", { foo: "bar" }); | |||
|
|
88 | t.deepEqual(mockConsole.getLine(2), ['console writer: json: {\n "foo": "bar"\n}'], "should convert to string substitutions with spec"); | |||
|
|
89 | }); | |||
| @@ -0,0 +1,13 | |||||
|
|
1 | import * as tape from "tape"; | |||
|
|
2 | import { Uuid } from "../Uuid"; | |||
|
|
3 | ||||
|
|
4 | tape("simple", t => { | |||
|
|
5 | t.pass("sync assert"); | |||
|
|
6 | setTimeout(() => { | |||
|
|
7 | t.pass("async assert"); | |||
|
|
8 | t.comment(Uuid()); | |||
|
|
9 | t.ok(Uuid() !== Uuid()); | |||
|
|
10 | // end should be called after the last assertion | |||
|
|
11 | t.end(); | |||
|
|
12 | }, 100); | |||
|
|
13 | }); | |||
| @@ -6,7 +6,6 plugins { | |||||
| 6 | // результатом будет версия '{num}.{distance}' где distance - расстояние от |
|
6 | // результатом будет версия '{num}.{distance}' где distance - расстояние от | |
| 7 | // текущей ревизии до ревизии с тэгом |
|
7 | // текущей ревизии до ревизии с тэгом | |
| 8 | def tagDistance = 0; |
|
8 | def tagDistance = 0; | |
| 9 | def isRelease = false; |
|
|||
| 10 |
|
9 | |||
| 11 | if (!version) { |
|
10 | if (!version) { | |
| 12 |
|
11 | |||
| @@ -35,25 +34,11 if (hasProperty('versionSuffix') && vers | |||||
| 35 | version += "-$versionSuffix" |
|
34 | version += "-$versionSuffix" | |
| 36 | } |
|
35 | } | |
| 37 |
|
36 | |||
| 38 | if(!npmName) |
|
37 | if(! jsmodule in ["amd", "commonjs", "system", "umd", "es6", "esnext"]) | |
| 39 | npmName = name; |
|
|||
| 40 |
|
||||
| 41 | if (hasProperty('release')) { |
|
|||
| 42 | isRelease = (release != 'false') |
|
|||
| 43 | } else { |
|
|||
| 44 | isRelease = (tagDistance == 0); |
|
|||
| 45 | } |
|
|||
| 46 |
|
||||
| 47 | if(!["amd", "commonjs", "system", "umd", "es6", "esnext"].contains(jsmodule)) |
|
|||
| 48 | throw new Exception("Invalid jsmodule specified: $jsmodule"); |
|
38 | throw new Exception("Invalid jsmodule specified: $jsmodule"); | |
| 49 |
if(!["es3", "es5", "es6", "es2016", "es2017", "esnext"] |
|
39 | if(! target in ["es3", "es5", "es6", "es2016", "es2017", "esnext"]) | |
| 50 | throw new Exception("Invalid target specified: $target") |
|
40 | throw new Exception("Invalid target specified: $target") | |
| 51 |
|
41 | |||
| 52 | def targetLibs = [ |
|
|||
| 53 | "es3" : ["es5", "es2015.promise", "es2015.symbol", "dom", "scripthost"], |
|
|||
| 54 | "es5" : ["es5", "es2015.promise", "es2015.symbol", "dom", "scripthost"] |
|
|||
| 55 | ]; |
|
|||
| 56 |
|
||||
| 57 | ext { |
|
42 | ext { | |
| 58 | packageName = "@$npmScope/$npmName" |
|
43 | packageName = "@$npmScope/$npmName" | |
| 59 | } |
|
44 | } | |
| @@ -61,25 +46,50 ext { | |||||
| 61 | def jstarget = target; |
|
46 | def jstarget = target; | |
| 62 |
|
47 | |||
| 63 | sources { |
|
48 | sources { | |
|
|
49 | amd { | |||
| 64 |
|
50 | |||
|
|
51 | } | |||
|
|
52 | ||||
|
|
53 | cjs { | |||
|
|
54 | ||||
|
|
55 | } | |||
| 65 | } |
|
56 | } | |
| 66 |
|
57 | |||
| 67 | typescript { |
|
58 | typescript { | |
| 68 | compilerOptions { |
|
59 | compilerOptions { | |
| 69 |
lib = |
|
60 | lib = [target, "dom", "scripthost"] | |
|
|
61 | if (jstarget in ["es5", "es3"]) | |||
|
|
62 | lib += ["es2015.promise"] | |||
|
|
63 | ||||
| 70 | target = jstarget |
|
64 | target = jstarget | |
| 71 | module = jsmodule |
|
65 | module = jsmodule | |
| 72 | types = [] |
|
66 | types = [] | |
|
|
67 | declaration = true | |||
|
|
68 | listFiles = true | |||
|
|
69 | ||||
| 73 | } |
|
70 | } | |
| 74 | tsLintCmd = "tslint" |
|
71 | tsLintCmd = "tslint" | |
| 75 | esLintCmd = "eslint" |
|
72 | esLintCmd = "eslint" | |
| 76 | npmCmd = "npm" |
|
73 | npmCmd = "npm" | |
| 77 | } |
|
74 | } | |
| 78 |
|
75 | |||
|
|
76 | configureTsMain { | |||
|
|
77 | compilerOptions { | |||
|
|
78 | if (jstarget in ["es5", "es3"]) | |||
|
|
79 | lib += ["es2015.symbol", "es2015.iterable"] | |||
|
|
80 | } | |||
|
|
81 | } | |||
|
|
82 | ||||
|
|
83 | configureTsTest { | |||
|
|
84 | compilerOptions { | |||
|
|
85 | types += [ "node" ] | |||
|
|
86 | } | |||
|
|
87 | } | |||
|
|
88 | ||||
| 79 | task printVersion { |
|
89 | task printVersion { | |
| 80 | doLast { |
|
90 | doLast { | |
| 81 | println "version: $version"; |
|
91 | println "version: $version"; | |
| 82 |
println " |
|
92 | println "tagDistance: $tagDistance"; | |
| 83 | println "packageName: $packageName"; |
|
93 | println "packageName: $packageName"; | |
| 84 | println "bundle: ${npmPack.outputs.files.join(',')}"; |
|
94 | println "bundle: ${npmPack.outputs.files.join(',')}"; | |
| 85 | println "target: $jstarget"; |
|
95 | println "target: $jstarget"; | |
| @@ -95,11 +105,6 task clean { | |||||
| 95 |
|
105 | |||
| 96 | npmPackMeta { |
|
106 | npmPackMeta { | |
| 97 | meta { |
|
107 | meta { | |
| 98 |
name = |
|
108 | name = packageName | |
| 99 | } |
|
109 | } | |
| 100 | } |
|
110 | } | |
| 101 |
|
||||
| 102 | task markRelease(type: Exec) { |
|
|||
| 103 | onlyIf { tagDistance > 1 } |
|
|||
| 104 | commandLine "hg", "tag", "v$version"; |
|
|||
| 105 | } No newline at end of file |
|
|||
| @@ -5,9 +5,9 | |||||
| 5 | "requires": true, |
|
5 | "requires": true, | |
| 6 | "dependencies": { |
|
6 | "dependencies": { | |
| 7 | "@types/node": { |
|
7 | "@types/node": { | |
| 8 |
"version": " |
|
8 | "version": "8.10.55", | |
| 9 |
"resolved": "https://registry.npmjs.org/@types/node/-/node- |
|
9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.55.tgz", | |
| 10 | "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", |
|
10 | "integrity": "sha512-iZeh1EgupfmAAOASk580R1SL5lWF3CsBVgVH0395qyNF8fhO16xy1UwAav2PdGxIIsYRn7RzJgMGjdsvam6YYg==", | |
| 11 | "dev": true |
|
11 | "dev": true | |
| 12 | }, |
|
12 | }, | |
| 13 | "@types/requirejs": { |
|
13 | "@types/requirejs": { | |
| @@ -21,7 +21,7 | |||||
| 21 | "tslib": "latest" |
|
21 | "tslib": "latest" | |
| 22 | }, |
|
22 | }, | |
| 23 | "devDependencies": { |
|
23 | "devDependencies": { | |
| 24 |
"@types/node": " |
|
24 | "@types/node": "^8.0.0", | |
| 25 | "@types/requirejs": "latest", |
|
25 | "@types/requirejs": "latest", | |
| 26 | "@types/tape": "latest", |
|
26 | "@types/tape": "latest", | |
| 27 | "dojo": "^1.10.0", |
|
27 | "dojo": "^1.10.0", | |
| @@ -1,5 +1,5 | |||||
| 1 |
import { IActivatable, ICancellation, IActivationController } from " |
|
1 | import { IActivatable, ICancellation, IActivationController } from "../interfaces"; | |
| 2 |
import { Cancellation } from " |
|
2 | import { Cancellation } from "../Cancellation"; | |
| 3 |
|
3 | |||
| 4 | export class MockActivationController implements IActivationController { |
|
4 | export class MockActivationController implements IActivationController { | |
| 5 |
|
5 | |||
| @@ -1,4 +1,4 | |||||
| 1 |
import {NullConsole} from " |
|
1 | import {NullConsole} from "../log/NullConsole"; | |
| 2 |
|
2 | |||
| 3 | interface ConsoleLineData { |
|
3 | interface ConsoleLineData { | |
| 4 | level: string; |
|
4 | level: string; | |
| @@ -1,5 +1,5 | |||||
| 1 |
import { AsyncComponent } from " |
|
1 | import { AsyncComponent } from "../components/AsyncComponent"; | |
| 2 |
import { ActivatableMixin } from " |
|
2 | import { ActivatableMixin } from "../components/ActivatableMixin"; | |
| 3 |
|
3 | |||
| 4 | export class SimpleActivatable extends ActivatableMixin(AsyncComponent) { |
|
4 | export class SimpleActivatable extends ActivatableMixin(AsyncComponent) { | |
| 5 |
|
5 | |||
| @@ -3,11 +3,10 | |||||
| 3 | "compilerOptions": { |
|
3 | "compilerOptions": { | |
| 4 | "rootDir": "ts", |
|
4 | "rootDir": "ts", | |
| 5 | "baseUrl": ".", |
|
5 | "baseUrl": ".", | |
| 6 |
" |
|
6 | "rootDirs": [ | |
| 7 | "@implab/core/*": [ |
|
7 | "ts", | |
| 8 |
|
|
8 | "../main/ts" | |
| 9 |
|
|
9 | ] | |
| 10 | } |
|
|||
| 11 | }, |
|
10 | }, | |
| 12 | "include" : [ |
|
11 | "include" : [ | |
| 13 | "ts/**/*.ts" |
|
12 | "ts/**/*.ts" | |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now
