]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Added preliminary attempt at lua version of rspec tests
authorMike Lowis <mike.lowis@gentex.com>
Mon, 22 Feb 2016 17:55:23 +0000 (12:55 -0500)
committerMike Lowis <mike.lowis@gentex.com>
Mon, 22 Feb 2016 17:55:23 +0000 (12:55 -0500)
Makefile
spec/lexer_spec.lua [new file with mode: 0644]
spec/spec.lua [new file with mode: 0755]

index defd536fcfea0eaa96a70752efd96a6ad7fb814f..c28fc43f503bacbbc6931a1a384cd9ad7ad8b541 100644 (file)
--- 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 (file)
index 0000000..abb835a
--- /dev/null
@@ -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 (executable)
index 0000000..2b115fc
--- /dev/null
@@ -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)()
+