From d362ef26db894ea52c6abd34489aa9efdbc0c89b Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Sat, 14 Jan 2023 13:22:39 +0530 Subject: chore: adds test cases + fixes Test effect scope --- src/eval-env/builtins.ts | 8 ++-- src/eval-env/test.ts | 17 +++++++-- src/eval.ts | 2 + src/index.ts | 17 ++++++--- stdlib/test.ts | 31 ++++++++++++---- tests/builtins.spec.ts | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+), 20 deletions(-) create mode 100644 tests/builtins.spec.ts diff --git a/src/eval-env/builtins.ts b/src/eval-env/builtins.ts index 669a005..35f8485 100644 --- a/src/eval-env/builtins.ts +++ b/src/eval-env/builtins.ts @@ -6,10 +6,10 @@ const applyFunc = (ctx: Ctx, fn: Type | undefined, val: string): Type => { const resultType = (() => { const baseTypes = fn ?.getBaseTypes() - .flatMap((t) => t.getSymbol()?.getName()) + .flatMap((t) => t.getSymbol()?.getName() ?? []) - if (baseTypes?.includes('Kind1')) { - const [_, resultNode] = ctx.createResult( + if (!!fn?.getProperty('return') || baseTypes?.includes('Kind1')) { + const [_key, resultNode] = ctx.createResult( `(${ctx.typeToString(fn)} & { input: ${val} })['return']` ) return resultNode @@ -53,7 +53,7 @@ const applyFunc = (ctx: Ctx, fn: Type | undefined, val: string): Type => { // TODO: Cleanup unwanted result node values if (!resultType) { - throw new Error('Fuck shit') + throw new Error('Couldnt get result for function application') } return resultType diff --git a/src/eval-env/test.ts b/src/eval-env/test.ts index 84ae138..4dd8c8d 100644 --- a/src/eval-env/test.ts +++ b/src/eval-env/test.ts @@ -2,7 +2,7 @@ import { Type } from 'ts-morph' import { Ctx } from '../types' export default (ctx: Ctx, args: Type[]) => ({ - Test: async () => { + Test: ctx.withScope(async () => { const [msg, effs] = args process.stdout.write(` - ${ctx.getTypeValue(msg)} `) @@ -13,12 +13,12 @@ export default (ctx: Ctx, args: Type[]) => ({ console.log('[✓]') } catch (e) { - console.log('[TEST FAILED]') + // console.log('[TEST FAILED]') throw e } return [] - }, + }), Assert: async () => { if (!ctx.getTypeValue(args[0])) { @@ -27,4 +27,15 @@ export default (ctx: Ctx, args: Type[]) => ({ return [] }, + + ShowAssertionError: async () => { + const [left, right] = args + console.log() + console.log(' | Assertion error:') + console.log(' | - Left: ', ctx.typeToString(left)) + console.log(' | - Right:', ctx.typeToString(right)) + console.log() + + return [] + }, }) diff --git a/src/eval.ts b/src/eval.ts index a7b1fb1..6eb72a1 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -32,6 +32,7 @@ export const evaluateType = async ( const name = effTyp.getSymbol()?.getName() const args = effTyp.getTypeArguments() + // console.log('>>>>>', name) // console.log(ctx.typeToString(effTyp)) // console.log(name, args.map(ctx.typeToString)) @@ -58,6 +59,7 @@ export const evaluateType = async ( prevEnv = ctx.currentEnv } + // Evaluate custom effects (overrides builtins) if (name && ctx.hasCustomEffect(name)) { return ctx.runCustomEffect(name, args) } diff --git a/src/index.ts b/src/index.ts index f6d46d6..4775823 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,12 +15,17 @@ const main = () => { .description('Run a typescript .ts file') .argument('', 'Typescript file to run') .action(async (filePath) => { - const ctx = createContext({ filePath }) - const resultType = ctx.entryPoint.getType() - const effects = resultType.isTuple() - ? resultType.getTupleElements() - : [resultType] - await evalList(ctx, effects) + try { + const ctx = createContext({ filePath }) + const resultType = ctx.entryPoint.getType() + const effects = resultType.isTuple() + ? resultType.getTupleElements() + : [resultType] + await evalList(ctx, effects) + } catch (e) { + console.error(e) + process.exit(1) + } }) return program.parseAsync() diff --git a/stdlib/test.ts b/stdlib/test.ts index 639c433..a592d87 100644 --- a/stdlib/test.ts +++ b/stdlib/test.ts @@ -1,12 +1,29 @@ -import { Effect } from './effect' +import { Do, Effect, Kind1 } from './effect' +import { Throw, Try } from './exception' +import { Equals } from './util' export interface Config { - compileTimeTestFailures: false - stopAtFailure: true // TODO: stopAtFailure + // compileTimeTestFailures: false + // stopAtFailure: true // TODO: stopAtFailure } -type Assertion = Config['compileTimeTestFailures'] extends true ? true : boolean +export interface Assert<_B extends boolean> extends Effect {} + +export interface Test<_m extends string, _effs extends Effect[]> extends Effect {} + +export interface ShowAssertionError<_L extends unknown, _R extends unknown> extends Effect {} + +export type AssertEquals = Try< + Assert>, + () => Do<[ + ShowAssertionError, + Throw, + ]> +> + +export interface AssertEqualsK extends Kind1 { + return: AssertEquals +} + +// TODO: export interface AssertFails? -export interface Assert<_B extends Assertion> extends Effect {} -export interface Test<_m extends string, _effs extends Effect[]> - extends Effect {} diff --git a/tests/builtins.spec.ts b/tests/builtins.spec.ts new file mode 100644 index 0000000..cd4b5c4 --- /dev/null +++ b/tests/builtins.spec.ts @@ -0,0 +1,96 @@ +import { Bind, BindTo, Do, Effect, Label, Pure } from '../stdlib/effect' +import { Throw, Try } from '../stdlib/exception' +import { PutStringLn } from '../stdlib/stdio' +import { DefineEffect, JsExpr, SetEvalEnvironment } from '../stdlib/sys' +import { Test, AssertEqualsK, AssertEquals } from '../stdlib/test' + +type testBind = Do<[ + PutStringLn<'Bind & BindTo'>, + + Test<'should bind value to function and kind', [ + Bind, () => + AssertEquals>, + + Bind, AssertEqualsK<[1,2,3]>>, + ]>, + + Test<'should bind label correctly', [ + BindTo<"value", Pure<{ a: 'b', c: { d: 1 } }>>, + + Bind, AssertEqualsK<{ a: 'b', c: { d: 1 } }>>, + ]>, + + Test<'should bind only inside Do scope', [ + Do<[ + BindTo<"value", Pure<"some value">>, + Bind, AssertEqualsK<"some value">>, + ]>, + + Bind< + Try, <_>() => Pure<"none">>, + AssertEqualsK<"none"> + >, + ]>, + + Test<'should bind only inside Bind scope', [ + Bind< + BindTo<"value", Pure<"some value">>, + <_>() => Bind, AssertEqualsK<"some value">> + >, + + Bind< + Try, <_>() => Pure<"none">>, + AssertEqualsK<"none"> + >, + ]>, +]> + +type testExcpt = Do<[ + PutStringLn<'Try/Throw'>, + + Test<'should return the result of effect', [ + Bind, <_>() => Pure<0>>, + AssertEqualsK<20>>, + ]>, + + Test<'should return the result of error handler', [ + Bind, Pure<20> ]>, <_>() => Pure<0>>, + AssertEqualsK<0>>, + + Bind, Pure<20> ]>, () => Pure>, + AssertEqualsK<"wow">>, + ]>, +]> + +interface MyEffect<_a extends number, _b extends string, _c extends unknown> extends Effect {} +type testFFI = Do<[ + PutStringLn<'FFI'>, + + Test<'should return the result of js expression', [ + Bind, AssertEqualsK<28980>>, + ]>, + + Test<'should test custom effect', [ + DefineEffect<'MyEffect', `([a, b, c], ctx) => { + return [ + ctx.getTypeValue(a) * 2, + ctx.getTypeValue(b) + '!', + [...ctx.getTypeValue(c), 'wow'], + ] + }`>, + Bind, AssertEqualsK<[ + 8, "hey!", [1, 2, 'wow'], + ]>>, + ]>, +]> + +export type main = [ + SetEvalEnvironment<'test.node'>, + + PutStringLn<'====================='>, + PutStringLn<'=== Running tests ==='>, + PutStringLn<'=====================\n\n'>, + testBind, + testExcpt, + testFFI, +] -- cgit v1.3.1