aboutsummaryrefslogtreecommitdiffstats
path: root/spec/core
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-02-28 12:21:57 +0000
committers-ol <s-ol@users.noreply.github.com>2020-02-28 21:01:19 +0000
commitdf8141c3214a5fb8d447297be64bdf5619b7d8a7 (patch)
treef401303d36724c1055e25e0aaef9e0a27107c8a1 /spec/core
parentlots of fixes (diff)
downloadalive-df8141c3214a5fb8d447297be64bdf5619b7d8a7.tar.gz
alive-df8141c3214a5fb8d447297be64bdf5619b7d8a7.zip
doc and tag spec
Diffstat (limited to 'spec/core')
-rw-r--r--spec/core/cell_spec.moon36
-rw-r--r--spec/core/parsing_spec.moon146
-rw-r--r--spec/core/registry_spec.moon8
-rw-r--r--spec/core/scope_spec.moon114
-rw-r--r--spec/core/tag_spec.moon100
-rw-r--r--spec/core/value_spec.moon123
6 files changed, 527 insertions, 0 deletions
diff --git a/spec/core/cell_spec.moon b/spec/core/cell_spec.moon
new file mode 100644
index 0000000..fcf9861
--- /dev/null
+++ b/spec/core/cell_spec.moon
@@ -0,0 +1,36 @@
+import Cell, RootCell, Value, Scope, globals from require 'core'
+import Registry from require 'core.registry'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+hello_world = Cell nil, { (Value.sym 'hello'), (Value.str 'world') }
+two_plus_two = Cell nil, { (Value.sym '+'), (Value.num 2), (Value.num 2) }
+
+describe 'Cell', ->
+ it 'supports quoting', ->
+ with hello_world\quote!
+ assert.is.equal Cell, .__class
+ assert.is.equal (Value.sym 'hello'), \head!
+ assert.is.same { Value.str 'world' }, \tail!
+
+ with two_plus_two\quote!
+ assert.is.equal Cell, .__class
+ assert.is.equal (Value.sym '+'), \head!
+ assert.is.same { (Value.num 2), (Value.num 2) }, \tail!
+
+
+describe 'RootCell', ->
+ test 'head is always "do"', ->
+ cell = RootCell\parse {}
+ assert.is.equal (Value.sym 'do'), cell\head!
+
+ cell = RootCell nil, { hello_world, two_plus_two }
+ assert.is.equal (Value.sym 'do'), cell\head!
+
+ test 'tail is all children', ->
+ cell = RootCell\parse {}
+ assert.is.same {}, cell\tail!
+
+ cell = RootCell nil, { hello_world, two_plus_two }
+ assert.is.same { hello_world, two_plus_two },
+ cell\tail!
diff --git a/spec/core/parsing_spec.moon b/spec/core/parsing_spec.moon
new file mode 100644
index 0000000..ddf760f
--- /dev/null
+++ b/spec/core/parsing_spec.moon
@@ -0,0 +1,146 @@
+import space, atom, expr, explist, cell, program, comment from require 'core.parsing'
+import Value from require 'core'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+verify_parse = (parser, str) ->
+ with assert parser\match str
+ assert.is.equal str, \stringify!
+
+verify_parse_nope = (parser, str) ->
+ with assert parser\match str
+ without_nope = str\match '^(.*) nope$'
+ assert.is.equal without_nope, \stringify!
+
+describe 'atom parsing', ->
+ test 'symbols', ->
+ sym = verify_parse_nope atom, 'some-toast nope'
+ assert.is.equal 'sym', sym.type
+ assert.is.equal 'some-toast', sym\unwrap!
+ assert.is.equal 'some-toast', sym\stringify!
+
+ describe 'numbers', ->
+ it 'parses ints', ->
+ num = verify_parse_nope atom, '1234 nope'
+ assert.is.equal 'num', num.type
+ assert.is.equal 1234, num\unwrap!
+ assert.is.equal '1234', num\stringify!
+
+ it 'parses floats', ->
+ num = verify_parse_nope atom, '0.123 nope'
+ assert.is.equal 'num', num.type
+ assert.is.equal 0.123, num\unwrap!
+
+ num = verify_parse_nope atom, '.123 nope'
+ assert.is.equal 'num', num.type
+ assert.is.equal 0.123, num\unwrap!
+
+ num = verify_parse_nope atom, '0. nope'
+ assert.is.equal 'num', num.type
+ assert.is.equal 0, num\unwrap!
+
+ describe 'strings', ->
+ it 'parses double-quote strings', ->
+ str = verify_parse_nope atom, '"help some stuff!" nope'
+ assert.is.equal 'str', str.type
+ assert.is.equal 'help some stuff!', str\unwrap!
+
+ it 'parses single-quote strings', ->
+ str = verify_parse_nope atom, "'help some stuff!' nope"
+ assert.is.equal 'str', str.type
+ assert.is.equal "help some stuff!", str\unwrap!
+
+ it 'handles escapes', ->
+ str = verify_parse_nope atom, '"string with \\"quote\\"s and \\\\" nope'
+ assert.is.equal 'str', str.type
+ assert.is.equal 'string with \"quote\"s and \\', str\unwrap!
+
+ str = verify_parse_nope atom, "'string with \\'quote\\'s and \\\\' nope"
+ assert.is.equal 'str', str.type
+ assert.is.equal "string with \'quote\'s and \\", str\unwrap!
+
+describe 'Cell', ->
+ test 'basic parsing', ->
+ node = verify_parse cell, '( 3 ok-yes
+ "friend" )'
+
+ assert.is.equal 3, #node.children
+ assert.is.equal (Value.num 3), node.children[1]
+ assert.is.equal (Value.sym 'ok-yes'), node.children[2]
+ assert.is.equal (Value.str 'friend'), node.children[3]
+
+ test 'tag parsing', ->
+ node = verify_parse cell, '([42]tagged 2)'
+
+ assert.is.equal 2, #node.children
+ assert.is.equal 42, node.tag.value
+
+ test 'tag parsing with whitespace', ->
+ node = verify_parse cell, '([42]
+ tagged 2)'
+
+ assert.is.equal 2, #node.children
+ assert.is.equal 42, node.tag.value
+
+describe 'RootCell parsing', ->
+ describe 'handles whitespace', ->
+ verify = (str) ->
+ node = verify_parse program, str
+
+ assert.is.equal 2, #node.children
+ assert.is.equal (Value.num 3), node.children[1]
+ assert.is.equal (Value.sym 'ok-yes'), node.children[2]
+
+ it 'at the front of the string', ->
+ verify ' 3\tok-yes'
+
+ it 'at the end of the string', ->
+ verify ' 3\tok-yes\n'
+
+ it 'everywhere', ->
+ verify ' 3\tok-yes\n'
+
+test 'whitespace', ->
+ assert.is.equal ' ', space\match ' '
+ assert.is.equal '\n\t ', space\match '\n\t '
+
+describe 'comments', ->
+ comment = comment / 1
+ it 'are parsed', ->
+ str = '#(this is a comment)'
+ assert.is.equal str, comment\match str
+
+ it 'extend to matching braces', ->
+ str = '#(this is a comment #(with nested comments))'
+ assert.is.equal str, comment\match str
+
+ it 'can nest', ->
+ str = '#(this is a comment (with nested parenthesis))'
+ assert.is.equal str, comment\match str
+
+describe 'resynthesis', ->
+ test 'mixed parsing', ->
+ str = '( 3 ok-yes
+ "friend" )'
+ node = verify_parse program, str
+ assert.is.equal str, node\stringify!
+
+ test 'complex', ->
+ str = '
+ #(send a CC controlled LFO to /radius)
+ (osc "/radius" (lfo (cc 14)))
+
+ (osc rot
+ (step
+ #(whenever a kick is received...)
+ (note "kick")
+
+ #(..cycle through random rotation values)
+ (random-rot)
+ (random-rot)
+ (random-rot)
+ (random-rot)
+ )
+ ) '
+ matched = assert.is.truthy verify_parse program, str
+ assert.is.equal str, matched\stringify!
diff --git a/spec/core/registry_spec.moon b/spec/core/registry_spec.moon
new file mode 100644
index 0000000..6fe2e3a
--- /dev/null
+++ b/spec/core/registry_spec.moon
@@ -0,0 +1,8 @@
+import Registry, Tag from require 'core.registry'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+mk = ->
+ mock destroy: =>
+
+describe 'registry', ->
diff --git a/spec/core/scope_spec.moon b/spec/core/scope_spec.moon
new file mode 100644
index 0000000..471bbce
--- /dev/null
+++ b/spec/core/scope_spec.moon
@@ -0,0 +1,114 @@
+import Scope, Value, Op from require 'core'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+class TestOp extends Op
+ new: (...) => super ...
+
+describe 'Scope', ->
+ describe 'constifies', ->
+ scope = Scope!
+
+ test 'numbers', ->
+ scope\set_raw 'num', 3
+
+ got = (scope\get 'num')\const!
+ assert.is.equal 'num', got.type
+ assert.is.equal 3, got.value
+
+ test 'strings', ->
+ scope\set_raw 'str', "im a happy string"
+
+ got = (scope\get 'str')\const!
+ assert.is.equal 'str', got.type
+ assert.is.equal "im a happy string", got.value
+
+ test 'Values', ->
+ pi = Value 'num', 3.14
+ scope\set_raw 'pi', pi
+
+ assert.is.equal pi, (scope\get 'pi')\const!
+
+ test 'Opdefs', ->
+ scope\set_raw 'test', TestOp
+
+ got = (scope\get 'test')\const!
+ assert.is.equal 'opdef', got.type
+ assert.is.equal TestOp, got.value
+
+ test 'Scopes', ->
+ sub = Scope!
+ scope\set_raw 'sub', sub
+
+ got = (scope\get 'sub')\const!
+ assert.is.equal 'scope', got.type
+ assert.is.equal sub, got.value
+
+ test 'tables', ->
+ pi = Value 'num', 3.14
+ scope\set_raw 'math', { :pi }
+
+ got = (scope\get 'math')\const!
+ assert.is.equal 'scope', got.type
+ assert.is.equal Scope, got.value.__class
+ assert.is.equal pi, (got.value\get 'pi')\const!
+ assert.is.equal pi, (scope\get 'math/pi')\const!
+
+ it 'wraps Values in from_table', ->
+ pi = Value 'num', 3.14
+ scope = Scope.from_table {
+ num: 3
+ str: "im a happy string"
+ :pi
+ math: :pi
+ test: TestOp
+ }
+
+ got = (scope\get 'num')\const!
+ assert.is.equal 'num', got.type
+ assert.is.equal 3, got.value
+
+ got = (scope\get 'str')\const!
+ assert.is.equal 'str', got.type
+ assert.is.equal "im a happy string", got.value
+
+ assert.is.equal pi, (scope\get 'pi')\const!
+
+ got = (scope\get 'test')\const!
+ assert.is.equal 'opdef', got.type
+ assert.is.equal TestOp, got.value
+
+ got = (scope\get 'math')\const!
+ assert.is.equal 'scope', got.type
+ assert.is.equal pi, (scope\get 'math/pi')\const!
+
+ it 'gets from nested scopes', ->
+ root = Scope!
+ a = Scope!
+ b = Scope!
+
+ pi = Value 'num', 3.14
+ b\set_raw 'test', pi
+ a\set_raw 'child', b
+ root\set_raw 'deep', a
+
+ assert.is.equal pi, (root\get 'deep/child/test')\const!
+
+ describe 'inheritance', ->
+ root = Scope!
+ root\set_raw 'hidden', 1234
+ root\set_raw 'inherited', "inherited string"
+
+ scope = Scope nil, root
+
+ it 'allows access', ->
+ got = (scope\get 'inherited')\const!
+ assert.is.equal 'str', got.type
+ assert.is.equal "inherited string", got.value
+
+ it 'can keep defs', ->
+ scope\set_raw 'hidden', "overwritten"
+
+ got = (scope\get 'hidden')\const!
+ assert.is.equal 'str', got.type
+ assert.is.equal "overwritten", got.value
diff --git a/spec/core/tag_spec.moon b/spec/core/tag_spec.moon
new file mode 100644
index 0000000..7855fd6
--- /dev/null
+++ b/spec/core/tag_spec.moon
@@ -0,0 +1,100 @@
+import Tag from require 'core.tag'
+import Registry from require 'core.registry'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+with_reg = (fn) ->
+ registry = Registry!
+ fn = registry\wrap_eval fn
+ fn, registry
+
+do_reg = (fn) ->
+ fn, reg = with_reg fn
+ fn!
+ reg
+
+describe 'Tag', ->
+ describe 'should be constructable', ->
+ it 'by parsing', ->
+ tag = Tag\parse '2'
+ assert tag
+ assert.is.equal 2, tag.value
+ assert.is.equal '[2]', tag\stringify!
+ assert.is.equal '2', tostring tag
+
+ it 'as blank Tags', ->
+ tag = Tag\blank!
+ assert tag
+ assert.is.nil tag.value
+ assert.is.equal '', tag\stringify!
+ assert.is.equal '?', tostring tag
+
+ describe 'should be clonable', ->
+ do_asserts = (tag, expect) ->
+ assert tag
+ assert.is.nil tag.value
+ assert.is.equal expect, tostring tag
+ assert.has.error tag\stringify
+
+ it 'from parsed tags', with_reg ->
+ parent = Tag\parse '1'
+ original = Tag\parse '2'
+ tag = original\clone parent
+ do_asserts tag, '1.2'
+
+ it 'but not from blank tags', with_reg ->
+ parent = Tag\parse '1'
+ original = Tag\blank!
+ tag = original\clone parent
+ do_asserts tag, '1.?'
+
+ it 'with blank parent', with_reg ->
+ parent = Tag\blank!
+ original = Tag\parse '2'
+ tag = original\clone parent
+ do_asserts tag, '?.2'
+
+ it 'completely blank', with_reg ->
+ parent = Tag\blank!
+ original = Tag\blank!
+ tag = original\clone parent
+ do_asserts tag, '?.?'
+
+ describe 'should be set-able', ->
+ it 'only if blank', with_reg ->
+ tag = Tag\parse '42'
+ assert.has.error -> tag\set 43
+
+ clone = tag\clone Tag\parse '3'
+ assert.has.error -> clone\set 42
+
+ clone = tag\clone Tag\blank!
+ assert.has.error -> clone\set 42
+
+ it 'and stores the value', with_reg ->
+ blank = Tag\blank!
+ blank\set 12
+
+ assert.is.equal blank.value, 12
+
+ it 'sets the original if cloned', with_reg ->
+ original = Tag\blank!
+ parent = Tag\parse '7'
+
+ o_set = spy.on original, 'set'
+ p_set = spy.on parent, 'set'
+
+ clone = original\clone parent
+ clone\set 11
+
+ assert.spy(o_set).was_called_with (match.is_ref original), 11
+ assert.spy(p_set).was_not_called!
+
+ assert.is.equal original.value, 11
+
+ it 'requires the parent to be registered if cloned', with_reg ->
+ original = Tag\blank!
+ parent = Tag\blank!
+
+ clone = original\clone parent
+ assert.has.error -> clone\set 11
diff --git a/spec/core/value_spec.moon b/spec/core/value_spec.moon
new file mode 100644
index 0000000..cda7123
--- /dev/null
+++ b/spec/core/value_spec.moon
@@ -0,0 +1,123 @@
+import Value, Result, Op, Action, Scope from require 'core'
+import Logger from require 'logger'
+Logger.init 'silent'
+
+class TestOp extends Op
+ new: (...) => super ...
+
+class TestAction extends Action
+ new: (...) =>
+
+describe 'Value', ->
+ describe 'wraps', ->
+ test 'numbers', ->
+ got = Value.wrap 3
+ assert.is.equal 'num', got.type
+ assert.is.equal 3, got.value
+
+ test 'strings', ->
+ got = Value.wrap "im a happy string"
+ assert.is.equal 'str', got.type
+ assert.is.equal "im a happy string", got.value
+
+ test 'Values', ->
+ pi = Value 'num', 3.14
+ got = Value.wrap pi
+
+ assert.is.equal pi, got
+
+ test 'Opdefs', ->
+ got = Value.wrap TestOp
+
+ assert.is.equal 'opdef', got.type
+ assert.is.equal TestOp, got.value
+
+ test 'Bultins', ->
+ got = Value.wrap TestAction
+
+ assert.is.equal 'builtin', got.type
+ assert.is.equal TestAction, got.value
+
+ test 'Scopes', ->
+ sub = Scope!
+ got = Value.wrap sub
+
+ assert.is.equal 'scope', got.type
+ assert.is.equal sub, got.value
+
+ test 'tables', ->
+ pi = Value 'num', 3.14
+ got = Value.wrap { :pi }
+
+ assert.is.equal 'scope', got.type
+ assert.is.equal pi, (got.value\get 'pi')\const!
+
+ describe 'unwraps', ->
+ test 'unwrap!', ->
+ assert.is.equal 3.14, (Value.num 3.14)\unwrap!
+ assert.is.equal 'hi', (Value.str 'hi')\unwrap!
+ assert.is.equal 'hi', (Value.sym 'hi')\unwrap!
+
+ test 'with type assert', ->
+ assert.is.equal 3.14, (Value.num 3.14)\unwrap 'num'
+ assert.is.equal 'hi', (Value.str 'hi')\unwrap 'str'
+ assert.is.equal 'hi', (Value.sym 'hi')\unwrap 'sym'
+ assert.has_error -> (Value.num 3.14)\unwrap 'sym'
+ assert.has_error -> (Value.str 'hi')\unwrap 'num'
+ assert.has_error -> (Value.sym 'hi')\unwrap 'str'
+
+ test 'with __call shorthand', ->
+ assert.is.equal 3.14, (Value.num 3.14)!
+ assert.is.equal 'hi', (Value.str 'hi')!
+ assert.is.equal 'hi', (Value.sym 'hi')!
+ assert.is.equal 3.14, (Value.num 3.14) 'num'
+ assert.is.equal 'hi', (Value.str 'hi') 'str'
+ assert.is.equal 'hi', (Value.sym 'hi') 'sym'
+ assert.has_error -> (Value.num 3.14) 'sym'
+ assert.has_error -> (Value.str 'hi') 'num'
+ assert.has_error -> (Value.sym 'hi') 'str'
+
+ describe 'checks equality', ->
+ test 'using the type', ->
+ val = Value 'num', 3
+ assert.is.equal (Value.num 3), val
+ assert.not.equal (Value.str '3'), val
+
+ val = Value 'str', 'hello'
+ assert.is.equal (Value.str 'hello'), val
+ assert.not.equal (Value.sym 'hello'), val
+
+ test 'using the value', ->
+ val = Value 'num', 3
+ assert.is.equal (Value.num 3), val
+ assert.not.equal (Value.num 4), val
+
+ describe 'evaluates literal', ->
+ test 'numbers to consts', ->
+ assert_noop = (val) ->
+ assert.is.equal val, val\eval!\const!
+
+ assert_noop Value.num 2
+ assert_noop Value.str 'hello'
+
+ test 'symbols in the scope', ->
+ scope = with Scope!
+ \set 'number', Result value: Value.num 3
+ \set 'hello', Result value: Value.str "world"
+ \set 'goodbye', Result value: Value.sym "again"
+
+ assert_eval = (sym, val) ->
+ const = Value.sym sym
+ assert.is.equal val, (const\eval scope)\const!
+
+ assert_eval 'number', Value.num 3
+ assert_eval 'hello', Value.str "world"
+ assert_eval 'goodbye', Value.sym "again"
+
+ describe 'quotes literals', ->
+ test 'as themselves', ->
+ assert_noop = (val) -> assert.is.equal val, val\quote!
+
+ assert_noop Value.num 2
+ assert_noop Value.str 'hello'
+ assert_noop Value.sym 'world'