Sunlight

Sunlight is a minimal Ruby testing library for testing better testing libraries. It doesn’t depend on anything beyond the Ruby platform and doesn’t modify the environment beyond its conventional namespace. The program that tests it is written in primitive Ruby, with no other testing library, so it can be verified straightforwardly.

Here’s an example of a test program that uses Sunlight:

require "sunlight"

exit Sunlight.call STDOUT,
  lambda {
    unless "Hello, World!" == ["He", "", "o, Wor", "d!"].join("l")
      raise "join did not work as expected"
    end
  },
  lambda {
    unless "sample" == "simple".gsub(/i/, "a")
      raise "gsub did not work as expected"
    end
  }

Sunlight.call runs a sequence of tests and reports information about any that fail. It returns false if there were failures, true otherwise.

Sunlight.call expects two things from a test object: that it executes the test when sent a call message and that it returns a description when sent a to_s message. (Procs work well as test objects because they execute when sent a call message and return a description string when sent a to_s message. The description string typically includes the file path and line number where the proc was defined.) A test can signal failure by raising a StandardError.

Sunlight.call uses the output stream (its first parameter) like this: when it encounters a failure, Sunlight.call sends a puts message to the output stream with five positional arguments: (1) “FAILED TEST:”, (2) the test’s description, (3) “…ERROR:”, (4) a description of the exception raised, and (5) an empty string. It ignores the object returned. If you, for example, ran Sunlight.call with the standard output stream (STDOUT or the initial value of $stdout) and a lambda that ran a failing test, the output would resemble this:

FAILED TEST:
#<Proc:0x0000000fe2e010@test.rb:4 (lambda)>
...ERROR:
RuntimeError: join did not work as expected
test.rb:6:in `block in <main>'
[more backtrace lines]
[blank line]

If a test raises a non-StandardError exception, Sunlight.call interprets it as a system-level event or fundamental problem: it immediately raises the exception and doesn’t run any more tests.

Sunlight’s test program loads the Sunlight module if necessary, but does not significantly change the runtime environment beyond that. Your test program can set up the environment it wants to test (plus any test helpers) and execute Sunlight’s test program (with Kernel#load, for example) to check if Sunlight works in that environment. If it detects a problem, it will raise an exception. Otherwise, your program can use Sunlight to run tests – now with more evidence that it works as expected and with no significant changes to the runtime environment.