From: Mike Lowis Date: Mon, 22 Feb 2016 17:55:23 +0000 (-0500) Subject: Added preliminary attempt at lua version of rspec tests X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=83478bd7b5448ed49f41fbe39e83d7f8997d8813;p=proto%2Fsclpl.git Added preliminary attempt at lua version of rspec tests --- diff --git a/Makefile b/Makefile index defd536..c28fc43 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,11 @@ ${BIN}: lib${BIN}.a specs: $(BIN) @echo TEST $< - @rspec --pattern 'spec/**{,/*/**}/*_spec.rb' + @rspec --pattern 'spec/**{,/*/**}/*_spec.rb' --format documentation + +lspecs: $(BIN) + @echo TEST $< + @./spec/spec.lua spec/*_spec.lua .l.c: @echo LEX $< diff --git a/spec/lexer_spec.lua b/spec/lexer_spec.lua new file mode 100644 index 0000000..abb835a --- /dev/null +++ b/spec/lexer_spec.lua @@ -0,0 +1,233 @@ +function lexer(input) + return {} +end + +expect = check_equal + +describe "lexer" { + context "punctuation" { + it "should recognize [" (function() + end), + it "should recognize ]" (function() + end), + } +} + +describe "lexer" { + context "punctuation" { + it "should recognize [" (function() + expect(lexer('['), {"T_LBRACK"}) + end), + + it "should recognize ]" (function() + expect(lexer(']'), {"T_RBRACK"}) + end), + + it "should recognize (" (function() + expect(lexer('('), {"T_LPAR"}) + end), + + it "should recognize )" (function() + expect(lexer(')'), {"T_RPAR"}) + end), + + it "should recognize {" (function() + expect(lexer('{'), {"T_LBRACE"}) + end), + + it "should recognize }" (function() + expect(lexer('}'), {"T_RBRACE"}) + end), + + it "should recognize '" (function() + expect(lexer('\''), {"T_SQUOTE"}) + end), + + it "should recognize ," (function() + expect(lexer(','), {"T_COMMA"}) + end), + + it "should recognize ;" (function() + expect(lexer(';'), {"T_END"}) + end), + + it "should recognize all punctuation" (function() + expect(lexer('[](){}\',;'), + {"T_LBRACK", "T_RBRACK", "T_LPAR", "T_RPAR", "T_LBRACE", "T_RBRACE", + "T_SQUOTE", "T_COMMA", "T_END"}) + end), + + it "should recognize [ after an identifier" (function() + expect(lexer('foo['), {"T_ID:foo", "T_LBRACK"}) + end), + + it "should recognize ] after an identifier" (function() + expect(lexer('foo]'), {"T_ID:foo", "T_RBRACK"}) + end), + + it "should recognize ( after an identifier" (function() + expect(lexer("foo("), {"T_ID:foo", "T_LPAR"}) + end), + + it "should recognize ) after an identifier" (function() + expect(lexer("foo)"), {"T_ID:foo", "T_RPAR"}) + end), + + it "should recognize { after an identifier" (function() + expect(lexer('foo{'), {"T_ID:foo", "T_LBRACE"}) + end), + + it "should recognize } after an identifier" (function() + expect(lexer('foo}'), {"T_ID:foo", "T_RBRACE"}) + end), + + it "should recognize } after an identifier" (function() + expect(lexer('foo\''), {"T_ID:foo", "T_SQUOTE"}) + end), + + it "should recognize } after an identifier" (function() + expect(lexer('foo,'), {"T_ID:foo", "T_COMMA"}) + end), + + it "should recognize } after an identifier" (function() + expect(lexer("foo;"), {"T_ID:foo", "T_END"}) + end), + }, + + context "characters" { + it "should recognize space" (function() + expect(lexer("\space"), {'T_CHAR:\space'}) + end), + + it "should recognize newline" (function() + expect(lexer("\newline"), {'T_CHAR:\newline'}) + end), + + it "should recognize return" (function() + expect(lexer("\return"), {'T_CHAR:\return'}) + end), + + it "should recognize tab" (function() + expect(lexer("\tab"), {'T_CHAR:\tab'}) + end), + + it "should recognize vertical tab" (function() + expect(lexer("\vtab"), {'T_CHAR:\vtab'}) + end), + + it "should recognize 'c'" (function() + expect(lexer("\c"), {'T_CHAR:\c'}) + end), + + it "should recognize invalid named characters as identifiers" (function() + expect(lexer("\foobar"), {'T_ID:\foobar'}) + end), + }, + + context "numbers" { + context "integers" { + it "should recognize positive integer without sign" (function() + expect(lexer("123"), {"T_INT:123"}) + end), + + it "should recognize positive integer with sign" (function() + expect(lexer("+123"), {"T_INT:123"}) + end), + + it "should recognize negitve integer with sign" (function() + expect(lexer("-123"), {"T_INT:-123"}) + end), + + it "should recognize invalid ints as identifiers" (function() + expect(lexer("123a"), {"T_ID:123a"}) + end), + }, + + context "radix integers" { + it "should recognize binary integer" (function() + expect(lexer("0b101"), {"T_INT:5"}) + end), + + it "should recognize octal integer" (function() + expect(lexer("0o707"), {"T_INT:455"}) + end), + + it "should recognize decimal integer" (function() + expect(lexer("0d909"), {"T_INT:909"}) + end), + + it "should recognize decimal integer" (function() + expect(lexer("0hf0f"), {"T_INT:3855"}) + end), + + it "should recognize invalid radix ints as identifiers" (function() + expect(lexer("0b012"), {"T_ID:0b012"}) + end), + }, + + context "floating point" { + it "should recognize positive float without sign" (function() + expect(lexer("123.0"), {"T_FLOAT:123.000000"}) + end), + + it "should recognize positive float with sign" (function() + expect(lexer("+123.0"), {"T_FLOAT:123.000000"}) + end), + + it "should recognize negative float with sign" (function() + expect(lexer("-123.0"), {"T_FLOAT:-123.000000"}) + end), + + it "should recognize invalid floats as identifiers" (function() + expect(lexer("123..0"), {"T_ID:123..0"}) + end), + }, + }, + + context "boolean" { + it "should recognize true" (function() + expect(lexer("true"), {"T_BOOL:true"}) + end), + + it "should recognize false" (function() + expect(lexer("false"), {"T_BOOL:false"}) + end), + }, + + context "identifiers" { + it "should recognize an identifier" (function() + expect(lexer("foo"), {"T_ID:foo"}) + end), + }, + + context "strings" { + it "should recognize an empty string" (function() + expect(lexer("\"\""), {"T_STRING:\"\""}) + end), + + it "should recognize a string with one element" (function() + expect(lexer("\"a\""), {"T_STRING:\"a\""}) + end), + + it "should recognize a string with two elements" (function() + expect(lexer("\"ab\""), {"T_STRING:\"ab\""}) + end), + + it "should recognize a string with a space" (function() + expect(lexer("\"a b\""), {"T_STRING:\"a b\""}) + end), + + it "should recognize a string that spans lines" (function() + expect(lexer("\"a\nb\""), {"T_STRING:\"a\nb\""}) + end), + + it "should recognize larger strings" (function() + expect(lexer("\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\""), { + "T_STRING:\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\""}) + end), + + --it "should raise an assertion exception when the file ends before a string terminates" (function() + -- expect{lexer("\"abc")}.to raise_error(/AssertionException/) + --end), + }, +} diff --git a/spec/spec.lua b/spec/spec.lua new file mode 100755 index 0000000..2b115fc --- /dev/null +++ b/spec/spec.lua @@ -0,0 +1,127 @@ +#!/bin/env lua + +AllSpecs = {} +TotalSpecs = 0 +FailedSpecs = 0 +PassedSpecs = 0 +Failures = {} + +-- Spec DSL Definitions +------------------------------------------------------------------------------- +function describe(desc) + return function(specs) + table.insert(AllSpecs, { type = "describe", desc = desc, specs = specs}) + end +end + +function context(desc) + return function(specs) + return { type = "context", desc = desc, specs = specs } + end +end + +function it(desc) + return function(spec) + return { type = "it", desc = desc, spec = spec } + end +end + +-- Test Assertion Functions +------------------------------------------------------------------------------- +function check_nequal(expected, actual) + if (expected == actual) then + error(string.format("Expected %s and %s to differ", tostring(expected), tostring(actual))) + end +end + +function check_equal(expected, actual) + if (expected ~= actual) then + error(string.format("Expected %s, received %s instead", tostring(expected), tostring(actual))) + end +end + +-- Spec Driver Logic +------------------------------------------------------------------------------- +builtin_error = error +function error_wrapper(msg) + builtin_error({msg = msg}) +end + +function parse_stack(errobj) + local lastframe = nil + local level = 1 + while true do + local info = debug.getinfo(level, "nSl") + if not info then break end + if info.name and info.name == "xpcall" then + break + else + lastframe = string.format("%s:%d", info.short_src, info.currentline) + end + level = level + 1 + end + if (type(errobj) == "table") then + return string.format("%s: %s", lastframe, errobj.msg) + else + local fstoccr = errobj:find(":") + local secoccr = errobj:find(":",fstoccr+1) + return string.format("%s: %s", lastframe, errobj:sub(secoccr+2, -1)) + end +end + +function run_spec(spec, depth) + local status, errobj = xpcall(spec.spec, parse_stack) + --local status, errobj = pcall(spec.spec) + if not status then + FailedSpecs = FailedSpecs + 1 + table.insert(Failures, { spec = spec, err = errobj }) + io.write(" (Failed - ", FailedSpecs, ")") + else + PassedSpecs = PassedSpecs + 1 + end + TotalSpecs = TotalSpecs + 1 +end + +function run_specs(specs, depth) + error = error_wrapper + for k,val in ipairs(specs) do + -- Print the description + for i=1, depth do + io.write(" ") + end + io.write(val.desc) + -- Run the test or recursively run the group + if val.type == "it" then + run_spec(val, depth) + io.write("\n") + else + io.write("\n") + run_specs(val.specs, depth+1) + end + end + error = builtin_error +end + +-- Spec Main Routine +------------------------------------------------------------------------------- +(function() + -- Load up the spec files specified on the command line + for k,val in ipairs(arg) do + dofile(val) + end + -- Run all the specs + run_specs(AllSpecs, 0) + -- Print the results + if table.getn(Failures) > 0 then + io.write("\nFailures:\n") + end + for k,val in ipairs(Failures) do + io.write(" ", val.err, "\n") + end + io.write("\nTest Results\n") + io.write("------------\n") + io.write("Total: ", TotalSpecs, "\n") + io.write("Passed: ", PassedSpecs, "\n") + io.write("Failed: ", FailedSpecs, "\n") +end)() +