8000 added asserts same as in WORKSHEETS Data Studio · jspython-dev/jspython-cli@1e4e86c · GitHub
[go: up one dir, main page]

Skip to content

Commit 1e4e86c

Browse files
committed
added asserts same as in WORKSHEETS Data Studio
1 parent f9ef058 commit 1e4e86c

File tree

5 files changed

+254
-56
lines changed

5 files changed

+254
-56
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jspython-cli",
3-
"version": "2.1.11",
3+
"version": "2.1.13",
44
"description": "CLI for jspython. Allows you to run jspython (*.jspy) files",
55
"main": "./lib/public-api.js",
66
"bin": {
@@ -31,7 +31,7 @@
3131
"homepage": "https://github.com/jspython-dev/jspython-cli#readme",
3232
"dependencies": {
3333
"arg": "^5.0.1",
34-
"jspython-interpreter": "^2.1.9"
34+
"jspython-interpreter": "^2.1.10"
3535
},
3636
"devDependencies": {
3737
"rollup": "^2.70.1",

src/assert.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
2+
export class Assert {
3+
#chainedCheckCount: number = 1;
4+
public status: boolean = true;
5+
public message?: string;
6+
readonly #logFn: (success: boolean, msg: string) => void;
7+
8+
constructor(
9+
public assert: string,
10+
private dataContext: object,
11+
logFn: (success: boolean, msg: string) => void
12+
) {
13+
this.#logFn = logFn;
14+
}
15+
16+
equal(expected: unknown, received: unknown): Assert {
17+
return this.assertFunction(
18+
expected,
19+
received,
20+
(e, r) => {
21+
if (typeof e === 'object') {
22+
// deepClone
23+
return JSON.stringify(e) !== JSON.stringify(r);
24+
}
25+
26+
return e === r;
27+
},
28+
(e, r) => `Expected '${e}', received '${r}'`
29+
);
30+
}
31+
32+
notEqual(expected: unknown, received: unknown): Assert {
33+
return this.assertFunction(
34+
expected,
35+
received,
36+
(e, r) => {
37+
if (typeof e === 'object') {
38+
// deepClone
39+
return JSON.stringify(e) !== JSON.stringify(r);
40+
}
41+
42+
return e !== r;
43+
},
44+
(e, r) => `Expected '${e}' is the same as received '${r}'`
45+
);
46+
}
47+
48+
isTrue(value: unknown): Assert {
49+
return this.assertFunction(
50+
value,
51+
null,
52+
(e, r) => e === true,
53+
(e, r) => `Value '${e}' is not true`
54+
);
55+
}
56+
57+
isFalse(value: unknown): Assert {
58+
return this.assertFunction(
59+
value,
60+
null,
61+
(e, r) => e === false,
62+
(e, r) => `Value '${e}' is not false`
63+
);
64+
}
65+
66+
greaterThan(value1: number | Date, value2: number | Date): Assert {
67+
return this.assertFunction(
68+
value1,
69+
value2,
70+
(e: any, r: any) => e > r,
71+
(e, r) => `${e}' is not greater than ${r}`
72+
);
73+
}
74+
75+
greaterOrEqualThan(value1: number | Date, value2: number | Date): Assert {
76+
return this.assertFunction(
77+
value1,
78+
value2,
79+
(e: any, r: any) => e >= r,
80+
(e, r) => `${e}' is not greater (or equal) than ${r}`
81+
);
82+
}
83+
84+
inRange(value: number | Date, min: number | Date, max: number | Date): Assert {
85+
return this.between(value, min, max);
86+
}
87+
88+
between(value: number | Date, min: number | Date, max: number | Date): Assert {
89+
return this.assertFunction(
90+
value,
91+
{ min, max },
92+
(v: any, r: any) => v >= r.min && v <= r.max,
93+
(v, r: any) => `${v}' is NOT in range of ${r.min} and ${r.max}`
94+
);
95+
}
96+
97+
lessThan(value1: number | Date, value2: number | Date): Assert {
98+
return this.assertFunction(
99+
value1,
100+
value2,
101+
(e: any, r: any) => e < r,
102+
(e, r) => `${e}' is not lesser than ${r}`
103+
);
104+
}
105+
106+
lessOrEqualThan(value1: number | Date, value2: number | Date): Assert {
107+
return this.assertFunction(
108+
value1,
109+
value2,
110+
(e: any, r: any) => e <= r,
111+
(e, r) => `${e}' is not lesser (or equal) than ${r}`
112+
);
113+
}
114+
115+
private assertFunction(
116+
expected: unknown,
117+
received: unknown,
118+
assertExpressionFn: (e: unknown, r: unknown) => boolean,
119+
errorMessageFn: (e: unknown, r: unknown) => string
120+
): Assert {
121+
// resolve function, if any
122+
if (typeof expected === 'function') {
123+
expected = expected(this.dataContext);
124+
}
125+
if (typeof received === 'function') {
126+
received = received(this.dataContext);
127+
}
128+
129+
if (!assertExpressionFn(expected, received)) {
130+
this.status = false;
131+
this.message = `[${this.#chainedCheckCount}] - ${errorMessageFn(expected, received)}`;
132+
this.#logFn(false, this.message);
133+
return this;
134+
}
135+
this.#logFn(true, '');
136+
this.#chainedCheckCount++;
137+
return this;
138+
}
139+
}

src/cli.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import arg from 'arg';
22
import fs from 'fs';
33
import { Interpreter } from 'jspython-interpreter';
4-
import { jsPythonForNode } from './jspython-node';
4+
import {
5+
AssertInfo,
6+
initialScope,
7+
jsPythonForNode
8+
} from './jspython-node';
59
import { InterpreterOptions } from './types';
610
import { trimChar } from './utils';
711
var util = require('util');
@@ -20,10 +24,7 @@ process
2024
});
2125

2226
const options = getOptionsFromArguments(process.argv);
23-
const initialScope: Record<string, any> = {
24-
session: {},
25-
params: options.params
26-
};
27+
const jspyContext: Record<string, any> = { ...initialScope, ...{ params: options.params } };
2728

2829
const interpreter: Interpreter = jsPythonForNode(options) as Int 38BA erpreter;
2930

@@ -129,11 +130,17 @@ async function main() {
129130
try {
130131
const res = await interpreter.evaluate(
131132
scripts,
132-
initialScope,
133+
jspyContext,
133134
options.entryFunction || undefined,
134135
options.file
135136< D306 /td>
);
136137

138+
if (!!jspyContext.asserts?.length) {
139+
const asserts = (jspyContext.asserts || []) as AssertInfo[];
140+
console.log(` > assert success : ${asserts.filter(a => a.success).length}`);
141+
console.log(` > assert failed : ${asserts.filter(a => !a.success).length}`);
142+
}
143+
137144
if (!!res || res === 0) {
138145
console.log('>', res);
139146
}

src/jspython-node.ts

Lines changed: 99 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,113 @@
11
import fs from 'fs';
22
import { jsPython, Interpreter, PackageLoader } from 'jspython-interpreter';
3+
import { Assert } from './assert';
34
import { InterpreterOptions } from './types';
45
import { trimChar } from './utils';
56

67
const rootFolder = process.cwd().split('\\').join('/');
7-
const initialScope: any = {};
8+
export const initialScope: any = {
9+
asserts: [] as AssertInfo[]
10+
};
811

912
type NodeJsInterpreter = Interpreter & { evaluateFile: (fileName: string) => Promise<any> };
13+
export type AssertInfo = { success: boolean; name: string; description?: string };
14+
type LogInfo = { level: 'info' | 'fail' | 'success'; message: string; time: Date; logId?: string };
1015

11-
const context: any = {
12-
asserts: [],
16+
const context: {
17+
params: any;
18+
} = {
1319
params: {}
1420
};
1521

16-
initialScope.assert = (condition: boolean, name?: string, description?: string) =>
17-
context.asserts.push({ condition, name, description });
18-
initialScope.showAsserts = () => console.table(context.asserts);
22+
function logFn(msg: LogInfo): void {
23+
const level = msg.level === 'success' ? msg.level : msg.level + ' ';
24+
25+
console.log(`| ${msg.time.toTimeString().slice(0, 8)} | ${level} | ${msg.message}`);
26+
}
27+
28+
function assert(name: string, dataContext?: boolean | any): Assert | void {
29+
// an original case when
30+
if (typeof dataContext === 'boolean') {
31+
logFn({
32+
level: dataContext ? 'success' : 'fail',
33+
message: name || '',
34+
time: new Date()
35+
});
36+
initialScope.asserts.push({ success: !!dataContext, name });
37+
return;
38+
}
39+
40+
function assertCallback(success: boolean, message: string) {
41+
logFn({
42+
logId: name,
43+
level: success ? 'success' : 'fail',
44+
message: `${name} ${message ? ':' : ''} ${message || ''}`,
45+
time: new Date()
46+
});
47+
48+
const existingAssert = initialScope.asserts?.find((a: AssertInfo) => a.name === name);
49+
if (existingAssert) {
50+
// only if condition it is not fail yet
51+
if (!!existingAssert.success) {
52+
existingAssert.success = !!success;
53+
existingAssert.description = message;
54+
}
55+
} else {
56+
initialScope.asserts.push({ success: !!success, name: name, description: message });
57+
}
58+
}
59+
60+
return new Assert(name, dataContext, assertCallback);
61+
}
62+
63+
function getScript(fileName: string): string {
64+
if (!fs.existsSync(fileName)) {
65+
throw Error(`File not found`);
66+
}
67+
68+
const scripts = fs.readFileSync(fileName, 'utf8');
69+
return scripts;
70+
}
71+
72+
async function initialize(baseSource: string) {
73+
// process app.js (if exists)
74+
// - run _init
75+
// - delete _ init
76+
// - run _initAsync
77+
// - delete _initAsync
78+
// - load content into 'app'
79+
80+
let appJsPath = `${rootFolder}/${baseSource}app.js`;
81+
console.log({ rootFolder, baseSource });
82+
if (!fs.existsSync(appJsPath)) {
83+
appJsPath = `${rootFolder}/src/app.js`;
84+
}
85+
86+
if (fs.existsSync(appJsPath)) {
87+
const app = require(appJsPath);
88+
89+
if (typeof app._init == 'function') {
90+
app._init();
91+
delete app._init;
92+
}
93+
94+
if (typeof app._initAsync == 'function') {
95+
await app._initAsync();
96+
delete app._initAsync;
97+
}
98+
99+
Object.assign(initialScope, app);
100+
}
101+
}
102+
103+
initialScope.assert = (name: string, dataContext: any) => assert(name, dataContext);
104+
initialScope.showAsserts = () => console.table(initialScope.asserts);
105+
initialScope.print = (...args: any) =>
106+
logFn({
107+
time: new Date(),
108+
level: 'info',
109+
message: args.map((v: any) => (typeof v === 'object' ? JSON.stringify(v) : v)).join(' ')
110+
});
19111
initialScope.params = (name: string) => {
20112
const value = context.params[name];
21113
return value === undefined ? null : value;
@@ -41,7 +133,7 @@ export function jsPythonForNode(
41133
entryFunctionName?: string | undefined,
42134
moduleName?: string | undefined
43135
) {
44-
context.asserts.length = 0;
136+
initialScope.asserts.splice(0, initialScope.asserts.length);
45137
await initialize(options.srcRoot || '');
46138
return evaluate.call(interpreter, script, evaluationContext, entryFunctionName, moduleName);
47139
};
@@ -112,43 +204,3 @@ export function jsPythonForNode(
112204
}
113205
}
114206
}
115-
116-
function getScript(fileName: string): string {
117-
if (!fs.existsSync(fileName)) {
118-
throw Error(`File not found`);
119-
}
120-
121-
const scripts = fs.readFileSync(fileName, 'utf8');
122-
return scripts;
123-
}
124-
125-
async function initialize(baseSource: string) {
126-
// process app.js (if exists)
127-
// - run _init
128-
// - delete _ init
129-
// - run _initAsync
130-
// - delete _initAsync
131-
// - load content into 'app'
132-
133-
let appJsPath = `${rootFolder}/${b 38BA aseSource}app.js`;
134-
console.log({ rootFolder, baseSource });
135-
if (!fs.existsSync(appJsPath)) {
136-
appJsPath = `${rootFolder}/src/app.js`;
137-
}
138-
139-
if (fs.existsSync(appJsPath)) {
140-
const app = require(appJsPath);
141-
142-
if (typeof app._init == 'function') {
143-
app._init();
144-
delete app._init;
145-
}
146-
147-
if (typeof app._initAsync == 'function') {
148-
await app._initAsync();
149-
delete app._initAsync;
150-
}
151-
152-
Object.assign(initialScope, app);
153-
}
154-
}

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
/* Basic Options */
44
// "incremental": true, /* Enable incremental compilation */
5-
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
5+
"target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
66
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
77
// "lib": [], /* Specify library files to be included in the compilation. */
88
// "allowJs": true, /* Allow javascript files to be compiled. */

0 commit comments

Comments
 (0)
0