diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-03-25 11:23:52 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-03-25 11:25:05 +0000 |
| commit | 22e3ba039d18f376cd98dfdc3271293ca33d4b14 (patch) | |
| tree | 47e862391f8c9bab4e77f1ef5a70eaf21c6f63dc | |
| parent | new core.base.match, update lib (diff) | |
| download | alive-22e3ba039d18f376cd98dfdc3271293ca33d4b14.tar.gz alive-22e3ba039d18f376cd98dfdc3271293ca33d4b14.zip | |
add match spec
| -rw-r--r-- | spec/core/match_spec.moon | 215 | ||||
| -rw-r--r-- | spec/core/pattern_spec.moon | 189 |
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} |
