aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-03-25 11:23:52 +0000
committers-ol <s-ol@users.noreply.github.com>2020-03-25 11:25:05 +0000
commit22e3ba039d18f376cd98dfdc3271293ca33d4b14 (patch)
tree47e862391f8c9bab4e77f1ef5a70eaf21c6f63dc
parentnew core.base.match, update lib (diff)
downloadalive-22e3ba039d18f376cd98dfdc3271293ca33d4b14.tar.gz
alive-22e3ba039d18f376cd98dfdc3271293ca33d4b14.zip
add match spec
-rw-r--r--spec/core/match_spec.moon215
-rw-r--r--spec/core/pattern_spec.moon189
2 files changed, 215 insertions, 189 deletions
diff --git a/spec/core/match_spec.moon b/spec/core/match_spec.moon
new file mode 100644
index 0000000..4a72561
--- /dev/null
+++ b/spec/core/match_spec.moon
@@ -0,0 +1,215 @@
+import val, evt from require 'core.base.match'
+import Result, ValueStream, EventStream from require 'core'
+
+mk_val = (type, const) ->
+ value = ValueStream type
+ with Result :value
+ .side_inputs = { 'fake' } unless const
+
+mk_evt = (type, const) ->
+ value = EventStream type
+ with Result :value
+ .side_inputs = { 'fake' } unless const
+
+describe 'val and evt', ->
+ describe 'type-less shorthand', ->
+ it 'matches metatype', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+ assert.is.equal str, val!\match { str }
+ assert.is.equal num, val!\match { num }
+ assert.has.error -> evt!\match { str }
+ assert.has.error -> evt!\match { num }
+
+ str = mk_evt 'str'
+ num = mk_evt 'num'
+ assert.is.equal str, evt!\match { str }
+ assert.is.equal num, evt!\match { num }
+ assert.has.error -> val!\match { str }
+ assert.has.error -> val!\match { num }
+
+ it 'is in recall mode', ->
+ value = val!
+ event = evt!
+ two_equal_values = value + value
+ two_equal_events = event + event
+
+ str1 = mk_val 'str'
+ str2 = mk_val 'str'
+ num = mk_val 'num'
+ assert.is.same { str1, str2 }, two_equal_values\match { str1, str2 }
+ assert.is.same { str2, str1 }, two_equal_values\match { str2, str1 }
+ assert.is.same { num, num }, two_equal_values\match { num, num }
+ assert.has.error -> two_equal_values\match { str1, num }
+ assert.has.error -> two_equal_values\match { num, str2 }
+ assert.has.error -> two_equal_events\match { str1, str2 }
+
+ str1 = mk_evt 'str'
+ str2 = mk_evt 'str'
+ num = mk_evt 'num'
+ assert.is.same { str1, str2 }, two_equal_events\match { str1, str2 }
+ assert.is.same { str2, str1 }, two_equal_events\match { str2, str1 }
+ assert.is.same { num, num }, two_equal_events\match { num, num }
+ assert.has.error -> two_equal_events\match { str1, num }
+ assert.has.error -> two_equal_events\match { num, str2 }
+ assert.has.error -> two_equal_values\match { str1, str2 }
+
+ describe 'typed shorthand', ->
+ it 'matches by metatype', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+ assert.is.equal str, val.str\match { str }
+ assert.is.equal num, val.num\match { num }
+ assert.has.error -> evt.str\match { str }
+ assert.has.error -> evt.num\match { num }
+
+ str = mk_evt 'str'
+ num = mk_evt 'num'
+ assert.is.equal str, evt.str\match { str }
+ assert.is.equal num, evt.num\match { num }
+ assert.has.error -> val.str\match { str }
+ assert.has.error -> val.num\match { num }
+
+ it 'matches by type', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+ assert.is.equal str, val.str\match { str }
+ assert.is.equal num, val.num\match { num }
+ assert.has.error -> val.num\match { str }
+ assert.has.error -> val.str\match { num }
+
+ str = mk_evt 'str'
+ num = mk_evt 'num'
+ assert.is.equal str, evt.str\match { str }
+ assert.is.equal num, evt.num\match { num }
+ assert.has.error -> evt.num\match { str }
+ assert.has.error -> evt.str\match { num }
+
+describe 'choice', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+ bool = mk_val 'bool'
+ choice = val.str / val.num
+
+ it 'matches either type', ->
+ assert.is.equal str, choice\match { str }
+ assert.is.equal num, choice\match { num }
+ assert.has.error -> choice\match { bool }
+
+ it 'can recall the choice', ->
+ same = choice!
+ assert.is.equal num, same\match { num }
+
+ same = same + same
+ assert.is.same { str, str }, same\match { str, str }
+ assert.is.same { num, num }, same\match { num, num }
+ assert.has.error -> same\match { str, num }
+ assert.has.error -> same\match { num, str }
+ assert.has.error -> same\match { bool, bool }
+
+ it 'makes inner types recall', ->
+ same = (val! / evt!)!
+ same = same + same
+ assert.is.same { str, str }, same\match { str, str }
+ assert.is.same { num, num }, same\match { num, num }
+ assert.is.same { bool, bool }, same\match { bool, bool }
+ assert.has.error -> same\match { str, num }
+ assert.has.error -> same\match { num, str }
+
+describe 'sequence', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+ bool = mk_val 'bool'
+ seq = val.str + val.num + val.bool
+
+ it 'matches all types in order', ->
+ assert.is.same { str, num, bool }, seq\match { str, num, bool }
+
+ it 'can assign non-numeric keys', ->
+ named = seq\named 'str', 'num', 'bool'
+ assert.is.same { :str, :num, :bool }, named\match { str, num, bool }
+ assert.is.same { str, num, bool }, seq\match { str, num, bool }
+
+ it 'fails if too little arguments', ->
+ assert.has.error -> seq\match { str, num }
+
+ it 'fails if too many arguments', ->
+ assert.has.error -> seq\match { str, num, bool, bool }
+
+ it 'can handle optional children', ->
+ opt = -val.str + val.num
+ assert.is.same { str, num }, opt\match { str, num }
+ assert.is.same { nil, num }, opt\match { num }
+ assert.has.error -> opt\match { str, str, num }
+ assert.has.error -> opt\match { str, num, num }
+
+ it 'can handle repeat children', ->
+ rep = val.str + val.num*2
+ assert.is.same { str, {num} }, rep\match { str, num }
+ assert.is.same { str, {num,num} }, rep\match { str, num, num }
+ assert.has.error -> rep\match { str }
+ assert.has.error -> rep\match { str, num, num, num }
+
+describe 'repeat', ->
+ str = mk_val 'str'
+ num = mk_val 'num'
+
+ times = (n, arg) -> return for i=1,n do arg
+
+ it '*x is [1,x[', ->
+ rep = val.str*3
+ assert.has.error -> rep\match (times 0, str)
+ assert.is.same (times 1, str), rep\match (times 1, str)
+ assert.is.same (times 2, str), rep\match (times 2, str)
+ assert.is.same (times 3, str), rep\match (times 3, str)
+ assert.has.error -> rep\match (times 4, str)
+ assert.has.error -> rep\match (times 3, num)
+
+ it '*0 is [1,[', ->
+ rep = val.str*0
+ assert.has.error -> rep\match (times 0, str)
+ assert.is.same (times 1, str), rep\match (times 1, str)
+ assert.is.same (times 2, str), rep\match (times 2, str)
+ assert.is.same (times 20, str), rep\match (times 20, str)
+ assert.has.error -> rep\match (times 3, num)
+
+ it '^x is [0,x[', ->
+ rep = val.str^3
+ assert.is.same {}, rep\match {}
+ assert.is.same (times 1, str), rep\match (times 1, str)
+ assert.is.same (times 2, str), rep\match (times 2, str)
+ assert.is.same (times 3, str), rep\match (times 3, str)
+ assert.has.error -> rep\match (times 4, str)
+ assert.has.error -> rep\match (times 3, num)
+
+ it '^0 is [0,[', ->
+ rep = val.str^0
+ assert.is.same {}, rep\match {}
+ assert.is.same (times 1, str), rep\match (times 1, str)
+ assert.is.same (times 2, str), rep\match (times 2, str)
+ assert.is.same (times 20, str), rep\match (times 20, str)
+ assert.has.error -> rep\match (times 3, num)
+
+ it ':rep(min, max) does anything else', ->
+ rep = val.str\rep 2, 2
+ assert.has.error -> rep\match {}
+ assert.has.error -> rep\match (times 1, str)
+ assert.is.same (times 2, str), rep\match (times 2, str)
+ assert.has.error -> rep\match (times 3, str)
+ assert.has.error -> rep\match (times 2, num)
+
+describe 'complex nesting', ->
+ it 'just works', ->
+ bang = mk_evt 'bang'
+ str = mk_val 'str'
+ num = mk_val 'num'
+
+ pattern = -evt.bang + val.num*4 + (val.str + (val.num / val.str))\named('key', 'val')^0
+ assert.is.same { bang, { num, num }, {} }, pattern\match { bang, num, num }
+ assert.is.same { nil, { num }, { { key: str, val: num }, { key: str, val: str } } },
+ pattern\match { num, str, num, str, str }
+ assert.has.error -> pattern\match { num, str }
+ assert.has.error -> pattern\match { bang, num, num, num, num, num, num }
+ assert.has.error -> pattern\match { bang, bang, num }
+ assert.has.error -> pattern\match { num, str, num, str }
+ assert.has.error -> pattern\match { num, str, num, str, mk_val 'bool' }
diff --git a/spec/core/pattern_spec.moon b/spec/core/pattern_spec.moon
deleted file mode 100644
index 523ce86..0000000
--- a/spec/core/pattern_spec.moon
+++ /dev/null
@@ -1,189 +0,0 @@
-import Pattern, match from require 'core.base.match'
-import Result, ValueStream from require 'core'
-
--- wrap in non-const result
-wrap = (value) ->
- with Result :value
- .side_inputs = { 'fake' }
-
--- wrap in const result
-wrap_const = (value) -> Result :value
-
-describe 'Type Pattern', ->
- num = wrap ValueStream.num 1
- str = wrap ValueStream.str 'hello'
- special = wrap ValueStream 'midi/sysex-message'
- c_num = wrap_const ValueStream.num 1
- c_str = wrap_const ValueStream.str 'hello'
-
- describe 'simple types', ->
- it 'matches self type', ->
- pat = Pattern 'num'
- assert.is.true pat\matches num
- assert.is.true pat\matches c_num
- assert.is.false pat\matches str
- assert.is.false pat\matches c_str
- assert.is.false pat\matches nil
-
- it 'can contain special symbols', ->
- pat = Pattern 'midi/sysex-message'
- assert.is.true pat\matches special
- assert.is.false pat\matches num
- assert.is.false pat\matches str
- assert.is.false pat\matches nil
-
- it 'can match \'any\' type', ->
- pat = Pattern 'any'
- assert.is.true pat\matches num
- assert.is.true pat\matches str
- assert.is.true pat\matches special
- assert.is.true pat\matches c_num
- assert.is.true pat\matches c_str
- assert.is.false pat\matches nil
-
- it 'checks const-ness', ->
- pat = Pattern '=any'
- assert.is.true pat.const
- assert.is.true pat\matches c_num
- assert.is.true pat\matches c_str
- assert.is.false pat\matches num
- assert.is.false pat\matches str
- assert.is.false pat\matches nil
-
- pat = Pattern '=num'
- assert.is.true pat.const
- assert.is.true pat\matches c_num
- assert.is.false pat\matches c_str
- assert.is.false pat\matches num
- assert.is.false pat\matches str
- assert.is.false pat\matches nil
-
- describe 'can capture', ->
- it 'matches', ->
- pat = Pattern 'str'
- stream = {str, num}
- assert.is.equal str, pat\match stream
- assert.is.same {num}, stream
-
- it 'errors if not given', ->
- pat = Pattern 'str'
- stream = {}
- assert.has.error -> pat\match stream
-
- stream = {num, str}
- assert.has.error -> pat\match stream
- assert.is.same {num, str}, stream
-
- describe 'optional types', ->
- pat = Pattern 'num?'
-
- it 'at the end', ->
- stream = {}
- assert.is.false, pat\match stream
-
- it 'in the middle', ->
- stream = {str}
- assert.is.false, pat\match stream
-
- describe 'splats', ->
- pat = Pattern '*num'
- it 'parses', ->
- assert.is.true pat.splat
- assert.is.equal 'num', pat.type
-
- it 'at the end', ->
- stream = {}
- assert.has.error -> pat\match stream
- assert.is.same {}, stream
-
- stream = {num}
- assert.is.same {num}, pat\match stream
- assert.is.same {}, stream
-
- stream = {num, num}
- assert.is.same {num, num}, pat\match stream
- assert.is.same {}, stream
-
- it 'in the middle', ->
- stream = {str}
- assert.has.error -> pat\match stream
- assert.is.same {str}, stream
-
- stream = {num, str}
- assert.is.same {num}, pat\match stream
- assert.is.same {str}, stream
-
- stream = {num, num, str}
- assert.is.same {num, num}, pat\match stream
- assert.is.same {str}, stream
-
- describe 'optional splats', ->
- pat = Pattern '*num?'
- it 'parses', ->
- assert.is.true pat.splat
- assert.is.true pat.opt
- assert.is.equal 'num', pat.type
-
- it 'at the end', ->
- stream = {}
- assert.is.same {}, pat\match stream
- assert.is.same {}, stream
-
- stream = {num}
- assert.is.same {num}, pat\match stream
- assert.is.same {}, stream
-
- stream = {num, num}
- assert.is.same {num, num}, pat\match stream
- assert.is.same {}, stream
-
- it 'in the middle', ->
- stream = {str}
- assert.is.same {}, pat\match stream
- assert.is.same {str}, stream
-
- stream = {num, str}
- assert.is.same {num}, pat\match stream
- assert.is.same {str}, stream
-
- stream = {num, num, str}
- assert.is.same {num, num}, pat\match stream
- assert.is.same {str}, stream
-
-describe 'match', ->
- num = wrap ValueStream.num 1
- str = wrap ValueStream.str 'hello'
- c_num = wrap_const ValueStream.num 1
- c_str = wrap_const ValueStream.str 'hello'
-
- it 'matches lists', ->
- assert.is.same {num, num, str}, match 'num num str', {num, num, str}
- assert.is.same {num, str}, match 'num str', {num, str}
- assert.is.same {c_num, str}, match '=num str', {c_num, str}
-
- it 'throws type errors', ->
- assert.has.error -> match 'str num str', {num, num, str}
- assert.has.error -> match 'num str num', {num, str}
- assert.has.error -> match '=num str', {num, str}
-
- it 'throws extra arg errors', ->
- assert.has.error -> match 'num str', {num, str, str}
- assert.has.error -> match {}, {num}
- assert.has.error -> match '*num', {num, num, str}
-
- it 'matches optional arguments', ->
- assert.is.same {str, num, str}, match 'str num? str', {str, num, str}
- assert.is.same {str, nil, str}, match 'str num? str', {str, str}
- assert.is.same {str, nil}, match 'str num?', {str}
-
- it 'matches splats', ->
- assert.is.same {{c_str, str, str}, num}, match '*str num', {c_str, str, str, num}
- assert.is.same {c_str, {str, str}}, match 'any? *str', {c_str, str, str}
- assert.has.error -> match '*str num', {num}
- assert.has.error -> match 'any? *str', {str}
-
- it 'matches optional splats', ->
- assert.is.same {{c_str, str, str}, num}, match '*str? num', {c_str, str, str, num}
- assert.is.same {c_str, {str, str}}, match 'any? *str?', {c_str, str, str}
- assert.is.same {{}, num}, match '*str? num', {num}
- assert.is.same {str, {}}, match 'any? *str?', {str}