Created
August 19, 2009 02:04
-
-
Save jarib/170109 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# simpletester.rb | |
# | |
# Created by Jari Bakken on 2009-08-19. | |
# Copyright 2009 Jari Bakken. All rights reserved. | |
# | |
require "rubygems" | |
require "json" | |
require "erb" | |
module QA | |
module SimpleTester | |
class AbstractFormatter | |
def begin; end | |
def begin_object(o); end | |
def begin_assert(e, o); end | |
def assertion(a); end | |
def finish_assert; end | |
def finish_object; end | |
def finish; end | |
end | |
class TextFormatter < AbstractFormatter | |
def begin(expectations) | |
$stdout.sync = true | |
end | |
def begin_object(obj) | |
@object = obj | |
@indent = "\t" | |
end | |
def begin_assert(expectation, obj) | |
@expectation = expectation | |
print "#{@indent}. " | |
end | |
def finish_object | |
@indent = "" | |
puts(@failed ? "[ FAIL ] #{@object}" : "[ PASS ] #{@object}") | |
end | |
def assertion(assertion) | |
@assertion_counter += 1 | |
if assertion.failed? | |
@failure_counter += 1 | |
@failed = true | |
puts "#{@indent}not ok! #{@expectation.description}. (#{assertion.expected.inspect} != #{assertion.actual.inspect})" | |
else | |
puts "#{@indent}ok #{@expectation.description}." | |
end | |
end | |
end | |
class JsonFormatter < AbstractFormatter | |
def begin(*args) | |
@result = {} | |
end | |
def begin_object(o) | |
@object = o | |
@result[o] = [] | |
end | |
def begin_assert(e, o) | |
end | |
def assertion(a) | |
@result[@object] << a | |
end | |
def finish_assert; end | |
def finish_object; end | |
def finish | |
puts @result.to_json | |
end | |
end | |
class PjsonFormatter < JsonFormatter | |
def finish; puts JSON.pretty_generate(@result); end | |
end | |
class HtmlFormatter < AbstractFormatter | |
def begin(expectations) | |
puts ERB.new(<<-HTML, 0, "%-<>").result(binding) | |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" | |
"http://www.w3.org/TR/html4/strict.dtd"> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<title>QA::SimpleTester</title> | |
<style type="text/css" media="screen"> | |
.pass { background-color: green;} | |
.fail { background-color: red;} | |
</style> | |
</head> | |
<body> | |
<table border="0"> | |
<tr> | |
<th>Resource</th> | |
<%- expectations.each do |exp| -%> | |
<th><%= exp.description %></th> | |
<%- end -%> | |
</tr> | |
HTML | |
end | |
def begin_object(o) | |
puts "<tr><td>%s</td>" % escape_html(o.to_s) | |
end | |
def begin_assert(e, o); end | |
def assertion(a) | |
if a.failed? | |
class_name = 'fail' | |
content = "<em>expected:</em> %s<hr><em>actual:</em> %s" % [a.expected, a.actual].map { |e| escape_html(e.inspect) } | |
else | |
class_name = 'pass' | |
content = escape_html(a.actual.inspect) | |
end | |
puts '<td class="%s">%s</td>' % [class_name, content] | |
end | |
def finish_assert; end | |
def finish_object | |
puts "</tr>" | |
end | |
def finish | |
puts <<-HTML | |
</table> | |
</body> | |
</html> | |
HTML | |
end | |
private | |
def escape_html(str) | |
str.gsub("<", '<').gsub(">", '>') | |
end | |
end | |
class Expectation | |
attr_reader :description, :expected, :actual | |
def initialize(description) | |
@description = description | |
end | |
def block=(blk) | |
if @block | |
raise "tried to assign block to alrady defined expectation, make sure each expectation has a description" | |
end | |
@block = blk | |
self | |
end | |
def to_be(obj) | |
@expected = obj | |
end | |
def test(obj) | |
@actual = @block.call(obj) | |
@failed = @expected != @actual | |
self | |
end | |
def failed? | |
@failed == true | |
end | |
def to_json(*args) | |
{ | |
:expected => @expected, | |
:actual => @actual, | |
:failed => @failed, | |
:description => @description | |
}.to_json(*args) | |
end | |
end | |
class << self | |
def set(key, value) | |
options[key] = value | |
end | |
def run! | |
validate_data_source | |
validate_formatter | |
test_expectations | |
end | |
def desc(str) | |
expectations << (e = Expectation.new(str)) | |
self | |
end | |
def expect(&blk) | |
e = expectations.last | |
e.block = blk | |
e | |
end | |
private | |
def validate_data_source | |
unless options[:data_source] | |
raise "no :data_source" | |
end | |
unless options[:data_source].respond_to?(:each) | |
raise "invalid :data_source (must respond to `each')" | |
end | |
end | |
def validate_formatter | |
formatter_name = "#{options[:output_format].to_s.capitalize}Formatter" | |
@formatter = const_get(formatter_name).new | |
rescue NameError | |
raise "invalid :output_format (#{options[:output_format].inspect}) - #{self.name}::#{formatter_name} not found" | |
end | |
def options | |
@options ||= default_options | |
end | |
def expectations | |
@expectations ||= [] | |
end | |
def results | |
@results ||= {} | |
end | |
def test_expectations | |
@formatter.begin(expectations) | |
options[:data_source].each do |obj| | |
@formatter.begin_object(obj) | |
run_expectations_with obj | |
@formatter.finish_object | |
end | |
@formatter.finish | |
end | |
def run_expectations_with(obj) | |
results[obj] = expectations.map do |expectation| | |
@formatter.begin_assert(expectation, obj) | |
@formatter.assertion expectation.test(obj) | |
@formatter.finish_assert | |
end | |
end | |
def default_options | |
{ | |
:output_format => :text | |
} | |
end | |
end | |
module Delegator | |
def set(key, value); QA::SimpleTester.set(key, value); end | |
def expect(&blk); QA::SimpleTester.expect(&blk); end | |
def desc(string); QA::SimpleTester.desc(string); end | |
end | |
end | |
at_exit { QA::SimpleTester.run! } | |
end | |
require "ostruct" | |
class DummyResourceFinder | |
def initialize(args) | |
end | |
def each(&blk) | |
data = [ | |
OpenStruct.new(:path => "/foo/bar", :content_type => "application/xml", :well_formed? => true, :content_encoding => "UTF-8", :xml_declaration_encoding => "UTF-8"), | |
OpenStruct.new(:path => "/bar/baz", :content_type => "application/f.xml", :well_formed? => true, :content_encoding => "UTF-8", :xml_declaration_encoding => "ISO-8859-1"), | |
] | |
data.each do |item| | |
item.instance_eval do | |
def to_s | |
"<RestResource #{path}>" | |
end | |
end | |
yield item | |
end | |
end | |
end | |
# test script | |
include QA::SimpleTester::Delegator | |
set :data_source , DummyResourceFinder.new(ARGV) # must repond to each | |
set :output_format, :html | |
desc 'XML has correct Content-Type' | |
expect { |rest| rest.content_type }.to_be 'application/xml' | |
desc 'XML is well formed' | |
expect { |rest| rest.well_formed? }.to_be true | |
desc 'XML has correct Content-Encoding' | |
expect { |rest| rest.content_encoding }.to_be "UTF-8" | |
desc 'XML has correct XML declaration encoding' | |
expect { |rest| rest.xml_declaration_encoding }.to_be "UTF-8" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment