app/console/testing.rb
the library's own source, console 0.2.0 · back to Console::Test
# Console::Test -- a tiny in-engine test harness. # # Tests run inside the real DragonRuby runtime, so they exercise the actual # renderer, the actual output collections and the actual mruby build rather # than a stand-in. Failures are collected, printed, and summarised in a single # machine-readable line the runner script can grep. # # class MySuite # include Console::Test # # def setup # @thing = [] # end # # test 'does the thing' do # assert_equal 2, @thing.size # end # end # # Each `test` block is evaluated against a fresh instance of the suite, so # `setup` runs first and instance state does not leak between tests. module Console module Test # Populated by the `test` macro; each entry is [suite_class, name, block]. def self.registry @registry ||= [] end def self.clear @registry = [] end # `include Console::Test` gives a suite the class-level `test` macro and # the instance-level assertions. def self.included(base) base.extend ClassLevel end module ClassLevel # Declare a test. Runs against a fresh instance of this suite. def test(name, &block) Console::Test.registry << [self, name.to_s, block] end end # --- assertions ------------------------------------------------------- def assert(condition, message = nil) Console::Test.record condition, message || 'expected condition to be true' end def refute(condition, message = nil) Console::Test.record !condition, message || 'expected condition to be false' end def assert_equal(expected, actual, message = nil) ok = expected == actual msg = message || "expected #{expected.inspect}, got #{actual.inspect}" Console::Test.record ok, msg end def assert_almost_equal(expected, actual, tolerance = 0.001, message = nil) ok = (expected - actual).abs <= tolerance msg = message || "expected #{expected} +/- #{tolerance}, got #{actual}" Console::Test.record ok, msg end def refute_equal(expected, actual, message = nil) ok = expected != actual Console::Test.record ok, message || "expected NOT #{expected.inspect}, got #{actual.inspect}" end def assert_nil(actual, message = nil) Console::Test.record actual.nil?, message || "expected nil, got #{actual.inspect}" end def assert_not_nil(actual, message = nil) Console::Test.record !actual.nil?, message || 'expected non-nil' end def assert_includes(collection, member, message = nil) ok = collection.include? member Console::Test.record ok, message || "expected #{collection.inspect} to include #{member.inspect}" end def refute_includes(collection, member, message = nil) ok = !collection.include?(member) Console::Test.record ok, message || "expected #{collection.inspect} NOT to include #{member.inspect}" end def assert_between(value, low, high, message = nil) ok = value >= low && value <= high Console::Test.record ok, message || "expected #{value} to be within #{low}..#{high}" end def assert_raises(message = nil) raised = false begin yield rescue raised = true end Console::Test.record raised, message || 'expected the block to raise' end # --- running ---------------------------------------------------------- def self.passes @passes ||= 0 end def self.total @total ||= 0 end def self.failures @failures ||= [] end def self.record(ok, message) @passes = passes + (ok ? 1 : 0) @total = total + 1 failures << "[#{@current_suite}##{@current_test}] #{message}" unless ok ok end # Run every registered suite. Returns a summary Hash. def self.run(args = nil) @passes = 0 @total = 0 @failures = [] registry.each do |entry| klass = entry[0] name = entry[1] block = entry[2] @current_suite = klass.to_s @current_test = name begin instance = klass.new instance.setup if instance.respond_to?(:setup) instance.instance_eval(&block) rescue => e @total += 1 @failures << "[#{klass}##{name}] raised #{e.class}: #{e.message}" end end report end def self.report status = @failures.size == 0 ? 'PASS' : 'FAIL' puts '' puts '=' * 62 if status == 'PASS' puts "TEST RESULT: PASS (#{registry.size} tests, #{@passes} assertions)" else puts "TEST RESULT: FAIL (#{@failures.size} failures, #{@passes} passed of #{@total} assertions)" @failures.each { |f| puts " x #{f}" } end puts '=' * 62 { status: status, passes: @passes, failures: @failures.size, total: @total, tests: registry.size } end # One line for a CI script to grep. def self.summary_line(summary) "CONSOLE_TEST_STATUS=#{summary[:status]} " \ "TESTS=#{summary[:tests]} " \ "ASSERTIONS=#{summary[:total]} " \ "FAILURES=#{summary[:failures]}" end end end