From df8141c3214a5fb8d447297be64bdf5619b7d8a7 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 28 Feb 2020 13:21:57 +0100 Subject: doc and tag spec --- spec/core/cell_spec.moon | 36 +++++++++++ spec/core/parsing_spec.moon | 146 +++++++++++++++++++++++++++++++++++++++++++ spec/core/registry_spec.moon | 8 +++ spec/core/scope_spec.moon | 114 +++++++++++++++++++++++++++++++++ spec/core/tag_spec.moon | 100 +++++++++++++++++++++++++++++ spec/core/value_spec.moon | 123 ++++++++++++++++++++++++++++++++++++ 6 files changed, 527 insertions(+) create mode 100644 spec/core/cell_spec.moon create mode 100644 spec/core/parsing_spec.moon create mode 100644 spec/core/registry_spec.moon create mode 100644 spec/core/scope_spec.moon create mode 100644 spec/core/tag_spec.moon create mode 100644 spec/core/value_spec.moon (limited to 'spec/core') 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' -- cgit v1.2.3