test-spec-0.10.0/0000755000175000017500000000000011635746741013073 5ustar boutilboutiltest-spec-0.10.0/SPECS0000644000175000017500000000546411635746741013704 0ustar boutilboutil == TestUnit * still works on its own * supports should good enough * works inside test/spec == CustomTestUnitSubclass * truth == test/spec * has should.satisfy * has should.equal * has should.raise * has should.raise with a block * should.raise should return the exception * has should.be.an.instance_of * has should.be.nil * has should.include * has should.be.a.kind_of * has should.match * has should.be * has should.not.raise * has should.not.satisfy * has should.not.be * has should.not.equal * has should.not.match * has should.throw * has should.not.throw * has should.respond_to * has should.be_close * multiple negation works * has should. * has should.? * has should (>, >=, <, <=, ===) * is robust against careless users * should detect warnings * should message/blame faults * should allow for custom shoulds * disabled specification (disabled) * empty specification (disabled) === more disabled * this is intentional (disabled) * an empty specification (empty) ==== even more disabled * we can cut out (disabled) * entire contexts, now (disabled) == setup/teardown * run in the right order == before all * runs parent before all == nested teardown === nested * should call local teardown then parent teardown == before all === nested * should call parent then local == after all === after nested * should call local then parent == contexts * are defined in class scope * can include modules == contexts with subclasses * use the supplied class as the superclass * truth == xcontexts with subclasses * work great! (disabled) * truth == Shared contexts * can be included several times * can include other shared contexts * can be included several times * can include other shared contexts * can be nested * can access data * should raise when the context cannot be found == SpecDox * can unmangle Test::Unit names correctly * can unmangle Test::Spec names correctly * has sensible fallbacks == flexmock * can not be found. BAIL OUT! (empty) == mocha * can not be found. BAIL OUT! (empty) == Outer context === Inner context * is nested (empty) * has multiple empty specifications (empty) === Second Inner context * is indented properly (empty) * still runs in order of definition (empty) ==== Inmost context * works too! (empty) * whoo! (empty) == A new-style description * should run before-clauses * should behave like context/specify * this is disabled (disabled) * should raise on unimplement{ed,able} before/after * should work as well with shared descriptions === when nested * should work == An disabled description * should not be run (disabled) == should.output * works for print * works for puts * works with readline == Context First * runs before Second == Context Second * runs before Last == Context Last * runs last 80 specifications, 8 disabled, 9 empty (602 requirements), 0 failures test-spec-0.10.0/examples/0000755000175000017500000000000011635746741014711 5ustar boutilboutiltest-spec-0.10.0/examples/stack_spec.rb0000644000175000017500000000505011635746741017355 0ustar boutilboutil# Copied with minor code changes (should_xxx -> should.xxx) from RSpec. require File.dirname(__FILE__) + '/../lib/test/spec' require File.dirname(__FILE__) + "/stack" context "A stack (in general)" do setup do @stack = Stack.new ["a","b","c"].each { |x| @stack.push x } end specify "should add to the top when sent 'push'" do @stack.push "d" @stack.peek.should.equal "d" end specify "should return the top item when sent 'peek'" do @stack.peek.should.equal "c" end specify "should NOT remove the top item when sent 'peek'" do @stack.peek.should.equal "c" @stack.peek.should.equal "c" end specify "should return the top item when sent 'pop'" do @stack.pop.should.equal "c" end specify "should remove the top item when sent 'pop'" do @stack.pop.should.equal "c" @stack.pop.should.equal "b" end end context "An empty stack" do setup do @stack = Stack.new end specify "should be empty" do @stack.should.be.empty end specify "should no longer be empty after 'push'" do @stack.push "anything" @stack.should.not.be.empty end specify "should complain when sent 'peek'" do lambda { @stack.peek }.should.raise StackUnderflowError end specify "should complain when sent 'pop'" do lambda { @stack.pop }.should.raise StackUnderflowError end end context "An almost empty stack (with one item)" do setup do @stack = Stack.new @stack.push 3 end specify "should not be empty" do @stack.should.not.be.empty end specify "should remain not empty after 'peek'" do @stack.peek @stack.should.not.be.empty end specify "should become empty after 'pop'" do @stack.pop @stack.should.be.empty end end context "An almost full stack (with one item less than capacity)" do setup do @stack = Stack.new (1..9).each { |i| @stack.push i } end specify "should not be full" do @stack.should.not.be.full end specify "should become full when sent 'push'" do @stack.push Object.new @stack.should.be.full end end context "A full stack" do setup do @stack = Stack.new (1..10).each { |i| @stack.push i } end specify "should be full" do @stack.should.be.full end specify "should remain full after 'peek'" do @stack.peek @stack.should.be.full end specify "should no longer be full after 'pop'" do @stack.pop @stack.should.not.be.full end specify "should complain on 'push'" do lambda { @stack.push Object.new }.should.raise StackOverflowError end end test-spec-0.10.0/examples/stack.rb0000644000175000017500000000105711635746741016346 0ustar boutilboutil# Copied without code changes from RSpec. class StackUnderflowError < RuntimeError end class StackOverflowError < RuntimeError end class Stack def initialize @items = [] end def push object raise StackOverflowError if @items.length == 10 @items.push object end def pop raise StackUnderflowError if @items.empty? @items.delete @items.last end def peek raise StackUnderflowError if @items.empty? @items.last end def empty? @items.empty? end def full? @items.length == 10 end end test-spec-0.10.0/metadata.yml0000644000175000017500000000361111635746741015377 0ustar boutilboutil--- !ruby/object:Gem::Specification name: test-spec version: !ruby/object:Gem::Version version: 0.10.0 platform: ruby authors: - Christian Neukirchen autorequire: bindir: bin cert_chain: [] date: 2009-02-01 00:00:00 +01:00 default_executable: dependencies: [] description: test/spec layers an RSpec-inspired interface on top of Test::Unit, so you can mix TDD and BDD (Behavior-Driven Development). test/spec is a clean-room implementation that maps most kinds of Test::Unit assertions to a `should'-like syntax. email: chneukirchen@gmail.com executables: - specrb extensions: [] extra_rdoc_files: - README - SPECS - ROADMAP files: - bin/specrb - examples/stack.rb - examples/stack_spec.rb - lib/test/spec/dox.rb - lib/test/spec/rdox.rb - lib/test/spec/should-output.rb - lib/test/spec/version.rb - lib/test/spec.rb - Rakefile - README - ROADMAP - test/spec_dox.rb - test/spec_flexmock.rb - test/spec_mocha.rb - test/spec_nestedcontexts.rb - test/spec_new_style.rb - test/spec_should-output.rb - test/spec_testspec.rb - test/spec_testspec_order.rb - test/test_testunit.rb - TODO - SPECS has_rdoc: true homepage: http://test-spec.rubyforge.org post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: "0" version: required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: "0" version: requirements: [] rubyforge_project: test-spec rubygems_version: 1.3.1 signing_key: specification_version: 2 summary: a Behaviour Driven Development interface for Test::Unit test_files: - test/test_testunit.rb - test/spec_dox.rb - test/spec_flexmock.rb - test/spec_mocha.rb - test/spec_nestedcontexts.rb - test/spec_new_style.rb - test/spec_should-output.rb - test/spec_testspec.rb - test/spec_testspec_order.rb test-spec-0.10.0/test/0000755000175000017500000000000011635746741014052 5ustar boutilboutiltest-spec-0.10.0/test/spec_should-output.rb0000644000175000017500000000123611635746741020247 0ustar boutilboutil$: << File.dirname(__FILE__) + '/../lib/' require 'test/spec' require 'test/spec/should-output' context "should.output" do specify "works for print" do lambda { print "foo" }.should.output "foo" lambda { print "foo" }.should.output(/oo/) end specify "works for puts" do lambda { puts "foo" }.should.output "foo\n" lambda { puts "foo" }.should.output(/foo/) end specify "works with readline" do lambda { require 'readline' }.should.not.raise(LoadError) lambda { puts "foo" }.should.output "foo\n" lambda { puts "foo" }.should.output(/foo/) File.should.not.exist(File.join(Dir.tmpdir, "should_output_#{$$}")) end end test-spec-0.10.0/test/spec_flexmock.rb0000644000175000017500000001165411635746741017230 0ustar boutilboutil# Adapted from flexmock (http://onestepback.org/software/flexmock). # # Copyright 2006 by Jim Weirich (jweirich@one.net). # All rights reserved. # Permission is granted for use, copying, modification, distribution, # and distribution of modified versions of this work as long as the # above copyright notice is included. require 'test/spec' begin require 'flexmock' rescue LoadError context "flexmock" do specify "can not be found. BAIL OUT!" do end end else context "flexmock" do include FlexMock::TestCase setup do @mock = FlexMock.new end specify "should receive and return" do args = nil @mock.should_receive(:hi).and_return { |a, b| args = [a,b] } @mock.hi(1,2) args.should.equal [1,2] end specify "should receive without a block" do lambda { @mock.should_receive(:blip) @mock.blip }.should.not.raise end specify "should receive and return with a block" do called = false @mock.should_receive(:blip).and_return { |block| block.call } @mock.blip { called = true } called.should.be true end specify "should have a return value" do @mock.should_receive(:blip).and_return { 10 } @mock.blip.should.equal 10 end specify "should handle missing methods" do ex = lambda { @mock.not_defined }.should.raise(NoMethodError) ex.message.should.match(/not_defined/) end specify "should ignore missing methods" do lambda { @mock.should_ignore_missing @mock.blip }.should.not.raise end specify "should count correctly" do @mock.should_receive(:blip).times(3) @mock.blip @mock.blip @mock.blip lambda { @mock.flexmock_verify }.should.not.raise Test::Unit::AssertionFailedError end specify "should raise on bad counts" do @mock.should_receive(:blip).times(3) @mock.blip @mock.blip lambda { @mock.flexmock_verify }.should.raise Test::Unit::AssertionFailedError end specify "should handle undetermined counts" do lambda { FlexMock.use('fs') { |m| m.should_receive(:blip) m.blip m.blip m.blip } }.should.not.raise Test::Unit::AssertionFailedError end specify "should handle zero counts" do lambda { FlexMock.use { |m| m.should_receive(:blip).never m.blip } }.should.raise Test::Unit::AssertionFailedError end specify "should have file IO with use" do file = FlexMock.use do |m| filedata = ["line 1", "line 2"] m.should_receive(:gets).times(3).and_return { filedata.shift } count_lines(m).should.equal 2 end end def count_lines(stream) result = 0 while line = stream.gets result += 1 end result end specify "should have use" do lambda { FlexMock.use do |m| m.should_receive(:blip).times(2) m.blip end }.should.raise Test::Unit::AssertionFailedError end specify "should handle failures during use" do ex = lambda { FlexMock.use do |m| m.should_receive(:blip).times(2) xyz end }.should.raise NameError ex.message.should.match(/undefined local variable or method/) end specify "should deal with sequential values" do values = [1,4,9,16] @mock.should_receive(:get).and_return { values.shift } @mock.get.should.equal 1 @mock.get.should.equal 4 @mock.get.should.equal 9 @mock.get.should.equal 16 end specify "respond_to? should return false for non handled methods" do @mock.should.not.respond_to :blah end specify "respond_to? should return true for explicit methods" do @mock.should_receive(:xyz) @mock.should.respond_to :xyz end specify "respond_to? should return true for missing_methods when should_ignore_missing" do @mock.should_ignore_missing @mock.should.respond_to :yada end specify "should raise error on unknown method proc" do lambda { @mock.method(:xyzzy) }.should.raise NameError end specify "should return callable proc on method" do got_it = false @mock.should_receive(:xyzzy).and_return { got_it = true } method_proc = @mock.method(:xyzzy) method_proc.should.not.be.nil method_proc.call got_it.should.be true end specify "should return do nothing proc for missing methods" do @mock.should_ignore_missing method_proc = @mock.method(:plugh) method_proc.should.not.be.nil lambda { method_proc.call }.should.not.raise end end class TemperatureSampler def initialize(sensor) @sensor = sensor end def average_temp total = (0...3).collect { @sensor.read_temperature }.inject { |i, s| i + s } total / 3.0 end end context "flexmock" do include FlexMock::TestCase specify "works with test/spec" do sensor = flexmock("temp") sensor.should_receive(:read_temperature).times(3).and_return(10, 12, 14) sampler = TemperatureSampler.new(sensor) sampler.average_temp.should.equal 12 end end end # if not rescue LoadError test-spec-0.10.0/test/spec_dox.rb0000644000175000017500000000246111635746741016206 0ustar boutilboutilrequire 'test/spec' require 'test/spec/dox' context "SpecDox" do setup do r = Test::Unit::UI::SpecDox::TestRunner.new(nil) @unmangler = r.method(:unmangle) end specify "can unmangle Test::Unit names correctly" do @unmangler["test_foo_bar(TestFoo)"].should.equal ["Foo", "foo bar"] @unmangler["test_foo_bar(FooTest)"].should.equal ["Foo", "foo bar"] @unmangler["test_he_he(Foo)"].should.equal ["Foo", "he he"] @unmangler["test_heh(Foo)"].should.equal ["Foo", "heh"] @unmangler["test_heh(Test::Unit::TC_Assertions)"]. should.equal ["Test::Unit::TC_Assertions", "heh"] @unmangler["test_heh(Foo::Bar::Test)"]. should.equal ["Foo::Bar::Test", "heh"] end specify "can unmangle Test::Spec names correctly" do @unmangler["test_spec {context} 007 [whee]()"]. should.equal ["context", "whee"] @unmangler["test_spec {a bit longish context} 069 [and more text]()"]. should.equal ["a bit longish context", "and more text"] @unmangler["test_spec {special chars !\"/&%$} 2 [special chars !\"/&%$]()"]. should.equal ["special chars !\"/&%$", "special chars !\"/&%$"] @unmangler["test_spec {[]} 666666 [{}]()"]. should.equal ["[]", "{}"] end specify "has sensible fallbacks" do @unmangler["weird"].should.equal [nil, nil] end end test-spec-0.10.0/test/spec_mocha.rb0000644000175000017500000000516111635746741016503 0ustar boutilboutil# Adapted from mocha (http://mocha.rubyforge.org/). # # Copyright (C) 2006 Revieworld Ltd. # # You may use, copy and redistribute this library under the same terms # as Ruby itself (see www.ruby-lang.org/en/LICENSE.txt) or under the # MIT license (see MIT-LICENSE file). require 'test/spec' begin require 'mocha' rescue LoadError context "mocha" do specify "can not be found. BAIL OUT!" do end end else context "mocha" do specify "works with test/spec" do object = mock() object.expects(:expected_method).with(:p1, :p2).returns(:result) object.expected_method(:p1, :p2).should.equal :result end end class Enterprise def initialize(dilithium) @dilithium = dilithium end def go(warp_factor) warp_factor.times { @dilithium.nuke(:anti_matter) } end end context "mocha" do specify "works with test/spec and Enterprise example" do dilithium = mock() dilithium.expects(:nuke).with(:anti_matter).at_least_once # auto-verified at end of test enterprise = Enterprise.new(dilithium) enterprise.go(2) end end class Order attr_accessor :shipped_on def total_cost line_items.inject(0) { |total, line_item| total + line_item.price } + shipping_cost end def total_weight line_items.inject(0) { |total, line_item| total + line_item.weight } end def shipping_cost total_weight * 5 + 10 end class << self def find_all # Database.connection.execute('select * from orders... end def number_shipped_since(date) find_all.select { |order| order.shipped_on > date }.size end def unshipped_value find_all.inject(0) { |total, order| order.shipped_on ? total : total + order.total_cost } end end end context "stubba" do specify "works with test/spec and instance method stubbing" do order = Order.new order.stubs(:total_weight).returns(10) order.shipping_cost.should.equal 60 end specify "works with test/spec and class method stubbing" do now = Time.now; week_in_secs = 7 * 24 * 60 * 60 order_1 = Order.new; order_1.shipped_on = now - 1 * week_in_secs order_2 = Order.new; order_2.shipped_on = now - 3 * week_in_secs Order.stubs(:find_all).returns([order_1, order_2]) Order.number_shipped_since(now - 2 * week_in_secs).should.equal 1 end specify "works with test/spec and global instance method stubbing" do Order.stubs(:find_all).returns([Order.new, Order.new, Order.new]) Order.any_instance.stubs(:shipped_on).returns(nil) Order.any_instance.stubs(:total_cost).returns(10) Order.unshipped_value.should.equal 30 end end end # if not rescue LoadError test-spec-0.10.0/test/test_testunit.rb0000644000175000017500000000070511635746741017317 0ustar boutilboutilrequire 'test/spec' class TestTestUnit < Test::Unit::TestCase def test_still_works_on_its_own assert_equal 1, 1 assert_raise(RuntimeError) { raise "Error" } end def test_supports_should_good_enough (2 + 3).should.be 5 lambda { raise "Error" }.should.raise assert true end end context "TestUnit" do specify "works inside test/spec" do assert_equal 1, 1 assert_raise(RuntimeError) { raise "Error" } end end test-spec-0.10.0/test/spec_new_style.rb0000644000175000017500000000247411635746741017431 0ustar boutilboutildescribe_shared "A new-style shared description" do it "should work as well with shared descriptions" do true.should.be true end end describe "A new-style description" do before do @before = true @a = 2 end before(:each) do @before_each = true end before(:all) do $before_all = true end it "should run before-clauses" do $before_all.should.be true @before.should.be true @before_each.should.be true end it "should behave like context/specify" do (1+1).should.equal 2 end xit "this is disabled" do bla end after do @a.should.equal 2 @a = 3 end after(:each) do @a.should.equal 3 end after(:all) do @b = 1 end after(:all) do @b.should.equal 1 end $describescope = self it "should raise on unimplement{ed,able} before/after" do lambda { $describescope.before(:foo) {} }.should.raise(ArgumentError) lambda { $describescope.after(:foo) {} }.should.raise(ArgumentError) lambda { context "foo" do end }.should.raise(Test::Spec::DefinitionError) end describe "when nested" do it "should work" do end end behaves_like "A new-style shared description" end describe "An empty description" do end xdescribe "An disabled description" do it "should not be run" end test-spec-0.10.0/test/spec_testspec.rb0000644000175000017500000004376211635746741017257 0ustar boutilboutil$: << File.dirname(__FILE__) + '/../lib/' require 'test/spec' $WARNING = "" class Object def warn(msg) $WARNING << msg.to_s super msg end end class Test::Spec::Should def _warn _wrap_assertion { begin old, $-w = $-w, nil $WARNING = "" self.not.raise $WARNING.should.blaming("no warning printed").not.be.empty ensure $-w = old end } end end # Hooray for meta-testing. module MetaTests class ShouldFail < Test::Spec::CustomShould def initialize end def assumptions(block) block.should.raise(Test::Unit::AssertionFailedError) end def failure_message "Block did not fail." end end class ShouldSucceed < Test::Spec::CustomShould def initialize end def assumptions(block) block.should.not.raise(Test::Unit::AssertionFailedError) end def failure_message "Block raised Test::Unit::AssertionFailedError." end end class ShouldBeDeprecated < Test::Spec::CustomShould def initialize end def assumptions(block) block.should._warn $WARNING.should =~ /deprecated/ end def failure_message "warning was not a deprecation" end end def fail ShouldFail.new end def succeed ShouldSucceed.new end def deprecated ShouldBeDeprecated.new end end module TestShoulds class EmptyShould < Test::Spec::CustomShould end class EqualString < Test::Spec::CustomShould def matches?(other) object == other.to_s end end class EqualString2 < Test::Spec::CustomShould def matches?(other) object == other.to_s end def failure_message "yada yada yada" end end def empty_should(obj) EmptyShould.new(obj) end def equal_string(str) EqualString.new(str) end def equal_string2(str) EqualString2.new(str) end end context "test/spec" do include MetaTests specify "has should.satisfy" do lambda { should.satisfy { 1 == 1 } }.should succeed lambda { should.satisfy { 1 } }.should succeed lambda { should.satisfy { 1 == 2 } }.should fail lambda { should.satisfy { false } }.should fail lambda { should.satisfy { false } }.should fail lambda { 1.should.satisfy { |n| n % 2 == 0 } }.should fail lambda { 2.should.satisfy { |n| n % 2 == 0 } }.should succeed end specify "has should.equal" do lambda { "string1".should.equal "string1" }.should succeed lambda { "string1".should.equal "string2" }.should fail lambda { "1".should.equal 1 }.should fail lambda { "string1".should == "string1" }.should succeed lambda { "string1".should == "string2" }.should fail lambda { "1".should == 1 }.should fail end specify "has should.raise" do lambda { lambda { raise "Error" }.should.raise }.should succeed lambda { lambda { raise "Error" }.should.raise RuntimeError }.should succeed lambda { lambda { raise "Error" }.should.not.raise }.should fail lambda { lambda { raise "Error" }.should.not.raise(RuntimeError) }.should fail lambda { lambda { 1 + 1 }.should.raise }.should fail lambda { lambda { raise "Error" }.should.raise(Interrupt) }.should fail end specify "has should.raise with a block" do lambda { should.raise { raise "Error" } }.should succeed lambda { should.raise(RuntimeError) { raise "Error" } }.should succeed lambda { should.not.raise { raise "Error" } }.should fail lambda { should.not.raise(RuntimeError) { raise "Error" } }.should fail lambda { should.raise { 1 + 1 } }.should fail lambda { should.raise(Interrupt) { raise "Error" } }.should fail end specify "should.raise should return the exception" do ex = lambda { raise "foo!" }.should.raise ex.should.be.kind_of RuntimeError ex.message.should.match(/foo/) end specify "has should.be.an.instance_of" do lambda { lambda { "string".should.be_an_instance_of String }.should succeed }.should.be deprecated lambda { lambda { "string".should.be_an_instance_of Hash }.should fail }.should.be deprecated lambda { "string".should.be.instance_of String }.should succeed lambda { "string".should.be.instance_of Hash }.should fail lambda { "string".should.be.an.instance_of String }.should succeed lambda { "string".should.be.an.instance_of Hash }.should fail end specify "has should.be.nil" do lambda { nil.should.be.nil }.should succeed lambda { nil.should.be nil }.should succeed lambda { nil.should.be_nil }.should.be deprecated lambda { nil.should.not.be.nil }.should fail lambda { nil.should.not.be nil }.should fail lambda { lambda { nil.should.not.be_nil }.should fail }.should.be deprecated lambda { "foo".should.be.nil }.should fail lambda { "bar".should.be nil }.should fail lambda { "foo".should.not.be.nil }.should succeed lambda { "bar".should.not.be nil }.should succeed end specify "has should.include" do lambda { [1,2,3].should.include 2 }.should succeed lambda { [1,2,3].should.include 4 }.should fail lambda { {1=>2, 3=>4}.should.include 1 }.should succeed lambda { {1=>2, 3=>4}.should.include 2 }.should fail end specify "has should.be.a.kind_of" do lambda { Array.should.be.kind_of Module }.should succeed lambda { "string".should.be.kind_of Object }.should succeed lambda { 1.should.be.kind_of Comparable }.should succeed lambda { Array.should.be.a.kind_of Module }.should succeed lambda { "string".should.be.a.kind_of Class }.should fail lambda { lambda { "string".should.be_a_kind_of Class }.should fail }.should.be deprecated lambda { Array.should.be_a_kind_of Module }.should.be deprecated lambda { "string".should.be_a_kind_of Object }.should.be deprecated lambda { 1.should.be_a_kind_of Comparable }.should.be deprecated end specify "has should.match" do lambda { "string".should.match(/strin./) }.should succeed lambda { "string".should.match("strin") }.should succeed lambda { "string".should =~ /strin./ }.should succeed lambda { "string".should =~ "strin" }.should succeed lambda { "string".should.match(/slin./) }.should fail lambda { "string".should.match("slin") }.should fail lambda { "string".should =~ /slin./ }.should fail lambda { "string".should =~ "slin" }.should fail end specify "has should.be" do thing = "thing" lambda { thing.should.be thing }.should succeed lambda { thing.should.be "thing" }.should fail lambda { 1.should.be(2, 3) }.should.raise(ArgumentError) end specify "has should.not.raise" do lambda { lambda { 1 + 1 }.should.not.raise }.should succeed lambda { lambda { 1 + 1 }.should.not.raise(Interrupt) }.should succeed lambda { begin lambda { raise ZeroDivisionError.new("ArgumentError") }.should.not.raise(RuntimeError, StandardError, Comparable) rescue ZeroDivisionError end }.should succeed lambda { lambda { raise "Error" }.should.not.raise }.should fail end specify "has should.not.satisfy" do lambda { should.not.satisfy { 1 == 2 } }.should succeed lambda { should.not.satisfy { 1 == 1 } }.should fail end specify "has should.not.be" do thing = "thing" lambda { thing.should.not.be "thing" }.should succeed lambda { thing.should.not.be thing }.should fail lambda { thing.should.not.be thing, thing }.should.raise(ArgumentError) end specify "has should.not.equal" do lambda { "string1".should.not.equal "string2" }.should succeed lambda { "string1".should.not.equal "string1" }.should fail end specify "has should.not.match" do lambda { "string".should.not.match(/sling/) }.should succeed lambda { "string".should.not.match(/string/) }.should fail lambda { "string".should.not.match("strin") }.should fail lambda { "string".should.not =~ /sling/ }.should succeed lambda { "string".should.not =~ /string/ }.should fail lambda { "string".should.not =~ "strin" }.should fail end specify "has should.throw" do lambda { lambda { throw :thing }.should.throw(:thing) }.should succeed lambda { lambda { throw :thing2 }.should.throw(:thing) }.should fail lambda { lambda { 1 + 1 }.should.throw(:thing) }.should fail end specify "has should.not.throw" do lambda { lambda { 1 + 1 }.should.not.throw }.should succeed lambda { lambda { throw :thing }.should.not.throw }.should fail end specify "has should.respond_to" do lambda { "foo".should.respond_to :to_s }.should succeed lambda { 5.should.respond_to :to_str }.should fail lambda { :foo.should.respond_to :nx }.should fail end specify "has should.be_close" do lambda { 1.4.should.be.close 1.4, 0 }.should succeed lambda { 0.4.should.be.close 0.5, 0.1 }.should succeed lambda { lambda { 1.4.should.be_close 1.4, 0 }.should succeed }.should.be deprecated lambda { lambda { 0.4.should.be_close 0.5, 0.1 }.should succeed }.should.be deprecated lambda { float_thing = Object.new def float_thing.to_f 0.2 end float_thing.should.be.close 0.1, 0.1 }.should succeed lambda { 0.4.should.be.close 0.5, 0.05 }.should fail lambda { 0.4.should.be.close Object.new, 0.1 }.should fail lambda { 0.4.should.be.close 0.5, -0.1 }.should fail end specify "multiple negation works" do lambda { 1.should.equal 1 }.should succeed lambda { 1.should.not.equal 1 }.should fail lambda { 1.should.not.not.equal 1 }.should succeed lambda { 1.should.not.not.not.equal 1 }.should fail lambda { 1.should.equal 2 }.should fail lambda { 1.should.not.equal 2 }.should succeed lambda { 1.should.not.not.equal 2 }.should fail lambda { 1.should.not.not.not.equal 2 }.should succeed end specify "has should." do lambda { [].should.be.empty }.should succeed lambda { [1,2,3].should.not.be.empty }.should succeed lambda { [].should.not.be.empty }.should fail lambda { [1,2,3].should.be.empty }.should fail lambda { {1=>2, 3=>4}.should.has_key 1 }.should succeed lambda { {1=>2, 3=>4}.should.not.has_key 2 }.should succeed lambda { nil.should.bla }.should.raise(NoMethodError) lambda { nil.should.not.bla }.should.raise(NoMethodError) end specify "has should.?" do lambda { [].should.be.empty? }.should succeed lambda { [1,2,3].should.not.be.empty? }.should succeed lambda { [].should.not.be.empty? }.should fail lambda { [1,2,3].should.be.empty? }.should fail lambda { {1=>2, 3=>4}.should.has_key? 1 }.should succeed lambda { {1=>2, 3=>4}.should.not.has_key? 2 }.should succeed lambda { nil.should.bla? }.should.raise(NoMethodError) lambda { nil.should.not.bla? }.should.raise(NoMethodError) end specify "has should (>, >=, <, <=, ===)" do lambda { 2.should.be > 1 }.should succeed lambda { 1.should.be > 2 }.should fail lambda { 1.should.be < 2 }.should succeed lambda { 2.should.be < 1 }.should fail lambda { 2.should.be >= 1 }.should succeed lambda { 2.should.be >= 2 }.should succeed lambda { 2.should.be >= 2.1 }.should fail lambda { 2.should.be <= 1 }.should fail lambda { 2.should.be <= 2 }.should succeed lambda { 2.should.be <= 2.1 }.should succeed lambda { Array.should === [1,2,3] }.should succeed lambda { Integer.should === [1,2,3] }.should fail lambda { /foo/.should === "foobar" }.should succeed lambda { "foobar".should === /foo/ }.should fail end $contextscope = self specify "is robust against careless users" do lambda { $contextscope.specify }.should.raise(ArgumentError) lambda { $contextscope.specify "foo" }.should.raise(ArgumentError) lambda { $contextscope.xspecify }.should.raise(ArgumentError) lambda { $contextscope.xspecify "foo" }.should.not.raise(ArgumentError) # allow empty xspecifys lambda { Kernel.send(:context, "foo") }.should.raise(ArgumentError) lambda { context "foo" do end }.should.raise(Test::Spec::DefinitionError) end specify "should detect warnings" do lambda { lambda { 0 }.should._warn }.should fail lambda { lambda { warn "just a test" }.should._warn }.should succeed end specify "should message/blame faults" do begin 2.should.blaming("Two is not two anymore!").equal 3 rescue Test::Unit::AssertionFailedError => e e.message.should =~ /Two/ end begin 2.should.messaging("Two is not two anymore!").equal 3 rescue Test::Unit::AssertionFailedError => e e.message.should =~ /Two/ end begin 2.should.blaming("I thought two was three").not.equal 2 rescue Test::Unit::AssertionFailedError => e e.message.should =~ /three/ end begin 2.should.blaming("I thought two was three").not.not.not.equal 3 rescue Test::Unit::AssertionFailedError => e e.message.should =~ /three/ end lambda { lambda { raise "Error" }.should.messaging("Duh.").not.raise }.should.raise(Test::Unit::AssertionFailedError).message.should =~ /Duh/ end include TestShoulds specify "should allow for custom shoulds" do lambda { (1+1).should equal_string("2") }.should succeed lambda { (1+2).should equal_string("2") }.should fail lambda { (1+1).should.pass equal_string("2") }.should succeed lambda { (1+2).should.pass equal_string("2") }.should fail lambda { (1+1).should.be equal_string("2") }.should succeed lambda { (1+2).should.be equal_string("2") }.should fail lambda { (1+1).should.not equal_string("2") }.should fail lambda { (1+2).should.not equal_string("2") }.should succeed lambda { (1+2).should.not.not equal_string("2") }.should fail lambda { (1+1).should.not.pass equal_string("2") }.should fail lambda { (1+2).should.not.pass equal_string("2") }.should succeed lambda { (1+1).should.not.be equal_string("2") }.should fail lambda { (1+2).should.not.be equal_string("2") }.should succeed lambda { (1+2).should equal_string("2") }.should.raise(Test::Unit::AssertionFailedError).message.should =~ /EqualString/ lambda { (1+1).should equal_string2("2") }.should succeed lambda { (1+2).should equal_string2("2") }.should fail lambda { (1+2).should equal_string2("2") }.should.raise(Test::Unit::AssertionFailedError).message.should =~ /yada/ lambda { (1+2).should.blaming("foo").pass equal_string2("2") }.should.raise(Test::Unit::AssertionFailedError).message.should =~ /foo/ lambda { nil.should empty_should(nil) }.should.raise(NotImplementedError) lambda { nil.should :break, :now }.should.raise(ArgumentError) lambda { nil.should.not :pass, :now }.should.raise(ArgumentError) lambda { nil.should.not.not :break, :now }.should.raise(ArgumentError) end xspecify "disabled specification" do # just trying end xspecify "empty specification" context "more disabled" do xspecify "this is intentional" do # ... end specify "an empty specification" do # ... end xcontext "even more disabled" do specify "we can cut out" do # ... end specify "entire contexts, now" do # ... end end end end context "setup/teardown" do setup do @a = 1 @b = 2 end setup do @a = 2 end teardown do @a.should.equal 2 @a = 3 end teardown do @a.should.equal 3 end specify "run in the right order" do @a.should.equal 2 @b.should.equal 2 end end context "before all" do before(:all) { @a = 1 } specify "runs parent before all" do @a.should == 1 end end context "nested teardown" do context "nested" do specify "should call local teardown then parent teardown" do @a = 3 end teardown do @a = 2 end end teardown do @a.should.equal 2 @a = 1 end after(:all) do @a.should.equal 1 end end context "before all" do context "nested" do before(:all) do @a = 2 end specify "should call parent then local" do @a.should.equal 2 @b.should.equal 2 end end before(:all) do @a = 1 @b = 2 end end context "after all" do context "after nested" do after(:all) do @a = 2 end specify "should call local then parent" do self.after_all @a.should.equal 1 @b.should.equal 2 end end after(:all) do @b = @a @a = 1 end end module ContextHelper def foo 42 end end context "contexts" do include ContextHelper FOO = 42 $class = self.class specify "are defined in class scope" do lambda { FOO }.should.not.raise(NameError) FOO.should.equal 42 $class.should.equal Class end specify "can include modules" do lambda { foo }.should.not.raise(NameError) foo.should.equal 42 end end class CustomTestUnitSubclass < Test::Unit::TestCase def test_truth assert true end end context "contexts with subclasses", CustomTestUnitSubclass do specify "use the supplied class as the superclass" do self.should.be.a.kind_of CustomTestUnitSubclass end end xcontext "xcontexts with subclasses", CustomTestUnitSubclass do specify "work great!" do self.should.be.a.kind_of CustomTestUnitSubclass end end shared_context "a shared context" do specify "can be included several times" do true.should.be true end behaves_like "yet another shared context" end shared_context "another shared context" do specify "can access data" do @answer.should.be 42 end end shared_context "yet another shared context" do specify "can include other shared contexts" do true.should.be true end end context "Shared contexts" do shared_context "a nested context" do specify "can be nested" do true.should.be true end end setup do @answer = 42 end behaves_like "a shared context" it_should_behave_like "a shared context" behaves_like "a nested context" behaves_like "another shared context" ctx = self specify "should raise when the context cannot be found" do should.raise(NameError) { ctx.behaves_like "no such context" } end end test-spec-0.10.0/test/spec_nestedcontexts.rb0000644000175000017500000000076011635746741020466 0ustar boutilboutilrequire 'test/spec' context "Empty context" do # should.not.raise end context "Outer context" do context "Inner context" do specify "is nested" do end specify "has multiple empty specifications" do end end context "Second Inner context" do context "Inmost context" do specify "works too!" do end specify "whoo!" do end end specify "is indented properly" do end specify "still runs in order of definition" do end end end test-spec-0.10.0/test/spec_testspec_order.rb0000644000175000017500000000054111635746741020436 0ustar boutilboutilrequire 'test/spec' $foo = 0 context "Context First" do specify "runs before Second" do $foo.should.equal 0 $foo += 1 end end context "Context Second" do specify "runs before Last" do $foo.should.equal 1 $foo += 1 end end context "Context Last" do specify "runs last" do $foo.should.equal 2 $foo += 1 end end test-spec-0.10.0/bin/0000755000175000017500000000000011635746741013643 5ustar boutilboutiltest-spec-0.10.0/bin/specrb0000755000175000017500000000476511635746741015063 0ustar boutilboutil#!/usr/bin/env ruby # -*- ruby -*- require 'optparse' testrbargv = [] automatic = false opts = OptionParser.new("", 24, ' ') { |opts| opts.banner = "Usage: specrb [options] [files | -a] [-- untouched arguments]" opts.separator "" opts.separator "Ruby options:" lineno = 1 opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| eval line, TOPLEVEL_BINDING, "-e", lineno lineno += 1 } opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { $DEBUG = true } opts.on("-w", "--warn", "turn warnings on for your script") { $-w = true } opts.on("-I", "--include PATH", "specify $LOAD_PATH (may be used more than once)") { |path| $LOAD_PATH.unshift(*path.split(":")) } opts.on("-r", "--require LIBRARY", "require the library, before executing your script") { |library| require library } opts.separator "" opts.separator "test/spec options:" opts.on("-s", "--specdox", "do AgileDox-like output") { testrbargv << "--runner=specdox" } opts.on("--rdox", "do AgileDox-like output with RDoc formatting") { testrbargv << "--runner=rdox" } opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") { $LOAD_PATH.unshift "lib" if File.directory? "lib" automatic = true } opts.separator "" opts.separator "test/unit options:" opts.on('-n', '--name NAME', String, "runs tests matching regexp NAME") { |n| testrbargv << "-n" << "/#{n}/" } opts.on('-t', '--testcase TESTCASE', String, "runs tests in TestCases matching regexp TESTCASE") { |t| testrbargv << "-t" << "/#{t}/" } opts.separator "" opts.separator "Common options:" opts.on_tail("-h", "--help", "Show this message") do puts opts exit end opts.on_tail("--version", "Show version") do require 'test/spec' puts "specrb #{Test::Spec::VERSION}" exit end opts.parse! ARGV } files = ARGV if automatic files.concat Dir["test/test_*.rb"] files.concat Dir["test/spec_*.rb"] files.concat Dir["spec/spec_*.rb"] end if files.empty? puts opts.banner exit 1 end argv = testrbargv + files # Should use -- to separate them *but* there's a bug in # Test::Unit::AutoRunner#process_args: arguments after -- are ignored. # (You could also argue that it's a bug in optparse.rb). require 'test/spec' Test::Unit.run = false runner = Test::Unit::AutoRunner.new true runner.process_args(argv) || abort("internal error calling Test::Unit, please report a bug") exit runner.run test-spec-0.10.0/ROADMAP0000644000175000017500000000005611635746741014102 0ustar boutilboutilVersion 1.0 (2008):: everything-done release. test-spec-0.10.0/TODO0000644000175000017500000000010111635746741013553 0ustar boutilboutil- see ROADMAP - better handling of .should outside of specify(?) test-spec-0.10.0/README0000644000175000017500000002612711635746741013763 0ustar boutilboutil= test/spec, a BDD interface for Test::Unit Copyright (C) 2006, 2007, 2008, 2009 Christian Neukirchen == What is test/spec? test/spec layers an RSpec-inspired interface on top of Test::Unit, so you can mix TDD and BDD (Behavior-Driven Development). test/spec is a clean-room implementation that maps most kinds of Test::Unit assertions to a `should'-like syntax. Consider this Test::Unit test case: class TestFoo < Test::Unit::TestCase def test_should_bar assert_equal 5, 2 + 3 end end In test/spec, it looks like this: require 'test/spec' context "Foo" do specify "should bar" do (2 + 3).should.equal 5 end end Since test/spec 0.4, you can also use the new RSpec 1.0 style: require 'test/spec' describe "Foo" do it "should bar" do (2 + 3).should.equal 5 end end test/spec does not include a mocking/stubbing-framework; use whichever you like to. test/spec has been tested successfully with FlexMock and Mocha. test/spec has no dependencies outside Ruby 1.8. == Mixing test/spec and test/unit test/spec and Test::Unit contexts/test cases can be intermixed freely, run in the same test and live in the same files. You can just add them to your Rake::TestTask, too. test/spec allows you to leverage your full existing Test::Unit infrastructure. test/spec does not change Test::Unit with the exception of monkey-patching Test::Unit::TestSuite to order the test cases before running them. (This should not do any harm, but if you know a way around it, please tell me.) test/spec adds seven global methods, Object#should, Kernel.context, Kernel.xcontext, Kernel.shared_context, Kernel.describe, Kernel.xdescribe, and Kernel.describe_shared. The Kernel methods are private. You can use assert_* freely in specify-blocks; Object#should works in plain Test::Unit test cases, too, but they will not be counted. == Wrapped assertions +assert_equal+:: should.equal, should == +assert_not_equal+:: should.not.equal, should.not == +assert_same+:: should.be +assert_not_same+:: should.not.be +assert_nil+:: should.be.nil +assert_not_nil+:: should.not.be.nil +assert_in_delta+:: should.be.close +assert_match+:: should.match, should =~ +assert_no_match+:: should.not.match, should.not =~ +assert_instance_of+:: should.be.an.instance_of +assert_kind_of+:: should.be.a.kind_of +assert_respond_to+:: should.respond_to +assert_raise+:: should.raise +assert_nothing_raised+:: should.not.raise +assert_throws+:: should.throw +assert_nothing_thrown+:: should.not.throw +assert_block+:: should.satisfy (+a+, +an+ and +be+ without arguments are optional and no-ops.) == Additional assertions These assertions are not included in Test::Unit, but have been added to test/spec for convenience: * should.not.satisfy * should.include * a.should._predicate_ (works like assert a._predicate_?) * a.should.be _operator_ (where _operator_ is one of >, >=, <, <= or ===) * should.output (require test/spec/should-output) If you write an useful general-purpose assertion, I'd like to hear of it and may add it to the test/spec distribution. == Messaging/Blaming With more complex assertions, it may be helpful to provide a message to show if the assertion has failed. This can be done with the Should#blaming or Should#messaging methods: RUBY_VERSION.should.messaging("Ruby too old.").be > "1.8.4" (1 + 1).should.blaming("weird math").not.equal 11 == Custom shoulds ("Matchers") To capture recurring patterns in parts of your specifications, you can define custom "shoulds" (RSpec calls them "matchers") in your contexts, or include modules of them: context "Numbers" class EqualString < Test::Spec::CustomShould def matches?(other) object == other.to_s end end def equal_string(str) EqualString.new(str) end specify "should have to_s" 42.should equal_string("42") end end Alternatively, your implementation can define CustomShould#assumptions, where you can use test/spec assertions instead of Boolean predicates: class EqualString < Test::Spec::CustomShould def assumptions(other) object.should.equal other.to_s end end A CustomShould by default takes one argument, which is placed in self.object for your convenience. You can CustomShould#failure_message to provide a better error message. == SpecDox and RDox test/spec adds two additional test runners to Test::Unit, based on the console runner but with a different output format. SpecDox, run with --runner=specdox (or -rs) looks like RSpec's output: should.output - works for print - works for puts - works with readline RDox, run with --runner=rdox (or -rr) can be included for RDoc documentation (e.g. see SPECS): == should.output * works for print * works for puts * works with readline SpecDox and RDox work for Test::Unit too: $ ruby -r test/spec test/testunit/test_testresult.rb -rs Test::Unit::TC_TestResult - fault notification - passed? - result changed notification Finished in 0.106647 seconds. 3 specifications (30 requirements), 0 failures Since version 0.4, SpecDox and RDox also notice and count empty specifications. == Disabled specifications Akin to the usual Test::Unit practice, tests quickly can be disabled by replacing +specify+ with +xspecify+ (or +it+ with +xit+). test/spec will count the disabled tests when you run it with SpecDox or RDox. When you use xspecify/xit, you also can drop the block. This is useful for writing specifications that you haven't yet started implementing. Complete contexts can be disabled by using +xcontext+/+xdescribe+. == Setup/Teardown Setup/Teardown methods are run in this order: * before(:all) in order of definition * before(:each)/setup in order of definition * specify * after(:each)/setup in order of definition * before(:each)/setup in order of definition * specify * after(:each)/setup in order of definition * ... * after(:all) in order of definition Please note that before(:all) and after(:all) are run in their own instance, so all instance variables they set are lost(!) and not visible to other specifications. They are e.g. useful for setting up database connections or starting servers. == Shared contexts Since version 0.9, you can define shared contexts in test/spec using shared_context/describe_shared. These contexts are not executed on their own, but can be included with it_should_behave_like/behaves_like in other contexts. You can use shared contexts to structure suites with many recurring specifications. == specrb Since version 0.2, test/spec features a standalone test runner called specrb. specrb is like an extended version of testrb, Test::Unit's test runner, but has additional options. It can be used for plain Test::Unit suites, too. $ specrb -a -s -n should.output should.output - works for print - works for puts - works with readline Finished in 0.162571 seconds. 3 specifications (6 requirements), 0 failures Run specrb --help for the usage. == test/spec on Rails If you want to specify your Rails applications, you can use the third-party plugin "test/spec on Rails", which can be found at: http://svn.techno-weenie.net/projects/plugins/test_spec_on_rails/ It features testing of model validation, redirection, output, HTTP status, template rendering and URL generation. == Installing with RubyGems Since version 0.3, a Gem of test/spec is available. You can install with: gem install test-spec I also provide a local mirror of the gems (and development snapshots) at my site: gem install test-spec --source http://chneukirchen.org/releases/gems == History * September 29th, 2006: First public release 0.1. * October 18th, 2006: Second public release 0.2. * Better, module-based implementation * Official support for FlexMock and Mocha * More robust Should#output * Should#_operator_ * Nested contexts * Standalone test/spec runner, specrb * January 24th, 2007: Third public release 0.3. * should.be_close, should.be_an_instance_of, should.be_a_kind_of, and should.be_nil have been deprecated. Use the dot-variants of them. These assertions will be removed in 1.0. * specrb -a now includes -Ilib by default for easier out-of-the-box testing. * Added custom shoulds. * Added messaging/blaming. * Added disabling of specifications. * Small bug fixes. * Gem available. * June 29th, 2007: Fourth public release 0.4. * Support for Ruby 1.8.6. * Support describe/it/before/after RSpec 1.0 syntax. * Allow should.raise { code_that_raises } * Add xcontext to disable complete contexts. * Backtraces are cleaner now. * Mention test/spec on Rails. * Fix small Gem bugs. * Fix bug related to counting negated assertions. * Fix bug in specrb. * Allow empty xspecifys. * Make SpecDox and RDox count empty specifications. * Allow Kernel#context to take a superclass. * July 2nd, 2008: Fifth public release 0.9. * Allow should.? as well as should.. * Add shared contexts. * Nested contexts now run the setups/teardowns/before(:all)/after(:all) of their parents. * February 1st, 2009: Sixth public release 0.10. * Support for Ruby 1.9. Now requires the test-spec gem. == Contact Please mail bugs, suggestions and patches to . Darcs repository ("darcs send" is welcome for patches): http://chneukirchen.org/repos/testspec == Thanks to * Eero Saynatkari for writing should.output. * Tuxie for writing test/spec on Rails. * Brian Donovan for allowing alternative superclasses. * Xavier Shay for implementing nested setups/teardowns. * Chris Wanstrath for should.raise with a block and xcontext. * Jean-Michel Garnier for packaging the first gem. * Mikko Lehtonen, Jan Wikholm, Matt Mower and Michael Fellinger for testing the gem. * Chris McGrath for reporting a bug. * Thomas Fuchs for script.aculo.us BDD testing which convinced me. * Dave Astels for BDD. * The RSpec team for API inspiration. * Nathaniel Talbott for Test::Unit. == Copying Copyright (C) 2006, 2007, 2008, 2009 Christian Neukirchen test/spec is licensed under the same terms as Ruby itself. Please mail bugs, feature requests or patches to the mail addresses found above or use IRC[irc://freenode.net/#ruby-lang] to contact the developer. == Links Behavior-Driven Development:: RSpec:: script.aculo.us testing:: FlexMock:: Mocha:: Christian Neukirchen:: test-spec-0.10.0/Rakefile0000644000175000017500000000677611635746741014560 0ustar boutilboutil# Rakefile for testspec. -*-ruby-*- require 'rake/rdoctask' require 'rake/testtask' desc "Run all the tests" task :default => [:test] desc "Do predistribution stuff" task :predist => [:chmod, :changelog, :rdoc] desc "Make an archive as .tar.gz" task :dist => :test do system "export DARCS_REPO=#{File.expand_path "."}; " + "darcs dist -d test-spec-#{get_darcs_tree_version}" end # Helper to retrieve the "revision number" of the darcs tree. def get_darcs_tree_version unless File.directory? "_darcs" load 'lib/test/spec/version.rb' return Test::Spec::VERSION end changes = `darcs changes` count = 0 tag = "0.0" changes.each("\n\n") { |change| head, title, desc = change.split("\n", 3) if title =~ /^ \*/ # Normal change. count += 1 elsif title =~ /tagged (.*)/ # Tag. We look for these. tag = $1 break else warn "Unparsable change: #{change}" end } tag + "." + count.to_s end def manifest `darcs query manifest 2>/dev/null`.split("\n").map { |f| f.gsub(/\A\.\//, '') } end desc "Make binaries executable" task :chmod do Dir["bin/*"].each { |binary| File.chmod(0775, binary) } end desc "Generate a ChangeLog" task :changelog do system "darcs changes --repo=#{ENV["DARCS_REPO"] || "."} >ChangeLog" end desc "Generate RDox" task "SPECS" do ruby "bin/specrb -Ilib:test -a --rdox >SPECS" end desc "Run all the tests" task :test => :chmod do ruby "bin/specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}" end begin require 'rubygems' require 'rake' require 'rake/clean' require 'rake/packagetask' require 'rake/gempackagetask' require 'fileutils' rescue LoadError # Too bad. else spec = Gem::Specification.new do |s| s.name = "test-spec" s.version = get_darcs_tree_version s.platform = Gem::Platform::RUBY s.summary = "a Behaviour Driven Development interface for Test::Unit" s.description = <<-EOF test/spec layers an RSpec-inspired interface on top of Test::Unit, so you can mix TDD and BDD (Behavior-Driven Development). test/spec is a clean-room implementation that maps most kinds of Test::Unit assertions to a `should'-like syntax. EOF s.files = manifest + %w(SPECS) s.bindir = 'bin' s.executables << 'specrb' s.require_path = 'lib' s.has_rdoc = true s.extra_rdoc_files = ['README', 'SPECS', 'ROADMAP'] s.test_files = Dir['test/{test,spec}_*.rb'] s.author = 'Christian Neukirchen' s.email = 'chneukirchen@gmail.com' s.homepage = "http://test-spec.rubyforge.org" s.rubyforge_project = 'test-spec' end task :package => [:dist] Rake::GemPackageTask.new(spec) do |p| p.gem_spec = spec p.need_tar = false p.need_zip = false end end desc "Generate RDoc documentation" Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.options << '--line-numbers' << '--inline-source' rdoc.rdoc_dir = "doc" rdoc.rdoc_files.include 'README' rdoc.rdoc_files.include 'ROADMAP' rdoc.rdoc_files.include 'SPECS' rdoc.rdoc_files.include('lib/**/*.rb') end task :rdoc => "SPECS" begin require 'rcov/rcovtask' Rcov::RcovTask.new do |t| t.test_files = FileList['test/{spec,test}_*.rb'] + ['--', '-rs'] # evil t.verbose = true # uncomment to see the executed command t.rcov_opts = ["--text-report", "--include-file", "^lib,^test", "--exclude-only", "^/usr,^/home/.*/src"] end rescue LoadError end test-spec-0.10.0/lib/0000755000175000017500000000000011635746741013641 5ustar boutilboutiltest-spec-0.10.0/lib/test/0000755000175000017500000000000011635746741014620 5ustar boutilboutiltest-spec-0.10.0/lib/test/spec.rb0000644000175000017500000003601711635746741016106 0ustar boutilboutil# # test/spec -- a BDD interface for Test::Unit # # Copyright (C) 2006, 2007, 2008, 2009 Christian Neukirchen # # This work is licensed under the same terms as Ruby itself. # require 'test/unit' class Test::Unit::AutoRunner # :nodoc: RUNNERS[:specdox] = lambda { |*args| require 'test/spec/dox' Test::Unit::UI::SpecDox::TestRunner } RUNNERS[:rdox] = lambda { |*args| require 'test/spec/rdox' Test::Unit::UI::RDox::TestRunner } end module Test # :nodoc: end module Test::Spec require 'test/spec/version' CONTEXTS = {} # :nodoc: SHARED_CONTEXTS = Hash.new { |h,k| h[k] = [] } # :nodoc: class DefinitionError < StandardError end class Should include Test::Unit::Assertions def self.deprecated_alias(to, from) # :nodoc: define_method(to) { |*args| warn "Test::Spec::Should##{to} is deprecated and will be removed in future versions." __send__ from, *args } end def initialize(object, message=nil) @object = object @message = message end $TEST_SPEC_TESTCASE = nil def add_assertion $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion) end def an self end def a self end def not(*args) case args.size when 0 ShouldNot.new(@object, @message) when 1 ShouldNot.new(@object, @message).pass(args.first) else raise ArgumentError, "#not takes zero or one argument(s)." end end def messaging(message) @message = message.to_s self end alias blaming messaging def satisfy(&block) assert_block(@message || "satisfy block failed.") { yield @object } end def equal(value) assert_equal value, @object, @message end alias == equal def close(value, delta) assert_in_delta value, @object, delta, @message end deprecated_alias :be_close, :close def be(*value) case value.size when 0 self when 1 if CustomShould === value.first pass value.first else assert_same value.first, @object, @message end else raise ArgumentError, "should.be needs zero or one argument" end end def match(value) assert_match value, @object, @message end alias =~ match def instance_of(klass) assert_instance_of klass, @object, @message end deprecated_alias :be_an_instance_of, :instance_of def kind_of(klass) assert_kind_of klass, @object, @message end deprecated_alias :be_a_kind_of, :kind_of def respond_to(method) assert_respond_to @object, method, @message end def _raise(*args, &block) args = [RuntimeError] if args.empty? block ||= @object args << @message if @message assert_raise(*args, &block) end def throw(sym) assert_throws(sym, @message, &@object) end def nil assert_nil @object, @message end deprecated_alias :be_nil, :nil def include(value) msg = build_message(@message, " expected to include ?, but it didn't.", @object, value) assert_block(msg) { @object.include?(value) } end def >(value) assert_operator @object, :>, value, @message end def >=(value) assert_operator @object, :>=, value, @message end def <(value) assert_operator @object, :<, value, @message end def <=(value) assert_operator @object, :<=, value, @message end def ===(value) assert_operator @object, :===, value, @message end def pass(custom) _wrap_assertion { assert_nothing_raised(Test::Unit::AssertionFailedError, @message || custom.failure_message) { assert custom.matches?(@object), @message || custom.failure_message } } end def method_missing(name, *args, &block) # This will make raise call Kernel.raise, and self.raise call _raise. return _raise(*args, &block) if name == :raise if @object.respond_to?("#{name}?") assert @object.__send__("#{name}?", *args), "#{name}? expected to be true. #{@message}" else if @object.respond_to?(name) assert @object.__send__(name, *args), "#{name} expected to be true. #{@message}" else super end end end end class ShouldNot include Test::Unit::Assertions def initialize(object, message=nil) @object = object @message = message end def add_assertion $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion) end def satisfy(&block) assert_block(@message || "not.satisfy block succeded.") { not yield @object } end def equal(value) assert_not_equal value, @object, @message end alias == equal def be(*value) case value.size when 0 self when 1 if CustomShould === value.first pass value.first else assert_not_same value.first, @object, @message end else Kernel.raise ArgumentError, "should.be needs zero or one argument" end end def match(value) # Icky Regexp check assert_no_match value, @object, @message end alias =~ match def _raise(*args, &block) block ||= @object args << @message if @message assert_nothing_raised(*args, &block) end def throw assert_nothing_thrown(@message, &@object) end def nil assert_not_nil @object, @message end def be_nil warn "Test::Spec::ShouldNot#be_nil is deprecated and will be removed in future versions." self.nil end def not(*args) case args.size when 0 Should.new(@object, @message) when 1 Should.new(@object, @message).pass(args.first) else raise ArgumentError, "#not takes zero or one argument(s)." end end def pass(custom) _wrap_assertion { begin assert !custom.matches?(@object), @message || custom.failure_message end } end def method_missing(name, *args, &block) # This will make raise call Kernel.raise, and self.raise call _raise. return _raise(*args, &block) if name == :raise if @object.respond_to?("#{name}?") assert_block("#{name}? expected to be false. #{@message}") { not @object.__send__("#{name}?", *args) } else if @object.respond_to?(name) assert_block("#{name} expected to be false. #{@message}") { not @object.__send__("#{name}", *args) } else super end end end end class CustomShould attr_accessor :object def initialize(obj) self.object = obj end def failure_message "#{self.class.name} failed" end def matches?(*args, &block) assumptions(*args, &block) true end def assumptions(*args, &block) raise NotImplementedError, "you need to supply a #{self.class}#matches? method" end end end class Test::Spec::TestCase attr_reader :testcase attr_reader :name attr_reader :position module InstanceMethods def setup # :nodoc: $TEST_SPEC_TESTCASE = self super call_methods_including_parents(:setups) end def teardown # :nodoc: super call_methods_including_parents(:teardowns, :reverse) end def before_all call_methods_including_parents(:before_all) end def after_all call_methods_including_parents(:after_all, :reverse) end def initialize(name) super name # Don't let the default_test clutter up the results and don't # flunk if no tests given, either. throw :invalid_test if name.to_s == "default_test" end def position self.class.position end def context(*args) raise Test::Spec::DefinitionError, "context definition is not allowed inside a specify-block" end alias :describe :context private def call_methods_including_parents(method, reverse=false, klass=self.class) return unless klass if reverse klass.send(method).each { |s| instance_eval(&s) } call_methods_including_parents(method, reverse, klass.parent) else call_methods_including_parents(method, reverse, klass.parent) klass.send(method).each { |s| instance_eval(&s) } end end end module ClassMethods attr_accessor :count attr_accessor :name attr_accessor :position attr_accessor :parent attr_accessor :setups attr_accessor :teardowns attr_accessor :before_all attr_accessor :after_all # old-style (RSpec <1.0): def context(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) (Test::Spec::CONTEXTS[self.name + "\t" + name] ||= klass.new(name, self, superclass)).add(&block) end def xcontext(name, superclass=Test::Unit::TestCase, &block) context(name, superclass, Test::Spec::DisabledTestCase, &block) end def specify(specname, &block) raise ArgumentError, "specify needs a block" if block.nil? self.count += 1 # Let them run in order of definition define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block) end def xspecify(specname, &block) specify specname do @_result.add_disabled(specname) end end def setup(&block) setups << block end def teardown(&block) teardowns << block end def shared_context(name, &block) Test::Spec::SHARED_CONTEXTS[self.name + "\t" + name] << block end def behaves_like(shared_context) if Test::Spec::SHARED_CONTEXTS.include?(shared_context) Test::Spec::SHARED_CONTEXTS[shared_context].each { |block| instance_eval(&block) } elsif Test::Spec::SHARED_CONTEXTS.include?(self.name + "\t" + shared_context) Test::Spec::SHARED_CONTEXTS[self.name + "\t" + shared_context].each { |block| instance_eval(&block) } else raise NameError, "Shared context #{shared_context} not found." end end alias :it_should_behave_like :behaves_like # new-style (RSpec 1.0+): alias :describe :context alias :describe_shared :shared_context alias :it :specify alias :xit :xspecify def before(kind=:each, &block) case kind when :each setup(&block) when :all before_all << block else raise ArgumentError, "invalid argument: before(#{kind.inspect})" end end def after(kind=:each, &block) case kind when :each teardown(&block) when :all after_all << block else raise ArgumentError, "invalid argument: after(#{kind.inspect})" end end def init(name, position, parent) self.position = position self.parent = parent if parent self.name = parent.name + "\t" + name else self.name = name end self.count = 0 self.setups = [] self.teardowns = [] self.before_all = [] self.after_all = [] end end @@POSITION = 0 def initialize(name, parent=nil, superclass=Test::Unit::TestCase) @testcase = Class.new(superclass) { include InstanceMethods extend ClassMethods } @@POSITION = @@POSITION + 1 @testcase.init(name, @@POSITION, parent) end def add(&block) raise ArgumentError, "context needs a block" if block.nil? @testcase.class_eval(&block) self end end (Test::Spec::DisabledTestCase = Test::Spec::TestCase.dup).class_eval do alias :test_case_initialize :initialize def initialize(*args, &block) test_case_initialize(*args, &block) @testcase.instance_eval do alias :test_case_specify :specify def specify(specname, &block) test_case_specify(specname) { @_result.add_disabled(specname) } end alias :it :specify end end end class Test::Spec::Disabled < Test::Unit::Failure # :nodoc: def initialize(name) @name = name end def single_character_display "D" end def short_display @name end def long_display @name + " is disabled" end end class Test::Spec::Empty < Test::Unit::Failure # :nodoc: def initialize(name) @name = name end def single_character_display "" end def short_display @name end def long_display @name + " is empty" end end # Monkey-patch test/unit to run tests in an optionally specified order. module Test::Unit # :nodoc: class TestSuite # :nodoc: undef run def run(result, &progress_block) sort! yield(STARTED, name) @tests.first.before_all if @tests.first.respond_to? :before_all @tests.each do |test| test.run(result, &progress_block) end @tests.last.after_all if @tests.last.respond_to? :after_all yield(FINISHED, name) end def sort! @tests = @tests.sort_by { |test| test.respond_to?(:position) ? test.position : 0 } end def position @tests.first.respond_to?(:position) ? @tests.first.position : 0 end end class TestResult # :nodoc: # Records a disabled test. def add_disabled(name) notify_listeners(FAULT, Test::Spec::Disabled.new(name)) notify_listeners(CHANGED, self) end end end # Hide Test::Spec interna in backtraces. module Test::Unit::Util::BacktraceFilter # :nodoc: TESTSPEC_PREFIX = __FILE__.gsub(/spec\.rb\Z/, '') # Vendor plugins like to be loaded several times, don't recurse # infinitely then. unless method_defined? "testspec_filter_backtrace" alias :testspec_filter_backtrace :filter_backtrace end def filter_backtrace(backtrace, prefix=nil) if prefix.nil? testspec_filter_backtrace(testspec_filter_backtrace(backtrace), TESTSPEC_PREFIX) else testspec_filter_backtrace(backtrace, prefix) end end end #-- Global helpers class Object def should(*args) case args.size when 0 Test::Spec::Should.new(self) when 1 Test::Spec::Should.new(self).pass(args.first) else raise ArgumentError, "Object#should takes zero or one argument(s)." end end end module Kernel def context(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc: (Test::Spec::CONTEXTS[name] ||= klass.new(name, nil, superclass)).add(&block) end def xcontext(name, superclass=Test::Unit::TestCase, &block) # :doc: context(name, superclass, Test::Spec::DisabledTestCase, &block) end def shared_context(name, &block) Test::Spec::SHARED_CONTEXTS[name] << block end alias :describe :context alias :xdescribe :xcontext alias :describe_shared :shared_context private :context, :xcontext, :shared_context private :describe, :xdescribe, :describe_shared end test-spec-0.10.0/lib/test/spec/0000755000175000017500000000000011635746741015552 5ustar boutilboutiltest-spec-0.10.0/lib/test/spec/rdox.rb0000644000175000017500000000102311635746741017047 0ustar boutilboutilrequire 'test/spec/dox' module Test::Unit::UI # :nodoc: module RDox # :nodoc: class TestRunner < Test::Unit::UI::SpecDox::TestRunner def output_heading(heading) output "#{@headprefix} #{heading}" end def output_item(item) output_no_nl "* #{item}" end def finished(elapsed_time) nl output_result end def indent(depth) @prefix = "" @headprefix = "==" + "=" * depth end end end end test-spec-0.10.0/lib/test/spec/dox.rb0000644000175000017500000000730411635746741016675 0ustar boutilboutilrequire 'test/unit/ui/console/testrunner' module Test::Unit::UI # :nodoc: module SpecDox # :nodoc: class TestRunner < Test::Unit::UI::Console::TestRunner protected def setup_mediator @mediator = create_mediator(@suite) end def add_fault(fault) if fault.kind_of? Test::Spec::Disabled @disabled += 1 output_no_nl " (disabled)" elsif fault.kind_of? Test::Spec::Empty @empty += 1 output_no_nl " (empty)" else @faults << fault word = fault.class.name[/(.*::)?(.*)/, 2].upcase output_no_nl " (#{word} - #{@faults.size})" end end def started(result) @io ||= @output @result = result @context = nil @contexts = [] @disabled = 0 @empty = 0 indent 0 end def finished(elapsed_time) nl output "Finished in #{elapsed_time} seconds." @faults.each_with_index do |fault, index| nl output("%3d) %s" % [index + 1, fault.long_display]) end nl output_result end def output_result if @disabled > 0 disabled = ", #{@disabled} disabled" else disabled = "" end if @empty > 0 empty = ", #{@empty} empty" else empty = "" end r = ("%d specifications#{disabled}#{empty} " + "(%d requirements), %d failures") % [ @result.run_count, @result.assertion_count, @result.failure_count] r << ", #{@result.error_count} errors" if @result.error_count > 0 output r end def test_started(name) return if special_test? name contextname, @specname = unmangle name return if contextname.nil? || @specname.nil? if @context != contextname @context = contextname @old_contexts = @contexts @contexts = @context.split("\t") common = 0 @contexts.zip(@old_contexts) { |a, b| break if a != b common += 1 } nl if common == 0 @contexts[common..-1].each_with_index { |head, i| indent common + i output_heading head } end @assertions = @result.assertion_count @prevdisabled = @disabled output_item @specname end def test_finished(name) return if special_test? name # Did any assertion run? if @assertions == @result.assertion_count && @prevdisabled == @disabled add_fault Test::Spec::Empty.new(@specname) end # Don't let empty contexts clutter up the output. nl unless name =~ /\Adefault_test\(/ end def output_no_nl(something, level=NORMAL) @io.write(something) if (output?(level)) @io.flush end def output_item(item) output_no_nl "#{@prefix}- #{item}" end def output_heading(heading) output "#{@prefix}#{heading}" end def unmangle(name) if name =~ /\Atest_spec \{(.*?)\} \d+ \[(.*)\]/ contextname = $1 specname = $2 elsif name =~ /test_(.*?)\((.*)\)$/ specname = $1 contextname = $2 contextname.gsub!(/^Test\B|\BTest$/, '') specname.gsub!(/_/, ' ') else contextname = specname = nil end [contextname, specname] end def indent(depth) @indent = depth @prefix = " " * depth end def special_test?(name) name =~ /\Atest_spec \{.*?\} (-1 BEFORE|AFTER) ALL\(/ end end end end test-spec-0.10.0/lib/test/spec/should-output.rb0000644000175000017500000000217211635746741020735 0ustar boutilboutil# Code adapted from rs, written by Eero Saynatkari. require 'fileutils' require 'tmpdir' class Test::Spec::Should # Captures output from the IO given as # the second argument (STDIN by default) # and matches it against a String or # Regexp given as the first argument. def output(expected, to = STDOUT) # Store the old stream old_to = to.dup # Obtain a filehandle to replace (works with Readline) to.reopen File.open(File.join(Dir.tmpdir, "should_output_#{$$}"), "w+") # Execute @object.call # Restore out = to.dup to.reopen old_to # Grab the data out.rewind output = out.read # Match up case expected when Regexp output.should.match expected else output.should.equal expected end # case expected # Clean up ensure out.close # STDIO redirection will break else begin to.seek 0, IO::SEEK_END rescue Errno::ESPIPE rescue Errno::EPIPE end FileUtils.rm_f out.path end # output end # Test::Spec::Should test-spec-0.10.0/lib/test/spec/version.rb0000644000175000017500000000016311635746741017564 0ustar boutilboutil# To load it externally, without activating Test::Unit. module Test module Spec VERSION = "0.10" end end