|
| 1 | +import { exec } from "child_process"; |
| 2 | + |
1 | 3 | import { Test } from "@rapidjs.org/testing"; |
2 | 4 |
|
3 | 5 | import { TColor } from "../../common.types"; |
4 | 6 |
|
5 | | -interface IObject { |
6 | | - [key: string]: string | number | boolean | IObject; |
| 7 | +interface IOutput { |
| 8 | + stdout: string; |
| 9 | + stderr: string; |
| 10 | +} |
| 11 | + |
| 12 | +interface TConfiguration { |
| 13 | + commonBinary?: string; |
7 | 14 | } |
8 | 15 |
|
9 | | -export class CLITest extends Test<IObject> { |
| 16 | +export class CLITest extends Test<IOutput> { |
10 | 17 | public static readonly suiteTitle: string = "CLI"; |
11 | 18 | public static readonly suiteColor: TColor = [73, 220, 177]; // 108, 55, 55 |
12 | 19 |
|
13 | | - constructor(title: string) { |
14 | | - super(title); |
| 20 | + private static configuration: TConfiguration = {}; |
| 21 | + |
| 22 | + public static configure(configuration: TConfiguration) { |
| 23 | + CLITest.configuration = { |
| 24 | + ...CLITest.configuration, |
| 25 | + ...configuration |
| 26 | + }; |
15 | 27 | } |
16 | 28 |
|
17 | | - protected evalActualExpression(obj: IObject): Promise<IObject> { |
18 | | - return new Promise((resolve) => { |
19 | | - resolve( |
20 | | - Object.fromEntries( |
21 | | - Object.entries(obj).map((entry: [string, unknown]) => [entry[0].toLowerCase(), entry[1]]) |
22 | | - ) as IObject |
23 | | - ); |
| 29 | + private normalizeOutput(output: Partial<IOutput>): IOutput { |
| 30 | + const normalizeStdValue = (value: string) => { |
| 31 | + return (value ?? "") |
| 32 | + .replace(/(\n|\r)+/g, "\n") |
| 33 | + .replace(/(\t| )+/g, " ") |
| 34 | + .trim() |
| 35 | + ?? null; |
| 36 | + } |
| 37 | + return { |
| 38 | + stdout: normalizeStdValue(output.stdout), |
| 39 | + stderr: normalizeStdValue(output.stderr) |
| 40 | + }; |
| 41 | + } |
| 42 | + |
| 43 | + protected evalActualExpression(args: string[]): Promise<IOutput>; |
| 44 | + protected evalActualExpression(binary: string, args?: string[]): Promise<IOutput>; |
| 45 | + protected evalActualExpression(binaryOrArgs: string|string[], args: string[] = []): Promise<IOutput> { |
| 46 | + // TODO: Pipe chain abstraction (?) |
| 47 | + const effectiveBinary: string = (!binaryOrArgs || Array.isArray(binaryOrArgs)) |
| 48 | + ? CLITest.configuration.commonBinary |
| 49 | + : binaryOrArgs; |
| 50 | + if(!effectiveBinary) throw new SyntaxError("Missing binary to execute"); |
| 51 | + |
| 52 | + const effectiveArgs: string[] = (args ?? [ binaryOrArgs ].flat()) ?? []; |
| 53 | + |
| 54 | + return new Promise((resolve, reject) => { |
| 55 | + exec([ effectiveBinary, effectiveArgs ].flat().join(" "), (err: Error, stdout: string, stderr: string) => { |
| 56 | + if(err && !stderr) { |
| 57 | + reject(err); |
| 58 | + |
| 59 | + return; |
| 60 | + } |
| 61 | + |
| 62 | + resolve(this.normalizeOutput({ |
| 63 | + stdout, stderr |
| 64 | + })); |
| 65 | + }); |
24 | 66 | }); |
25 | 67 | } |
26 | 68 |
|
27 | | - protected isEqual(actual: IObject, expected: IObject): boolean { |
28 | | - return !Object.keys(this.filterComparedValues(actual, expected).actual).length; |
| 69 | + protected evalExpectedExpression(expectedOutput: Partial<IOutput>|string): IOutput { |
| 70 | + return this.normalizeOutput( |
| 71 | + (typeof(expectedOutput) === "string") |
| 72 | + ? { |
| 73 | + stdout: expectedOutput |
| 74 | + } |
| 75 | + : { |
| 76 | + stdout: [ expectedOutput.stdout ].flat().join("\n"), |
| 77 | + stderr: [ expectedOutput.stderr ].flat().join("\n") |
| 78 | + } |
| 79 | + ); |
29 | 80 | } |
30 | 81 |
|
31 | | - protected filterComparedValues(actual: IObject, expected: IObject) { |
32 | | - return { |
33 | | - actual: actual, |
34 | | - expected: expected |
| 82 | + protected getDifference(actual: IOutput, expected: IOutput) { |
| 83 | + const filterObj = (sourceObj: IOutput, targetObj: IOutput) => { |
| 84 | + return { |
| 85 | + ...(sourceObj.stdout !== targetObj.stdout) |
| 86 | + ? { stdout: sourceObj.stdout } |
| 87 | + : {}, |
| 88 | + ...(sourceObj.stderr !== targetObj.stderr) |
| 89 | + ? { stderr: sourceObj.stderr } |
| 90 | + : {}, |
| 91 | + } |
35 | 92 | }; |
| 93 | + return { |
| 94 | + actual: filterObj(actual, expected), |
| 95 | + expected: filterObj(expected, actual) |
| 96 | + } |
36 | 97 | } |
37 | 98 | } |
0 commit comments