git.s-ol.nu alive / 5691cd2
add PureOp spec s-ol 2 years ago
3 changed file(s) with 141 addition(s) and 3 deletion(s). Raw diff Collapse all Expand all
0 import do_setup, do_teardown, invoke_op from require 'spec.test_setup'
1 import PureOp, Input, T, val, evt from require 'alv.base'
2 import RTNode from require 'alv'
3
4 setup do_setup
5 teardown do_teardown
6
7 class TestPureOp extends PureOp
8 pattern: (val.num / val.str / evt.num)*3
9 type: T.num
10 tick: => @out\set 1
11
12 literal = (result) ->
13 eval: ->
14 si = T.num\mk_sig!
15 RTNode :result, side_inputs: { [si]: Input.hot si }
16
17 describe 'PureOp', ->
18 it 'matches the pattern', ->
19 assert.has.error -> invoke_op TestPureOp, {}
20 assert.has.error -> invoke_op TestPureOp, { literal T.bool\mk_evt! }
21 invoke_op TestPureOp, { literal T.num\mk_const 1 }
22 invoke_op TestPureOp, { literal T.str\mk_const 'hello' }
23 invoke_op TestPureOp, { literal T.num\mk_evt! }
24
25 describe 'with constant inputs', ->
26 local rtn
27 it 'ticks once', ->
28 tiq = spy.on TestPureOp.__base, 'tick'
29 rtn = invoke_op TestPureOp, { T.num\mk_const(1), T.str\mk_const('hello') }
30 assert.spy(tiq).was_called_with match.is_ref(rtn.op), true
31 assert.is.equal 1, rtn.result!
32
33 it 'is constant', ->
34 assert.is.equal '=', rtn\metatype!
35
36 describe 'with signal inputs', ->
37 a = T.num\mk_sig 1
38 b = T.num\mk_sig 2
39 c = T.num\mk_sig 3
40 tiq = spy.on TestPureOp.__base, 'tick'
41 rtn = invoke_op TestPureOp, { (literal a), (literal b), (literal c) }
42 op = rtn.op
43
44 it 'sets up hot inputs', ->
45 assert.is.equal 3, #op.inputs
46 assert.is.equal a, op.inputs[1].result
47 assert.is.equal b, op.inputs[2].result
48 assert.is.equal c, op.inputs[3].result
49 assert.is.equal 'hot', op.inputs[1].mode
50 assert.is.equal 'hot', op.inputs[2].mode
51 assert.is.equal 'hot', op.inputs[3].mode
52 assert.spy(tiq).was_called!
53
54 it 'has signal output', ->
55 assert.is.equal '~', op.out.metatype
56
57 describe 'with event inputs', ->
58 a = T.num\mk_sig 1
59 b = T.num\mk_evt 2
60 c = T.num\mk_sig 3
61 tiq = spy.on TestPureOp.__base, 'tick'
62 rtn = invoke_op TestPureOp, { (literal a), (literal b), (literal c) }
63 op = rtn.op
64
65 it 'sets up hot input only for evt', ->
66 assert.is.equal 3, #op.inputs
67 assert.is.equal a, op.inputs[1].result
68 assert.is.equal b, op.inputs[2].result
69 assert.is.equal c, op.inputs[3].result
70 assert.is.equal 'cold', op.inputs[1].mode
71 assert.is.equal 'hot', op.inputs[2].mode
72 assert.is.equal 'cold', op.inputs[3].mode
73 assert.spy(tiq).was_not_called!
74
75 it 'has event output', ->
76 assert.is.equal '!', op.out.metatype
77
78 it 'only allows one event input', ->
79 a, b = T.num\mk_evt!, T.num\mk_evt!
80 assert.has.error -> invoke_op TestPureOp, { (literal a), (literal b) }
81
82 it 'supports nested input patterns', ->
83 num = val.num / evt.num
84 class NestedInputOp extends PureOp
85 pattern: (num + val.str)\named('a', 'b')\rep 2, 2
86 type: T.num
87 tick: => @out\set 1
88
89 num = T.num\mk_sig 1
90 str = T.str\mk_sig 'hello'
91 oth = T.num\mk_evt 2
92 args = { (literal num), (literal str), (literal oth), (literal str) }
93 rtn = invoke_op NestedInputOp, args
94 op = rtn.op
95
96 assert.is.equal 2, #op.inputs
97 assert.is.equal num, op.inputs[1].a.result
98 assert.is.equal str, op.inputs[1].b.result
99 assert.is.equal oth, op.inputs[2].a.result
100 assert.is.equal str, op.inputs[2].b.result
101 assert.is.equal 'cold', op.inputs[1].a.mode
102 assert.is.equal 'cold', op.inputs[1].b.mode
103 assert.is.equal 'hot', op.inputs[2].a.mode
104 assert.is.equal 'cold', op.inputs[2].b.mode
105
106 it 'supports dynamically generating the output type', ->
107 class DynamicOp extends PureOp
108 pattern: val.num + (val! / evt!)
109 type: (inputs) => inputs[2]\type!
110 tick: => @out\set @inputs[2]!
111 typ = spy.on DynamicOp, 'type'
112
113 a = T.num\mk_sig 1
114 num = T.num\mk_sig 1
115 str = T.str\mk_sig 1
116 sym = T.sym\mk_evt 1
117
118 rtn = invoke_op DynamicOp, { (literal a), (literal num) }
119 assert.is.equal '~', rtn.result.metatype
120 assert.is.equal num, rtn.result
121
122 rtn = invoke_op DynamicOp, { (literal a), (literal str) }
123 assert.is.equal '~', rtn.result.metatype
124 assert.is.equal str, rtn.result
125
126 rtn = invoke_op DynamicOp, { (literal a), (literal sym) }
127 assert.is.equal '!', rtn.result.metatype
128 assert.is.equal T.sym, rtn.result.type
1717 result, input, op_with_inputs { input }
1818
1919 node_with_sideinput = (result, input) ->
20 with RTNode :result
21 .side_inputs = { [result]: input }
20 RTNode :result, side_inputs: { [result]: input }
2221
2322 describe 'RTNode', ->
2423 it 'wraps result, children', ->
0 require 'alv'
0 import Constant, Scope, Op, Tag from require 'alv'
11 import Copilot from require 'alv.copilot.base'
22 import Module from require 'alv.module'
33 import Logger from require 'alv.logger'
2828
2929 do_teardown: ->
3030 COPILOT\end_eval!
31
32 invoke_op: (op, tail, scope=Scope!) ->
33 import op_invoke from require 'alv.invoke'
34
35 fake_cell =
36 head: -> 'test_op'
37 tail: -> tail
38 tag: Tag.blank!
39
40 op_invoke\eval_cell fake_cell, Scope!, Constant.wrap op
3141 }