Lua on Rails

A journey into building a web framework in Lua from scratch that never gets used.


Testing with lspec

Eventually all code becomes so unweildy or complicated that holding it all in your head at any one time becomes impossibe. At that point you make changes or try to implement a complex algorithm and struggle to continue flailing code into the editor. I usually deal with this situation with tests.

Whats available then?

There is actually a lot out there for lua unit testing. Just go checkout the Lua Unit Testing page.

Re-reading and checking out the lists there makes me realize that I could have just used one of the many minimal testing frameworks already written. I mean, telescope looks great!

For reasons only known to a past Jasper I decided to write my own because who doesn't love maintinaing their own code.

Not invented here though

With my seemingly abundance of free time and introverted vision I set about writing lspec. Suspiciously named after rspec, lspec is a minimal testing framework inspired by rspec.

How minimal you ask? lspec is only 37 lines of code (including white space). I'll dump that here for you to have a peek at.

local function build_describer(prefix)
  local prefix = prefix or ""

  local function describe(name, descriptor)
    local errors = {}
    local successes = {}

    function it(spec_line, spec)
      local status = xpcall(spec, function (err)
        table.insert(errors, string.format("\t%s\n\t\t%s\n", spec_line, err))

      if status then
        table.insert(successes, string.format("\t%s\n", spec_line))

    local status = xpcall(descriptor, function (err)
      table.insert(errors, err)
    end, it, build_describer(name))

    print(string.format("%s%s", prefix, name))
    if #errors > 0 then

    if #successes > 0 then

  return describe

return build_describer('')
lspec full code listing. Highlighted with highlight.js

We can use this small library to write tests like so:

local describe = require('lspec');
local require_relative = require('require_relative')
local StringScanner = require_relative('../template/string_scanner.lua')

describe('StringScanner', function (it, describe)
  describe(':finished()', function (it)
    it('should be finished when passed an empty string', function ()
      assert(StringScanner:new(''):finished() == true)

    it('should not be finished when passed a non empty string', function ()
      assert(StringScanner:new('a'):finished() == false)