Skip to content

Commit 81e4343

Browse files
committed
Add style abstraction (#24)
1 parent 88565f7 commit 81e4343

8 files changed

Lines changed: 241 additions & 164 deletions

File tree

src/framework/Framework.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {HybridScheduler, Scheduler} from './Scheduler';
33
import {TestScenario} from './scenario/TestScenario';
44

55
import {TestbedSpecification} from '../testbeds/TestbedSpecification';
6-
import {Reporter, SuiteResults} from './Reporter';
6+
import {Reporter, SuiteResults} from '../reporter/Reporter';
7+
8+
import {StyleType} from '../reporter';
9+
import {styling} from '../reporter/Style';
710

811
export interface Suite {
912

@@ -20,12 +23,6 @@ export interface TesteeOptions {
2023
connectionTimout?: number;
2124
}
2225

23-
export enum OutputStyle {
24-
silent, // TODO
25-
plain,
26-
github
27-
}
28-
2926
export class Suite {
3027
public title: string;
3128
public scenarios: TestScenario[] = [];
@@ -61,11 +58,11 @@ export class Framework {
6158

6259
public runs: number = 1;
6360

64-
private outputStyle: OutputStyle = OutputStyle.plain;
61+
private outputStyle: StyleType = StyleType.plain;
6562

6663
private scheduled: Suite[] = [];
6764

68-
public readonly reporter: Reporter = new Reporter();
65+
public readonly reporter: Reporter = new Reporter(styling(this.outputStyle));
6966

7067
private constructor() {
7168
}
@@ -78,11 +75,11 @@ export class Framework {
7875
return this.scheduled;
7976
}
8077

81-
public style(style: OutputStyle): void {
78+
public style(style: StyleType): void {
8279
this.outputStyle = style;
8380
}
8481

85-
public styling(): OutputStyle {
82+
public styling(): StyleType {
8683
return this.outputStyle;
8784
}
8885

src/framework/Testee.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {TestScenario} from './scenario/TestScenario';
99
import {OutofPlaceSpecification, PlatformType, TestbedSpecification} from '../testbeds/TestbedSpecification';
1010
import {CompileOutput, CompilerFactory} from '../manage/Compiler';
1111
import {WABT} from '../util/env';
12-
import {Completion, expect, Result, ScenarioResult, SuiteResults} from './Reporter';
12+
import {Completion, expect, ScenarioResult, SuiteResults} from '../reporter/Reporter';
1313
import {WASM} from '../sourcemap/Wasm';
1414
import {DummyProxy} from '../testbeds/Emulator';
15+
import {Result} from '../reporter/Result';
1516

1617
export function timeout<T>(label: string, time: number, promise: Promise<T>): Promise<T> {
1718
if (time === 0) {

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ export * from './framework/scenario/Step';
1515
export * from './framework/scenario/Invoker';
1616
export * from './testbeds/TestbedSpecification';
1717
export * from './debug/Breakpoint';
18+
export * from './reporter/index';
1819

1920
export const latch = Framework.getImplementation();
Lines changed: 31 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import {OutputStyle, Suite} from './Framework';
2-
import {Behaviour, Description, Step} from './scenario/Step';
3-
import {getValue, Testee} from './Testee';
4-
import {blue, bold, green, red, yellow, reset, inverse, grey} from 'ansi-colors';
5-
import {Archiver} from './Archiver';
6-
import {TestScenario} from './scenario/TestScenario';
1+
import {Suite} from '../framework/Framework';
2+
import {Step} from '../framework/scenario/Step';
3+
import {getValue, Testee} from '../framework/Testee';
4+
import {blue, bold, green, inverse, red, yellow} from 'ansi-colors';
5+
import {Archiver} from '../framework/Archiver';
6+
import {TestScenario} from '../framework/scenario/TestScenario';
77
import {version} from '../../package.json';
8+
import {indent} from '../util/printing';
9+
import {Result} from './Result';
10+
import {Verbosity} from './index';
11+
import {Style} from './Style';
812

913
export enum Completion {
1014
uncommenced = 'not started', // test hasn't started
@@ -15,20 +19,6 @@ export enum Completion {
1519
skipped = 'skipped' // test has failing dependencies
1620
}
1721

18-
export enum Verbosity {
19-
none,
20-
minimal,
21-
short,
22-
normal,
23-
more,
24-
all,
25-
debug
26-
}
27-
28-
function indent(level: number, size: number = 2): string {
29-
return ' '.repeat(level * size);
30-
}
31-
3222
export function expect(step: Step, actual: Object | void, previous?: Object): Result {
3323
const result: Result = new Result(step.title, '');
3424
result.completion = Completion.succeeded;
@@ -133,153 +123,49 @@ export class ScenarioResult {
133123
}
134124
}
135125

136-
export class Result {
137-
public completion: Completion; // completion status of the step
138-
public name: string; // name of the step
139-
public description: string;
140-
141-
constructor(name: string, description: string, completion?: Completion) {
142-
this.name = name;
143-
this.description = description;
144-
this.completion = completion ?? Completion.uncommenced;
145-
}
146-
147-
report(level: number) {
148-
console.log(reset(`${indent(level)}${this}`));
149-
}
150-
151-
toString(): string {
152-
switch (this.completion) {
153-
case Completion.succeeded:
154-
return `${bold(inverse(green(' PASS ')))} ${this.name}`;
155-
case Completion.uncommenced:
156-
return `${bold(inverse(yellow(' SKIP ')))} ${this.name}`;
157-
case Completion.error:
158-
case Completion.failed:
159-
default:
160-
return `${bold(inverse(red(' FAIL ')))} ${this.name}\n ${red(this.completion)}${red(this.description)}`;
161-
162-
}
163-
}
164-
165-
error(description: string) {
166-
this.completion = Completion.error;
167-
this.description = description;
168-
}
169-
170-
public expectPrimitive<T>(actual: T, expected: T): void {
171-
// this.completion = deepEqual(actual, expected) ? Completion.succeeded : Completion.failed;
172-
if (deepEqual(actual, expected)) {
173-
this.completion = Completion.succeeded;
174-
} else {
175-
this.completion = Completion.failed;
176-
this.description = `Expected ${bold(`${expected}`)} got ${bold(`${actual}`)}`;
177-
}
178-
}
179-
180-
public expectDescription<T>(actual: T, value: Description): void {
181-
if ((value === Description.defined && actual !== undefined) ||
182-
value === Description.notDefined && actual === undefined) {
183-
this.completion = Completion.succeeded;
184-
} else {
185-
this.completion = Completion.failed;
186-
this.description = value === Description.defined ? 'Should exist' : 'Unexpected field';
187-
}
188-
}
189-
190-
public expectComparison<T>(state: Object | void, actual: T, comparator: (state: Object, value: T) => boolean, message?: string): void {
191-
if (state === undefined) {
192-
this.completion = Completion.failed;
193-
this.description = `Got unexpected ${state}`;
194-
return;
195-
}
196-
197-
if (comparator(state, actual)) {
198-
this.completion = Completion.succeeded;
199-
} else {
200-
this.completion = Completion.failed;
201-
this.description = 'custom comparator failed';
202-
}
203-
}
204-
205-
public expectBehaviour(actual: any, previous: any, behaviour: Behaviour): void {
206-
switch (behaviour) {
207-
case Behaviour.unchanged:
208-
if (deepEqual(actual, previous)) {
209-
this.completion = Completion.succeeded;
210-
} else {
211-
this.completion = Completion.failed;
212-
this.description = `Expected ${actual} to equal ${previous}`
213-
}
214-
break;
215-
case Behaviour.changed:
216-
if (!deepEqual(actual, previous)) {
217-
this.completion = Completion.succeeded;
218-
} else {
219-
this.completion = Completion.failed;
220-
this.description = `Expected ${actual} to be different from ${previous}`
221-
}
222-
break;
223-
case Behaviour.increased:
224-
if (actual > previous) {
225-
this.completion = Completion.succeeded;
226-
} else {
227-
this.completion = Completion.failed;
228-
this.description = `Expected ${actual} to be greater than ${previous}`
229-
}
230-
break;
231-
case Behaviour.decreased:
232-
if (actual < previous) {
233-
this.completion = Completion.succeeded;
234-
} else {
235-
this.completion = Completion.failed;
236-
this.description = `Expected ${actual} to be less than ${previous}`
237-
}
238-
break;
239-
}
240-
}
241-
}
242-
243126
// const r Result = expect(e: Expected) <-- replaces the function in Testee todo
244127

245128
export class Reporter {
246129
private output: string = '';
247130

248131
private indentationLevel: number = 2;
249132

133+
private style: Style;
134+
250135
private suites: SuiteResults[] = [];
251136

252137
private archiver: Archiver;
253138

254139
private verbosity: Verbosity = Verbosity.short;
255140

256-
constructor() {
141+
constructor(style: Style) {
142+
this.style = style;
257143
this.archiver = new Archiver(`${process.env.TESTFILE?.replace('.asserts.wast', '.wast') ?? 'suite'}.${Date.now()}.log`);
258144
this.archiver.set('date', new Date(Date.now()).toISOString());
259145
}
260146

261147
private indent(override?: number) {
262-
return indent(override ?? this.indentationLevel);
148+
return indent(override ?? this.indentationLevel, this.style.indentation);
263149
}
264150

265151
general() {
266-
console.log(this.indent() + blue(bold('● latch')) + bold(' General information'));
152+
console.log(this.indent() + this.style.colors.highlight(this.style.bullet) + this.style.colors.highlight('latch') + this.style.emph(' General information'));
267153
// console.log(blue(`${this.indent()}===================`));
268-
console.log(this.indent() + ' '.repeat(2) + bold('version') + ' '.repeat(5) + version);
269-
console.log(this.indent() + ' '.repeat(2) + bold('archive') + ' '.repeat(5) + this.archiver.archive);
154+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('version') + ' '.repeat(5) + version);
155+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('archive') + ' '.repeat(5) + this.archiver.archive);
270156
console.log();
271157
}
272158

273159
report(suiteResult: SuiteResults) {
274160
this.suites.push(suiteResult);
275-
const status = (suiteResult.error ? bold(inverse(red(' ERROR '))) :
276-
(suiteResult.passing() ? bold(inverse(green(' PASSED '))) : bold(inverse(red(' FAIL ')))));
277-
console.log(this.indent() + blue(bold('● suite')) + ` ${bold(suiteResult.title())}${(this.verbosity === Verbosity.minimal) ? ' ' + status : ''}`);
161+
const status = (suiteResult.error ? this.style.colors.error(this.style.labels.error) :
162+
(suiteResult.passing() ? this.style.colors.success(this.style.labels.suiteSuccess) : this.style.colors.failure(this.style.labels.failure)));
163+
console.log(this.indent() + this.style.colors.highlight(this.style.bullet) + this.style.colors.highlight('suite') + ` ${this.style.emph(suiteResult.title())}${(this.verbosity === Verbosity.minimal) ? ' ' + status : ''}`);
278164
if (this.verbosity > Verbosity.minimal) {
279-
console.log(this.indent() + ' '.repeat(2) + bold('testbed') + ' '.repeat(5) + suiteResult.testee.name);
280-
console.log(this.indent() + ' '.repeat(2) + bold('scenarios') + ' '.repeat(3) + suiteResult.scenarios.length);
281-
console.log(this.indent() + ' '.repeat(2) + bold('actions') + ' '.repeat(5) + suiteResult.suite.scenarios.flatMap((scenario) => scenario.steps ?? []).flat().length); //.reduce((total, count) => total + count));
282-
console.log(this.indent() + ' '.repeat(2) + bold('status') + ' '.repeat(6) + status);
165+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('testbed') + ' '.repeat(5) + suiteResult.testee.name);
166+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('scenarios') + ' '.repeat(3) + suiteResult.scenarios.length);
167+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('actions') + ' '.repeat(5) + suiteResult.suite.scenarios.flatMap((scenario) => scenario.steps ?? []).flat().length); //.reduce((total, count) => total + count));
168+
console.log(this.indent() + ' '.repeat(2) + this.style.emph('status') + ' '.repeat(6) + status);
283169
}
284170
console.log();
285171
if (this.verbosity >= Verbosity.normal) {
@@ -310,7 +196,7 @@ export class Reporter {
310196
this.archiver.set('skipped scenarios', skipped);
311197
this.archiver.set('failed scenarios', failing);
312198

313-
console.log(this.indent() + blue(bold('● results')) + bold(' Overview'));
199+
console.log(this.indent() + this.style.colors.highlight(this.style.bullet) + this.style.colors.highlight('results') + this.style.emph(' Overview'));
314200
console.log();
315201
this.indentationLevel += 1;
316202

@@ -331,22 +217,19 @@ export class Reporter {
331217

332218
const len: number = 12;
333219
const pss = [`${sc} passing`, `${passing} passing`, `${psa} passing`]
334-
console.log(this.indent() + bold('Test suites:') + ' '.repeat(len - pss[0].length) + bold((sc === tl ? green : red)(pss[0])) + `, ${tl} total` + bold(` (${time.toFixed(0)}ms)`));
220+
console.log(this.indent() + this.style.emph('Test suites:') + ' '.repeat(len - pss[0].length) + this.style.emph((sc === tl ? green : red)(pss[0])) + `, ${tl} total` + this.style.emph(` (${time.toFixed(0)}ms)`));
335221
if (this.verbosity > Verbosity.minimal) {
336-
console.log(this.indent() + bold('Scenarios:') +
337-
' '.repeat(2 + len - pss[1].length) + bold((passing === scs.length ? green : red)(pss[1])) +
338-
(skipped > 0 ? ', ' + bold(yellow(`${skipped} skipped`)) : '') + `, ${scs.length} total`);
339-
console.log(this.indent() + bold('Actions:') + ' '.repeat(4 + len - pss[2].length) + bold((passing === scs.length ? green : red)(pss[2])) + (timeouts > 0 ? `, ${timeouts} timeouts` : '') + `, ${total} total`);
222+
console.log(this.indent() + this.style.emph('Scenarios:') +
223+
' '.repeat(2 + len - pss[1].length) + this.style.emph((passing === scs.length ? green : red)(pss[1])) +
224+
(skipped > 0 ? ', ' + this.style.emph(yellow(`${skipped} skipped`)) : '') + `, ${scs.length} total`);
225+
console.log(this.indent() + this.style.emph('Actions:') + ' '.repeat(4 + len - pss[2].length) + this.style.emph((passing === scs.length ? green : red)(pss[2])) + (timeouts > 0 ? `, ${timeouts} timeouts` : '') + `, ${total} total`);
340226
}
341227
this.indentationLevel -= 1;
342228

343229
console.log();
344230
this.archiver.write();
345231
}
346232

347-
style(style: OutputStyle) {
348-
}
349-
350233
info(text: string) {
351234
this.output += `info: ${text}\n`;
352235
}
@@ -367,7 +250,3 @@ export class Reporter {
367250
this.output += ` ${result.toString()}\n`;
368251
}
369252
}
370-
371-
function deepEqual(a: any, b: any): boolean {
372-
return a === b || (isNaN(a) && isNaN(b));
373-
}

0 commit comments

Comments
 (0)