Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2598db9
Showing
7 changed files
with
435 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,159 @@ | |||
NAME | |||
testy.rb | |||
|
|||
DESCRIPTION | |||
a BDD testing framework for ruby that's mad at the world and plans to kick | |||
it's ass in 78 freakin lines of code | |||
|
|||
SYNOPSIS | |||
Testy.testing 'your code' do | |||
test 'some behaviour' do |result| | |||
ultimate = Ultimate.new | |||
|
|||
result.check :name, :expect => 42, :actual => ultimate.answer | |||
end | |||
end | |||
|
|||
PRINCIPLES AND GOALS | |||
. it.should.not.merely.be.a.unit.testing.with.a.clever.dsl | |||
|
|||
. testing should not require learning a framework. ruby is a great | |||
framework so testy uses it instead, requiring programmers learn exactly 2 | |||
new method calls | |||
|
|||
. testing loc should not dwarf those of the application | |||
|
|||
. testing framework loc should not dwarf those of the application | |||
|
|||
. testing frameworks should *never* alter ruby built-ins nor add methods to | |||
Object, Kernel, .et al | |||
|
|||
. the output of tests should be machine parsable for reporting and ci tools | |||
to easily integrate with | |||
|
|||
. the output of tests should be beautiful so that humans can read it | |||
|
|||
. the shape of the test file should not insult the programmer so that tests | |||
can double as sample code | |||
|
|||
. the testing framework should never alter exception semantics | |||
|
|||
. hi-jacking at_exit sucks ass | |||
|
|||
. the exit status of running a test suite should indicate the degree of it's | |||
failure state: the more failures the higher the exit status | |||
|
|||
. sample code should easily be able to double as a test suite, including | |||
it's output | |||
|
|||
. testing should improve your code and help your users, not make you want to | |||
kill yourself | |||
|
|||
. using a format that aligns in terminal is sanity saving when comparing | |||
output | |||
|
|||
. testing frameworks should provide as few shortcuts for making brittle | |||
tightly coupled tests as possible | |||
|
|||
SAMPLES | |||
|
|||
<========< samples/a.rb >========> | |||
|
|||
~ > cat samples/a.rb | |||
|
|||
# simple use of testy involves simply writing code, and recording the result | |||
# you expect against the actual result | |||
# | |||
# notice that the output is very pretty and that the exitstatus is 0 when all | |||
# tests pass | |||
# | |||
require 'testy' | |||
|
|||
Testy.testing 'the kick-ass-ed-ness of testy' do | |||
|
|||
test 'the ultimate answer to life' do |result| | |||
list = [] | |||
|
|||
list << 42 | |||
result.check :a, :expect => 42, :actual => list.first | |||
|
|||
list << 42.0 | |||
result.check :b, 42.0, list.last | |||
end | |||
|
|||
end | |||
|
|||
~ > ruby samples/a.rb #=> exitstatus=0 | |||
|
|||
--- | |||
the kick-ass-ed-ness of testy: | |||
the ultimate answer to life: | |||
success: | |||
a: 42 | |||
b: 42.0 | |||
|
|||
|
|||
<========< samples/b.rb >========> | |||
|
|||
~ > cat samples/b.rb | |||
|
|||
# testy will handle unexpected results and exceptions thrown in your code in | |||
# exactly the same way - by reporting on them in a beautiful fashion and | |||
# continuing to run other tests. notice, however, that an unexpected result | |||
# or raised exception will cause a non-zero exitstatus (equalling the number | |||
# of failed tests) for the suite as a whole. also note that previously | |||
# accumulate expect/actual pairs are still reported on in the error report. | |||
# | |||
require 'testy' | |||
|
|||
Testy.testing 'the exception handling of testy' do | |||
|
|||
test 'raising an exception' do |result| | |||
list = [] | |||
|
|||
list << 42 | |||
result.check :a, :expect => 42, :actual => list.first | |||
|
|||
list.method_that_does_not_exist | |||
end | |||
|
|||
test 'returning unexpected results' do |result| | |||
result.check 'a', 42, 42 | |||
result.check :b, :expect => 'forty-two', :actual => 42.0 | |||
end | |||
|
|||
end | |||
|
|||
~ > ruby samples/b.rb #=> exitstatus=2 | |||
|
|||
--- | |||
the exception handling of testy: | |||
raising an exception: | |||
failure: | |||
error: | |||
class: NoMethodError | |||
message: undefined method `method_that_does_not_exist' for [42]:Array | |||
bactrace: | |||
- samples/b.rb:18 | |||
- ./lib/testy.rb:63:in `call' | |||
- ./lib/testy.rb:63:in `run' | |||
- /opt/local/lib/ruby/site_ruby/1.8/orderedhash.rb:65:in `each' | |||
- /opt/local/lib/ruby/site_ruby/1.8/orderedhash.rb:65:in `each' | |||
- ./lib/testy.rb:59:in `run' | |||
- ./lib/testy.rb:87:in `testing' | |||
- samples/b.rb:10 | |||
expect: | |||
a: 42 | |||
actual: | |||
a: 42 | |||
returning unexpected results: | |||
failure: | |||
expect: | |||
a: 42 | |||
b: forty-two | |||
actual: | |||
a: 42 | |||
b: 42.0 | |||
|
|||
|
|||
URI |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,59 @@ | |||
NAME | |||
testy.rb | |||
|
|||
DESCRIPTION | |||
a BDD testing framework for ruby that's mad at the world and plans to kick | |||
it's ass in 78 freakin lines of code | |||
|
|||
SYNOPSIS | |||
Testy.testing 'your code' do | |||
test 'some behaviour' do |result| | |||
ultimate = Ultimate.new | |||
|
|||
result.check :name, :expect => 42, :actual => ultimate.answer | |||
end | |||
end | |||
|
|||
PRINCIPLES AND GOALS | |||
. it.should.not.merely.be.a.unit.testing.with.a.clever.dsl | |||
|
|||
. testing should not require learning a framework. ruby is a great | |||
framework so testy uses it instead, requiring programmers learn exactly 2 | |||
new method calls | |||
|
|||
. testing loc should not dwarf those of the application | |||
|
|||
. testing framework loc should not dwarf those of the application | |||
|
|||
. testing frameworks should *never* alter ruby built-ins nor add methods to | |||
Object, Kernel, .et al | |||
|
|||
. the output of tests should be machine parsable for reporting and ci tools | |||
to easily integrate with | |||
|
|||
. the output of tests should be beautiful so that humans can read it | |||
|
|||
. the shape of the test file should not insult the programmer so that tests | |||
can double as sample code | |||
|
|||
. the testing framework should never alter exception semantics | |||
|
|||
. hi-jacking at_exit sucks ass | |||
|
|||
. the exit status of running a test suite should indicate the degree of it's | |||
failure state: the more failures the higher the exit status | |||
|
|||
. sample code should easily be able to double as a test suite, including | |||
it's output | |||
|
|||
. testing should improve your code and help your users, not make you want to | |||
kill yourself | |||
|
|||
. using a format that aligns in terminal is sanity saving when comparing | |||
output | |||
|
|||
. testing frameworks should provide as few shortcuts for making brittle | |||
tightly coupled tests as possible | |||
|
|||
SAMPLES | |||
@samples |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,38 @@ | |||
#! /usr/bin/env gem build | |||
|
|||
lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2 | |||
|
|||
require 'rubygems' | |||
|
|||
Gem::Specification::new do |spec| | |||
$VERBOSE = nil | |||
|
|||
shiteless = lambda do |list| | |||
list.delete_if do |file| | |||
file =~ %r/\.svn/ or | |||
file =~ %r/\.tmp/ | |||
end | |||
end | |||
|
|||
spec.name = lib | |||
spec.version = version | |||
spec.platform = Gem::Platform::RUBY | |||
spec.summary = lib | |||
|
|||
spec.files = shiteless[Dir::glob("**/**")] | |||
spec.executables = shiteless[Dir::glob("bin/*")].map{|exe| File::basename exe} | |||
|
|||
spec.require_path = "lib" | |||
|
|||
spec.has_rdoc = true # File::exist?("doc") | |||
spec.test_suite_file = "test/#{ lib }.rb" if File::file?("test/#{ lib }.rb") | |||
#spec.add_dependency 'lib', '>= version' | |||
#spec.add_dependency 'fattr' | |||
|
|||
spec.extensions << "extconf.rb" if File::exists? "extconf.rb" | |||
|
|||
spec.rubyforge_project = 'codeforpeople' | |||
spec.author = "Ara T. Howard" | |||
spec.email = "ara.t.howard@gmail.com" | |||
spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/" | |||
end |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,43 @@ | |||
#! /usr/bin/env ruby | |||
|
|||
require 'pathname' | |||
|
|||
$VERBOSE=nil | |||
|
|||
def indent s, n = 2 | |||
ws = ' ' * n | |||
s.gsub %r/^/, ws | |||
end | |||
|
|||
template = IO::read 'README.tmpl' | |||
|
|||
samples = '' | |||
prompt = '~ > ' | |||
|
|||
Dir['sample*/*'].sort.each do |sample| | |||
samples << "\n" << " <========< #{ sample } >========>" << "\n\n" | |||
|
|||
cmd = "cat #{ sample }" | |||
samples << indent(prompt + cmd, 2) << "\n\n" | |||
samples << indent(`#{ cmd }`, 4) << "\n" | |||
|
|||
cmd = "ruby #{ sample }" | |||
#samples << indent(prompt + cmd, 2) << "\n\n" | |||
|
|||
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'" | |||
out = `#{ cmd } 2>&1` | |||
#samples << indent(`#{ cmd } 2>&1`, 4) << "\n" | |||
|
|||
exitstatus = " #=> exitstatus=#{ $?.exitstatus }" | |||
cmd = "ruby #{ sample }" | |||
samples << indent(prompt + cmd + exitstatus, 2) << "\n\n" | |||
samples << indent(out, 4) << "\n" | |||
|
|||
#samples << indent("\n#{ prompt } #{ $?.exitstatus } ### exitstatus\n") | |||
end | |||
|
|||
#samples.gsub! %r/^/, ' ' | |||
|
|||
readme = template.gsub %r/^\s*@samples\s*$/, samples | |||
open('README', 'w'){|fd| fd.write readme} | |||
print readme |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,89 @@ | |||
require 'rubygems' | |||
require 'orderedhash' | |||
require 'yaml' | |||
|
|||
module Testy | |||
class Test | |||
class BadResult < StandardError | |||
end | |||
|
|||
class OrderedHash < ::OrderedHash | |||
def with_string_keys | |||
oh = self.class.new | |||
each_pair{|key, val| oh[key.to_s] = val} | |||
oh | |||
end | |||
end | |||
|
|||
class Result | |||
attr_accessor :expect | |||
attr_accessor :actual | |||
|
|||
def initialize | |||
@expect = OrderedHash.new | |||
@actual = OrderedHash.new | |||
end | |||
|
|||
def check(name, *args) | |||
options = args.last.is_a?(Hash) ? args.pop : {} | |||
value = args.size==0 ? (options[:expect]||options['expect']) : args.shift | |||
expect[name.to_s] = value | |||
value = args.size==0 ? (options[:actual]||options['actual']) : args.shift | |||
actual[name.to_s] = value | |||
end | |||
|
|||
def ok? | |||
expect == actual | |||
end | |||
end | |||
|
|||
attr_accessor :name | |||
attr_accessor :tests | |||
attr_accessor :block | |||
|
|||
def initialize(*args, &block) | |||
options = args.last.is_a?(Hash) ? args.pop : {} | |||
@name = args.first || options[:name] || options['name'] | |||
@tests = OrderedHash.new | |||
@block = block | |||
end | |||
|
|||
def test(name, &block) | |||
@tests[name.to_s] = block | |||
end | |||
|
|||
def run port = STDOUT | |||
instance_eval(&@block) if @block | |||
report = OrderedHash.new | |||
status = 0 | |||
tests.each do |name, block| | |||
result = Result.new | |||
report[name] = | |||
begin | |||
block.call(result) | |||
raise BadResult, name unless result.ok? | |||
{'success' => result.actual} | |||
rescue Object => e | |||
status += 1 | |||
failure = OrderedHash.new | |||
unless e.is_a?(BadResult) | |||
error = OrderedHash.new | |||
error['class'] = e.class.name | |||
error['message'] = e.message.to_s | |||
error['bactrace'] = e.backtrace||[] | |||
failure['error'] = error | |||
end | |||
failure['expect'] = result.expect | |||
failure['actual'] = result.actual | |||
{'failure' => failure} | |||
end | |||
end | |||
port << {name => report}.to_yaml | |||
exit(status) | |||
end | |||
end | |||
|
|||
def Testy.testing(*args, &block) | |||
Test.new(*args, &block).run | |||
end | |||
end |
Oops, something went wrong.