diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-21 15:10:49 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:24:49 +0000 |
| commit | 4b87fefc2e14acab7f0215599f0ac47d2ceb6339 (patch) | |
| tree | fffdf262e6688b030334a7c24a93b028f2327cf9 | |
| parent | base.match: fix bug when repeating multi-element patterns (diff) | |
| download | alive-4b87fefc2e14acab7f0215599f0ac47d2ceb6339.tar.gz alive-4b87fefc2e14acab7f0215599f0ac47d2ceb6339.zip | |
add PureOp spec
| -rw-r--r-- | spec/pureop_spec.moon | 129 | ||||
| -rw-r--r-- | spec/rtnode_spec.moon | 3 | ||||
| -rw-r--r-- | spec/test_setup.moon | 12 |
3 files changed, 141 insertions, 3 deletions
diff --git a/spec/pureop_spec.moon b/spec/pureop_spec.moon new file mode 100644 index 0000000..78dce4d --- /dev/null +++ b/spec/pureop_spec.moon @@ -0,0 +1,129 @@ +import do_setup, do_teardown, invoke_op from require 'spec.test_setup' +import PureOp, Input, T, val, evt from require 'alv.base' +import RTNode from require 'alv' + +setup do_setup +teardown do_teardown + +class TestPureOp extends PureOp + pattern: (val.num / val.str / evt.num)*3 + type: T.num + tick: => @out\set 1 + +literal = (result) -> + eval: -> + si = T.num\mk_sig! + RTNode :result, side_inputs: { [si]: Input.hot si } + +describe 'PureOp', -> + it 'matches the pattern', -> + assert.has.error -> invoke_op TestPureOp, {} + assert.has.error -> invoke_op TestPureOp, { literal T.bool\mk_evt! } + invoke_op TestPureOp, { literal T.num\mk_const 1 } + invoke_op TestPureOp, { literal T.str\mk_const 'hello' } + invoke_op TestPureOp, { literal T.num\mk_evt! } + + describe 'with constant inputs', -> + local rtn + it 'ticks once', -> + tiq = spy.on TestPureOp.__base, 'tick' + rtn = invoke_op TestPureOp, { T.num\mk_const(1), T.str\mk_const('hello') } + assert.spy(tiq).was_called_with match.is_ref(rtn.op), true + assert.is.equal 1, rtn.result! + + it 'is constant', -> + assert.is.equal '=', rtn\metatype! + + describe 'with signal inputs', -> + a = T.num\mk_sig 1 + b = T.num\mk_sig 2 + c = T.num\mk_sig 3 + tiq = spy.on TestPureOp.__base, 'tick' + rtn = invoke_op TestPureOp, { (literal a), (literal b), (literal c) } + op = rtn.op + + it 'sets up hot inputs', -> + assert.is.equal 3, #op.inputs + assert.is.equal a, op.inputs[1].result + assert.is.equal b, op.inputs[2].result + assert.is.equal c, op.inputs[3].result + assert.is.equal 'hot', op.inputs[1].mode + assert.is.equal 'hot', op.inputs[2].mode + assert.is.equal 'hot', op.inputs[3].mode + assert.spy(tiq).was_called! + + it 'has signal output', -> + assert.is.equal '~', op.out.metatype + + describe 'with event inputs', -> + a = T.num\mk_sig 1 + b = T.num\mk_evt 2 + c = T.num\mk_sig 3 + tiq = spy.on TestPureOp.__base, 'tick' + rtn = invoke_op TestPureOp, { (literal a), (literal b), (literal c) } + op = rtn.op + + it 'sets up hot input only for evt', -> + assert.is.equal 3, #op.inputs + assert.is.equal a, op.inputs[1].result + assert.is.equal b, op.inputs[2].result + assert.is.equal c, op.inputs[3].result + assert.is.equal 'cold', op.inputs[1].mode + assert.is.equal 'hot', op.inputs[2].mode + assert.is.equal 'cold', op.inputs[3].mode + assert.spy(tiq).was_not_called! + + it 'has event output', -> + assert.is.equal '!', op.out.metatype + + it 'only allows one event input', -> + a, b = T.num\mk_evt!, T.num\mk_evt! + assert.has.error -> invoke_op TestPureOp, { (literal a), (literal b) } + + it 'supports nested input patterns', -> + num = val.num / evt.num + class NestedInputOp extends PureOp + pattern: (num + val.str)\named('a', 'b')\rep 2, 2 + type: T.num + tick: => @out\set 1 + + num = T.num\mk_sig 1 + str = T.str\mk_sig 'hello' + oth = T.num\mk_evt 2 + args = { (literal num), (literal str), (literal oth), (literal str) } + rtn = invoke_op NestedInputOp, args + op = rtn.op + + assert.is.equal 2, #op.inputs + assert.is.equal num, op.inputs[1].a.result + assert.is.equal str, op.inputs[1].b.result + assert.is.equal oth, op.inputs[2].a.result + assert.is.equal str, op.inputs[2].b.result + assert.is.equal 'cold', op.inputs[1].a.mode + assert.is.equal 'cold', op.inputs[1].b.mode + assert.is.equal 'hot', op.inputs[2].a.mode + assert.is.equal 'cold', op.inputs[2].b.mode + + it 'supports dynamically generating the output type', -> + class DynamicOp extends PureOp + pattern: val.num + (val! / evt!) + type: (inputs) => inputs[2]\type! + tick: => @out\set @inputs[2]! + typ = spy.on DynamicOp, 'type' + + a = T.num\mk_sig 1 + num = T.num\mk_sig 1 + str = T.str\mk_sig 1 + sym = T.sym\mk_evt 1 + + rtn = invoke_op DynamicOp, { (literal a), (literal num) } + assert.is.equal '~', rtn.result.metatype + assert.is.equal num, rtn.result + + rtn = invoke_op DynamicOp, { (literal a), (literal str) } + assert.is.equal '~', rtn.result.metatype + assert.is.equal str, rtn.result + + rtn = invoke_op DynamicOp, { (literal a), (literal sym) } + assert.is.equal '!', rtn.result.metatype + assert.is.equal T.sym, rtn.result.type diff --git a/spec/rtnode_spec.moon b/spec/rtnode_spec.moon index 1719620..6ac7d15 100644 --- a/spec/rtnode_spec.moon +++ b/spec/rtnode_spec.moon @@ -18,8 +18,7 @@ dirty_op = -> result, input, op_with_inputs { input } node_with_sideinput = (result, input) -> - with RTNode :result - .side_inputs = { [result]: input } + RTNode :result, side_inputs: { [result]: input } describe 'RTNode', -> it 'wraps result, children', -> diff --git a/spec/test_setup.moon b/spec/test_setup.moon index dc91bdd..a402af4 100644 --- a/spec/test_setup.moon +++ b/spec/test_setup.moon @@ -1,4 +1,4 @@ -require 'alv' +import Constant, Scope, Op, Tag from require 'alv' import Copilot from require 'alv.copilot.base' import Module from require 'alv.module' import Logger from require 'alv.logger' @@ -29,4 +29,14 @@ export COPILOT do_teardown: -> COPILOT\end_eval! + + invoke_op: (op, tail, scope=Scope!) -> + import op_invoke from require 'alv.invoke' + + fake_cell = + head: -> 'test_op' + tail: -> tail + tag: Tag.blank! + + op_invoke\eval_cell fake_cell, Scope!, Constant.wrap op } |
