Permalink
Browse files

initial commit, port from micronaut-unit to rspec 2

  • Loading branch information...
0 parents commit 19f0aa8a7f3991eece21dc98c417d52355aa5709 @glv committed Feb 22, 2010
Showing with 2,058 additions and 0 deletions.
  1. +5 −0 .document
  2. +5 −0 .gitignore
  3. +20 −0 LICENSE
  4. +82 −0 README.md
  5. +53 −0 Rakefile
  6. +4 −0 VERSION.yml
  7. +1 −0 lib/rspec-unit.rb
  8. +3 −0 lib/rspec/unit.rb
  9. +651 −0 lib/rspec/unit/assertions.rb
  10. +208 −0 lib/rspec/unit/test_case.rb
  11. +52 −0 rspec-unit.gemspec
  12. +528 −0 spec/assertions_spec.rb
  13. +42 −0 spec/spec_helper.rb
  14. +404 −0 spec/test_case_spec.rb
5 .document
@@ -0,0 +1,5 @@
+README.rdoc
+lib/**/*.rb
+bin/*
+features/**/*.feature
+LICENSE
5 .gitignore
@@ -0,0 +1,5 @@
+*.sw?
+.DS_Store
+coverage
+rdoc
+pkg
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Glenn Vanderburg
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
82 README.md
@@ -0,0 +1,82 @@
+# rspec-unit
+
+Test::Unit compatibility for rspec.
+
+Just add this to your code:
+
+ require 'rspec/unit'
+
+and then you can write test classes like this:
+
+ class FooTest < Rspec::Unit::TestCase
+ def test_foo
+ assert_equal 3, Foo::major_version
+ end
+ end
+
+Using the `test_info` method, you can attach metadata to the next
+defined test (this works much the same way Rake's `desc` method
+attaches a description string to the next defined task):
+
+ test_info :speed => 'slow', :run => 'nightly'
+ def test_tarantula_multipass
+ # ...
+ end
+
+You can also attach metadata to the entire class with the
+`test_case_info` method:
+
+ class BarTest < Rspec::Unit::TestCase
+ test_case_info :integration => true
+
+ # ...
+ end
+
+Each instance of `Rspec::Unit::TestCase` is equivalent to a
+rspec `describe` block, so it can also include `it` blocks,
+`before` and `after` blocks, and nested `describe` blocks. Test
+methods and `it` blocks can contain either assertions or `should`
+expressions. `test` blocks (as found in Rails 2.x) also work.
+
+Additionally, assertions can be used inside ordinary rspec
+examples.
+
+## Rationale
+
+The point of this gem is not that I think test/unit is a better way
+to write tests than the RSpec style. I admit that I'm a TDD oldtimer
+who sees RSpec as mostly a cosmetic (rather than fundamental) change,
+but that doesn't mean it's not an important change. My curmudgeonly
+nature has its limits, and I do find specs a big improvement.
+
+So why rspec-unit? Three reasons:
+
+1. I wanted to show off the generality of Rspec's architecture.
+ On the surface, Rspec might not seem all that compelling
+ (since it's basically an RSpec work-alike). But it's really a
+ fantastic tool; it's just that the
+ [innovation is all under the hood][uth], in a way that makes it
+ easy to change the surface aspects. I hope rspec-unit can
+ serve as an example for anyone who wants to experiment with new
+ ways of expressing tests and specs on top of Rspec.
+2. Many projects with existing test/unit test suites might want to
+ benefit from Rspec's [metadata goodness][metadata], or begin
+ a gradual, piecemeal change to an RSpec style. That's pretty
+ easy to do with rspec-unit.
+3. Even when writing specs and examples, I frequently encounter
+ cases where an assertion is more expressive than a `should`
+ expression. It's nice just to have assertions supported within
+ Rspec examples.
+
+[uth]: http://blog.thinkrelevance.com/2009/4/1/micronaut-innovation-under-the-hood
+[metadata]: http://blog.thinkrelevance.com/2009/3/26/introducing-micronaut-a-lightweight-bdd-framework
+
+## To Do
+
+It would be nice to try using the assertion code from minitest,
+which is much more compact and seems less coupled than that from
+test/unit.
+
+### Copyright
+
+Copyright (c) 2009 Glenn Vanderburg. See LICENSE for details.
53 Rakefile
@@ -0,0 +1,53 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "rspec-unit"
+ gem.summary = %Q{Adds test/unit compatibility to Rspec.}
+ gem.email = "glv@vanderburg.org"
+ gem.homepage = "http://github.com/glv/rspec-unit"
+ gem.authors = ["Glenn Vanderburg"]
+ gem.rubyforge_project = "rspec-unit"
+ gem.add_dependency('rspec', '>= 2.0.0.a7')
+ gem.has_rdoc = false
+ gem.files = FileList["[A-Z]*", "{bin,lib,examples}/**/*"]
+ gem.rubyforge_project = 'glv'
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ end
+
+ Jeweler::RubyforgeTasks.new
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
+end
+
+require 'rspec/core/rake_task'
+Rspec::Core::RakeTask.new(:examples) do |examples|
+ examples.pattern = 'spec/**/*_spec.rb'
+ examples.ruby_opts = '-Ilib -Ispec'
+end
+
+Rspec::Core::RakeTask.new(:rcov) do |examples|
+ examples.pattern = 'spec/**/*_spec.rb'
+ examples.rcov_opts = '-Ilib -Ispec -x "/Library/Ruby/Gems,^spec/"'
+ examples.rcov = true
+end
+
+task :default => :examples
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ if File.exist?('VERSION.yml')
+ config = YAML.load(File.read('VERSION.yml'))
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
+ else
+ version = ""
+ end
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "rspec-unit #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
4 VERSION.yml
@@ -0,0 +1,4 @@
+---
+:patch: 0
+:major: 0
+:minor: 1
1 lib/rspec-unit.rb
@@ -0,0 +1 @@
+require 'rspec/unit'
3 lib/rspec/unit.rb
@@ -0,0 +1,3 @@
+# This file may be the starting point in some cases, so pull in all of micronaut:
+require 'rspec'
+require 'rspec/unit/test_case'
651 lib/rspec/unit/assertions.rb
@@ -0,0 +1,651 @@
+# Author:: Nathaniel Talbott.
+# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
+# License:: Ruby license.
+
+module Rspec
+ module Unit
+
+ ##
+ # Test::Unit::Assertions contains the standard Test::Unit assertions.
+ # Assertions is included in Test::Unit::TestCase.
+ #
+ # To include it in your own code and use its functionality, you simply
+ # need to rescue Test::Unit::AssertionFailedError. Additionally you may
+ # override add_assertion to get notified whenever an assertion is made.
+ #
+ # Notes:
+ # * The message to each assertion, if given, will be propagated with the
+ # failure.
+ # * It is easy to add your own assertions based on assert_block().
+ #
+ # = Example Custom Assertion
+ #
+ # def deny(boolean, message = nil)
+ # message = build_message message, '<?> is not false or nil.', boolean
+ # assert_block message do
+ # not boolean
+ # end
+ # end
+
+ module Assertions
+
+ ##
+ # The assertion upon which all other assertions are based. Passes if the
+ # block yields true.
+ #
+ # Example:
+ # assert_block "Couldn't do the thing" do
+ # do_the_thing
+ # end
+
+ public
+ def assert_block(message="assert_block failed.") # :yields:
+ _wrap_assertion do
+ if (! yield)
+ raise AssertionFailedError.new(message.to_s)
+ end
+ end
+ end
+
+ ##
+ # Asserts that +boolean+ is not false or nil.
+ #
+ # Example:
+ # assert [1, 2].include?(5)
+
+ public
+ def assert(boolean, message=nil)
+ _wrap_assertion do
+ assert_block("assert should not be called with a block.") { !block_given? }
+ assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
+ end
+ end
+
+ ##
+ # Passes if +expected+ == +actual.
+ #
+ # Note that the ordering of arguments is important, since a helpful
+ # error message is generated when this one fails that tells you the
+ # values of expected and actual.
+ #
+ # Example:
+ # assert_equal 'MY STRING', 'my string'.upcase
+
+ public
+ def assert_equal(expected, actual, message=nil)
+ full_message = build_message(message, <<EOT, expected, actual)
+<?> expected but was
+<?>.
+EOT
+ assert_block(full_message) { expected == actual }
+ end
+
+ private
+ def _check_exception_class(args) # :nodoc:
+ args.partition do |klass|
+ next if klass.instance_of?(Module)
+ assert(Exception >= klass, "Should expect a class of exception, #{klass}")
+ true
+ end
+ end
+
+ private
+ def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
+ exceptions.include?(actual_exception.class) or
+ modules.any? {|mod| actual_exception.is_a?(mod)}
+ end
+
+ ##
+ # Passes if the block raises one of the given exceptions.
+ #
+ # Example:
+ # assert_raise RuntimeError, LoadError do
+ # raise 'Boom!!!'
+ # end
+
+ public
+ def assert_raise(*args)
+ _wrap_assertion do
+ if Module === args.last
+ message = ""
+ else
+ message = args.pop
+ end
+ exceptions, modules = _check_exception_class(args)
+ expected = args.size == 1 ? args.first : args
+ actual_exception = nil
+ full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
+ assert_block(full_message) do
+ begin
+ yield
+ rescue Exception => actual_exception
+ break
+ end
+ false
+ end
+ full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
+ assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
+ actual_exception
+ end
+ end
+
+ ##
+ # Alias of assert_raise.
+ #
+ # Will be deprecated in 1.9, and removed in 2.0.
+
+ public
+ def assert_raises(*args, &block)
+ assert_raise(*args, &block)
+ end
+
+ ##
+ # Passes if +object+ .instance_of? +klass+
+ #
+ # Example:
+ # assert_instance_of String, 'foo'
+
+ public
+ def assert_instance_of(klass, object, message="")
+ _wrap_assertion do
+ assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
+ full_message = build_message(message, <<EOT, object, klass, object.class)
+<?> expected to be an instance of
+<?> but was
+<?>.
+EOT
+ assert_block(full_message){object.instance_of?(klass)}
+ end
+ end
+
+ ##
+ # Passes if +object+ is nil.
+ #
+ # Example:
+ # assert_nil [1, 2].uniq!
+
+ public
+ def assert_nil(object, message="")
+ assert_equal(nil, object, message)
+ end
+
+ ##
+ # Passes if +object+ .kind_of? +klass+
+ #
+ # Example:
+ # assert_kind_of Object, 'foo'
+
+ public
+ def assert_kind_of(klass, object, message="")
+ _wrap_assertion do
+ assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
+ full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
+ assert_block(full_message){object.kind_of?(klass)}
+ end
+ end
+
+ ##
+ # Passes if +object+ .respond_to? +method+
+ #
+ # Example:
+ # assert_respond_to 'bugbear', :slice
+
+ public
+ def assert_respond_to(object, method, message="")
+ _wrap_assertion do
+ full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
+
+ assert_block(full_message) do
+ method.kind_of?(Symbol) || method.respond_to?(:to_str)
+ end
+ full_message = build_message(message, <<EOT, object, object.class, method)
+<?>
+of type <?>
+expected to respond_to\\?<?>.
+EOT
+ assert_block(full_message) { object.respond_to?(method) }
+ end
+ end
+
+ ##
+ # Passes if +string+ =~ +pattern+.
+ #
+ # Example:
+ # assert_match(/\d+/, 'five, 6, seven')
+
+ public
+ def assert_match(pattern, string, message="")
+ _wrap_assertion do
+ pattern = case(pattern)
+ when String
+ Regexp.new(Regexp.escape(pattern))
+ else
+ pattern
+ end
+ full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
+ assert_block(full_message) { string =~ pattern }
+ end
+ end
+
+ ##
+ # Passes if +actual+ .equal? +expected+ (i.e. they are the same
+ # instance).
+ #
+ # Example:
+ # o = Object.new
+ # assert_same o, o
+
+ public
+ def assert_same(expected, actual, message="")
+ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
+<?>
+with id <?> expected to be equal\\? to
+<?>
+with id <?>.
+EOT
+ assert_block(full_message) { actual.equal?(expected) }
+ end
+
+ ##
+ # Compares the +object1+ with +object2+ using +operator+.
+ #
+ # Passes if object1.__send__(operator, object2) is true.
+ #
+ # Example:
+ # assert_operator 5, :>=, 4
+
+ public
+ def assert_operator(object1, operator, object2, message="")
+ _wrap_assertion do
+ full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
+ assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
+ full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
+<?> expected to be
+?
+<?>.
+EOT
+ assert_block(full_message) { object1.__send__(operator, object2) }
+ end
+ end
+
+ ##
+ # Passes if block does not raise an exception.
+ #
+ # Example:
+ # assert_nothing_raised do
+ # [1, 2].uniq
+ # end
+
+ public
+ def assert_nothing_raised(*args)
+ _wrap_assertion do
+ if Module === args.last
+ message = ""
+ else
+ message = args.pop
+ end
+ exceptions, modules = _check_exception_class(args)
+ begin
+ yield
+ rescue Exception => e
+ if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
+ _expected_exception?(e, exceptions, modules))
+ assert_block(build_message(message, "Exception raised:\n?", e)){false}
+ else
+ raise
+ end
+ end
+ nil
+ end
+ end
+
+ ##
+ # Flunk always fails.
+ #
+ # Example:
+ # flunk 'Not done testing yet.'
+
+ public
+ def flunk(message="Flunked")
+ assert_block(build_message(message)){false}
+ end
+
+ ##
+ # Passes if ! +actual+ .equal? +expected+
+ #
+ # Example:
+ # assert_not_same Object.new, Object.new
+
+ public
+ def assert_not_same(expected, actual, message="")
+ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
+<?>
+with id <?> expected to not be equal\\? to
+<?>
+with id <?>.
+EOT
+ assert_block(full_message) { !actual.equal?(expected) }
+ end
+
+ ##
+ # Passes if +expected+ != +actual+
+ #
+ # Example:
+ # assert_not_equal 'some string', 5
+
+ public
+ def assert_not_equal(expected, actual, message="")
+ full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
+ assert_block(full_message) { expected != actual }
+ end
+
+ ##
+ # Passes if ! +object+ .nil?
+ #
+ # Example:
+ # assert_not_nil '1 two 3'.sub!(/two/, '2')
+
+ public
+ def assert_not_nil(object, message="")
+ full_message = build_message(message, "<?> expected to not be nil.", object)
+ assert_block(full_message){!object.nil?}
+ end
+
+ ##
+ # Passes if +regexp+ !~ +string+
+ #
+ # Example:
+ # assert_no_match(/two/, 'one 2 three')
+
+ public
+ def assert_no_match(regexp, string, message="")
+ _wrap_assertion do
+ assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
+ full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
+ assert_block(full_message) { regexp !~ string }
+ end
+ end
+
+ UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
+ ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
+
+ ##
+ # Passes if the block throws +expected_symbol+
+ #
+ # Example:
+ # assert_throws :done do
+ # throw :done
+ # end
+
+ public
+ def assert_throws(expected_symbol, message="", &proc)
+ _wrap_assertion do
+ assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
+ assert_block("Should have passed a block to assert_throws."){block_given?}
+ caught = true
+ begin
+ catch(expected_symbol) do
+ proc.call
+ caught = false
+ end
+ full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
+ assert_block(full_message){caught}
+ rescue NameError, ThreadError => error
+ if UncaughtThrow[error.class] !~ error.message
+ raise error
+ end
+ full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
+ flunk(full_message)
+ end
+ end
+ end
+
+ ##
+ # Passes if block does not throw anything.
+ #
+ # Example:
+ # assert_nothing_thrown do
+ # [1, 2].uniq
+ # end
+
+ public
+ def assert_nothing_thrown(message="", &proc)
+ _wrap_assertion do
+ assert(block_given?, "Should have passed a block to assert_nothing_thrown")
+ begin
+ proc.call
+ rescue NameError, ThreadError => error
+ if UncaughtThrow[error.class] !~ error.message
+ raise error
+ end
+ full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
+ flunk(full_message)
+ end
+ assert(true, "Expected nothing to be thrown")
+ end
+ end
+
+ ##
+ # Passes if +expected_float+ and +actual_float+ are equal
+ # within +delta+ tolerance.
+ #
+ # Example:
+ # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
+
+ public
+ def assert_in_delta(expected_float, actual_float, delta, message="")
+ _wrap_assertion do
+ {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
+ assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
+ end
+ assert_operator(delta, :>=, 0.0, "The delta should not be negative")
+ full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
+<?> and
+<?> expected to be within
+<?> of each other.
+EOT
+ assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
+ end
+ end
+
+ ##
+ # Passes if the method send returns a true value.
+ #
+ # +send_array+ is composed of:
+ # * A receiver
+ # * A method
+ # * Arguments to the method
+ #
+ # Example:
+ # assert_send [[1, 2], :include?, 4]
+
+ public
+ def assert_send(send_array, message="")
+ _wrap_assertion do
+ assert_instance_of(Array, send_array, "assert_send requires an array of send information")
+ assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
+ full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
+<?> expected to respond to
+<?(?)> with a true value.
+EOT
+ assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
+ end
+ end
+
+ ##
+ # Builds a failure message. +head+ is added before the +template+ and
+ # +arguments+ replaces the '?'s positionally in the template.
+
+ public
+ def build_message(head, template=nil, *arguments)
+ template &&= template.chomp
+ return AssertionMessage.new(head, template, arguments)
+ end
+
+ private
+ def _wrap_assertion
+ @_assertion_wrapped ||= false
+ unless (@_assertion_wrapped)
+ @_assertion_wrapped = true
+ begin
+ add_assertion
+ return yield
+ ensure
+ @_assertion_wrapped = false
+ end
+ else
+ return yield
+ end
+ end
+
+ ##
+ # Called whenever an assertion is made. Define this in classes that
+ # include Test::Unit::Assertions to record assertion counts.
+
+ private
+ def add_assertion
+ end
+
+ ##
+ # Select whether or not to use the pretty-printer. If this option is set
+ # to false before any assertions are made, pp.rb will not be required.
+
+ public
+ def self.use_pp=(value)
+ AssertionMessage.use_pp = value
+ end
+
+ # :stopdoc:
+
+ class AssertionMessage
+ @use_pp = true
+ class << self
+ attr_accessor :use_pp
+ end
+
+ class Literal
+ def initialize(value)
+ @value = value
+ end
+
+ def inspect
+ @value.to_s
+ end
+ end
+
+ class Template
+ def self.create(string)
+ parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
+ self.new(parts)
+ end
+
+ attr_reader :count
+
+ def initialize(parts)
+ @parts = parts
+ @count = parts.find_all{|e| e == '?'}.size
+ end
+
+ def result(parameters)
+ raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
+ params = parameters.dup
+ @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
+ end
+ end
+
+ def self.literal(value)
+ Literal.new(value)
+ end
+
+ def initialize(head, template_string, parameters)
+ @head = head
+ @template_string = template_string
+ @parameters = parameters
+ end
+
+ def convert(object)
+ case object
+ when Exception
+ <<EOM.chop
+Class: <#{convert(object.class)}>
+Message: <#{convert(object.message)}>
+---Backtrace---
+#{filter_backtrace(object.backtrace).join("\n")}
+---------------
+EOM
+ else
+ if(self.class.use_pp)
+ begin
+ require 'pp'
+ rescue LoadError
+ self.class.use_pp = false
+ return object.inspect
+ end unless(defined?(PP))
+ PP.pp(object, '').chomp
+ else
+ object.inspect
+ end
+ end
+ end
+
+ def template
+ @template ||= Template.create(@template_string)
+ end
+
+ def add_period(string)
+ (string =~ /\.\Z/ ? string : string + '.')
+ end
+
+ def to_s
+ message_parts = []
+ if (@head)
+ head = @head.to_s
+ unless(head.empty?)
+ message_parts << add_period(head)
+ end
+ end
+ tail = template.result(@parameters.collect{|e| convert(e)})
+ message_parts << tail unless(tail.empty?)
+ message_parts.join("\n")
+ end
+
+ MICRONAUTUNIT_FILE_SEPARATORS = %r{[\\/:]}
+ MICRONAUTUNIT_PREFIX = __FILE__.split(MICRONAUTUNIT_FILE_SEPARATORS)[0..-3]
+ MICRONAUTUNIT_RB_FILE = /\.rb\Z/
+
+ def filter_backtrace(backtrace, prefix=nil)
+ return ["No backtrace"] unless(backtrace)
+ split_p = if(prefix)
+ prefix.split(MICRONAUTUNIT_FILE_SEPARATORS)
+ else
+ MICRONAUTUNIT_PREFIX
+ end
+ match = proc do |e|
+ split_e = e.split(MICRONAUTUNIT_FILE_SEPARATORS)[0, split_p.size]
+ next false unless(split_e[0..-2] == split_p[0..-2])
+ split_e[-1].sub(MICRONAUTUNIT_RB_FILE, '') == split_p[-1]
+ end
+ return backtrace unless(backtrace.detect(&match))
+ found_prefix = false
+ new_backtrace = backtrace.reverse.reject do |e|
+ if(match[e])
+ found_prefix = true
+ true
+ elsif(found_prefix)
+ false
+ else
+ true
+ end
+ end.reverse
+ new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
+ new_backtrace = new_backtrace.reject(&match)
+ new_backtrace.empty? ? backtrace : new_backtrace
+ end
+
+ end
+
+ # :startdoc:
+
+ end
+ end
+end
208 lib/rspec/unit/test_case.rb
@@ -0,0 +1,208 @@
+require 'rspec/unit/assertions'
+
+module Rspec
+
+ module Core
+ class ExampleGroup
+ include ::Rspec::Unit::Assertions
+ end
+
+ class <<Runner
+ alias :rspec_unit_original_installed_at_exit? :installed_at_exit?
+ def installed_at_exit?; true; end
+ end
+ end
+
+ module Unit
+ class AssertionFailedError < Rspec::Matchers::MatcherError
+ end
+
+ class TestCase < Rspec::Core::ExampleGroup
+
+ TEST_METHOD_PATTERN = /^test_/
+
+ alias_example_to :test, :test_unit => true
+
+ @configuration = Rspec::Core.configuration
+
+ class <<self
+ def inherited(klass)
+ super
+
+ install_setup_and_teardown(klass)
+
+ # extra_metadata = {
+ # :test_unit => true,
+ # :caller => caller
+ # }
+ # extra_metadata[:file_path] = extra_metadata[:caller][0].split(":")[0].strip
+ # extra_metadata[:line_number] = extra_metadata[:caller][0].split(":")[1].to_i
+ #
+ # klass_name = klass.name(false)
+ # desc = (klass_name.nil? || klass_name.empty?) ? 'Anonymous TestCase' : "TestCase #{klass_name}"
+ # klass.set_it_up(desc, extra_metadata)
+ name = test_case_name(klass)
+ _build(klass, caller, [name, {}])
+ klass.metadata[:example_group][:test_unit] = true
+ end
+
+ def test_case_name(klass)
+ class_name = klass.name(false)
+ (class_name.nil? || class_name.empty?) ? 'Anonymous TestCase' : "TestCase #{class_name}"
+ end
+
+ def test_case_info(options)
+ metadata[:example_group].update(options)
+ end
+
+ def test_info(options)
+ @_metadata_for_next = options
+ end
+
+ def method_added(id)
+ name = id.to_s
+ caller_lines[name] = caller
+ if test_method?(name)
+ test_method_metadata[name] = @_metadata_for_next
+ @_metadata_for_next = nil
+ end
+ end
+
+ def examples
+ @tc_examples ||= ExamplesCollection.new(self, super)
+ end
+
+ def ancestors(superclass_last=false)
+ superclass_last ? super[0..-2] : super[1..-1]
+ end
+
+ def to_s
+ self == Rspec::Unit::TestCase ? 'Rspec::Unit::TestCase' : super
+ end
+
+ private
+
+ def caller_lines
+ @_caller_lines ||= {}
+ end
+
+ def test_method_metadata
+ @_test_method_metadata ||= {}
+ end
+
+ def install_setup_and_teardown(klass)
+ # Only do this for direct descendants, because test/unit chains
+ # fixtures through explicit calls to super.
+ if self == Rspec::Unit::TestCase
+ klass.class_eval do
+ before {setup}
+ after {teardown}
+ end
+ end
+ end
+
+ def test_method?(method_name)
+ method_name =~ TEST_METHOD_PATTERN &&
+ public_method_defined?(method_name) &&
+ (-1..0).include?(instance_method(method_name).arity)
+ end
+
+ def test_methods
+ public_instance_methods(true).select{|m| test_method?(m)}
+ end
+
+ def number_of_tests
+ test_methods.size
+ end
+
+ def tests
+ @tests ||= test_methods.sort.map do |m|
+ name = "#{metadata[:example_group][:name]}##{m}"
+ meta = (test_method_metadata[m] || {}).merge({:caller => caller_lines[m],
+ :full_description => name,
+ :test_unit => true})
+ Core::Example.new(self, m, meta, proc{execute(m)})
+ end
+ end
+
+ end
+
+ def initialize
+ @test_passed = true
+ super
+ end
+
+ def setup
+ end
+
+ def teardown
+ end
+
+ def execute(method)
+ begin
+ send(method.to_sym)
+ rescue
+ @test_passed = false
+ raise
+ end
+ end
+
+ private
+
+ def passed?
+ @test_passed
+ end
+
+ class ExamplesCollection
+ include Enumerable
+
+ attr_accessor :testcase, :core_examples
+
+ def initialize(testcase, core_examples)
+ @testcase, @core_examples = testcase, core_examples
+ end
+
+ def tests
+ testcase.send(:tests)
+ end
+
+ def number_of_tests
+ testcase.send(:number_of_tests)
+ end
+
+ def size
+ core_examples.size + number_of_tests
+ end
+
+ def empty?
+ core_examples.empty? && number_of_tests == 0
+ end
+
+ def first
+ core_examples.first || tests.first
+ end
+
+ def <<(example)
+ core_examples << example
+ end
+
+ def each
+ core_examples.each{|ex| yield(ex)}
+ tests.each{|test| yield(test)}
+ end
+
+ def to_ary
+ core_examples + tests
+ end
+ end
+
+ end
+ end
+
+ module Core
+ class <<Runner
+ alias :installed_at_exit? :rspec_unit_original_installed_at_exit?
+ remove_method :rspec_unit_original_installed_at_exit?
+ end
+ end
+end
52 rspec-unit.gemspec
@@ -0,0 +1,52 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{micronaut-unit}
+ s.version = "0.2.0"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Glenn Vanderburg"]
+ s.date = %q{2009-05-23}
+ s.email = %q{glv@vanderburg.org}
+ s.extra_rdoc_files = [
+ "LICENSE",
+ "README.md"
+ ]
+ s.files = [
+ "LICENSE",
+ "README.md",
+ "Rakefile",
+ "VERSION.yml",
+ "examples/assertions_example.rb",
+ "examples/example_helper.rb",
+ "examples/test_case_example.rb",
+ "lib/micronaut-unit.rb",
+ "lib/micronaut/unit.rb",
+ "lib/micronaut/unit/assertions.rb",
+ "lib/micronaut/unit/test_case.rb"
+ ]
+ s.homepage = %q{http://github.com/glv/micronaut-unit}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubyforge_project = %q{glv}
+ s.rubygems_version = %q{1.3.3}
+ s.summary = %q{Adds test/unit compatibility to Micronaut.}
+ s.test_files = [
+ "examples/assertions_example.rb",
+ "examples/example_helper.rb",
+ "examples/test_case_example.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
+ else
+ s.add_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
+ end
+ else
+ s.add_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
+ end
+end
528 spec/assertions_spec.rb
@@ -0,0 +1,528 @@
+# Author:: Nathaniel Talbott.
+# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
+# License:: Ruby license.
+
+require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
+
+# This is borrowed with minor changes from test/unit. I'm leaving it in test/unit format
+# rather than converting to rspec-style. ---glv
+class TC_Assertions < Rspec::Unit::TestCase
+ AssertionFailedError = Rspec::Unit::AssertionFailedError
+
+ def check(value, message="")
+ add_assertion
+ if (!value)
+ raise AssertionFailedError.new(message)
+ end
+ end
+
+ def check_assertions(expect_fail, expected_message="", return_value_expected=false)
+ @actual_assertion_count = 0
+ failed = true
+ actual_message = nil
+ @catch_assertions = true
+ return_value = nil
+ begin
+ return_value = yield
+ failed = false
+ rescue AssertionFailedError => error
+ actual_message = error.message
+ end
+ @catch_assertions = false
+ check(expect_fail == failed, (expect_fail ? "Should have failed, but didn't" : "Should not have failed, but did with message\n<#{actual_message}>"))
+ check(1 == @actual_assertion_count, "Should have made one assertion but made <#{@actual_assertion_count}>")
+ if (expect_fail)
+ case expected_message
+ when String
+ check(actual_message == expected_message, "Should have the correct message.\n<#{expected_message.inspect}> expected but was\n<#{actual_message.inspect}>")
+ when Regexp
+ check(actual_message =~ expected_message, "The message should match correctly.\n</#{expected_message.source}/> expected to match\n<#{actual_message.inspect}>")
+ else
+ check(false, "Incorrect expected message type in assert_nothing_failed")
+ end
+ else
+ if (!return_value_expected)
+ check(return_value.nil?, "Should not return a value but returned <#{return_value}>")
+ else
+ check(!return_value.nil?, "Should return a value")
+ end
+ end
+ return return_value
+ end
+
+ def check_nothing_fails(return_value_expected=false, &proc)
+ check_assertions(false, "", return_value_expected, &proc)
+ end
+
+ def check_fails(expected_message="", &proc)
+ check_assertions(true, expected_message, &proc)
+ end
+
+ def test_assert_block
+ check_nothing_fails {
+ assert_block {true}
+ }
+ check_nothing_fails {
+ assert_block("successful assert_block") {true}
+ }
+ check_nothing_fails {
+ assert_block("successful assert_block") {true}
+ }
+ check_fails("assert_block failed.") {
+ assert_block {false}
+ }
+ check_fails("failed assert_block") {
+ assert_block("failed assert_block") {false}
+ }
+ end
+
+ def test_assert
+ check_nothing_fails{assert("a")}
+ check_nothing_fails{assert(true)}
+ check_nothing_fails{assert(true, "successful assert")}
+ check_fails("<nil> is not true."){assert(nil)}
+ check_fails("<false> is not true."){assert(false)}
+ check_fails("failed assert.\n<false> is not true."){assert(false, "failed assert")}
+ end
+
+ def test_assert_equal
+ check_nothing_fails {
+ assert_equal("string1", "string1")
+ }
+ check_nothing_fails {
+ assert_equal( "string1", "string1", "successful assert_equal")
+ }
+ check_nothing_fails {
+ assert_equal("string1", "string1", "successful assert_equal")
+ }
+ check_fails(%Q{<"string1"> expected but was\n<"string2">.}) {
+ assert_equal("string1", "string2")
+ }
+ check_fails(%Q{failed assert_equal.\n<"string1"> expected but was\n<"string2">.}) {
+ assert_equal("string1", "string2", "failed assert_equal")
+ }
+ check_fails(%Q{<"1"> expected but was\n<1>.}) do
+ assert_equal("1", 1)
+ end
+ end
+
+ def test_assert_raise
+ return_value = nil
+ check_nothing_fails(true) {
+ return_value = assert_raise(RuntimeError) {
+ raise "Error"
+ }
+ }
+ check(return_value.kind_of?(Exception), "Should have returned the exception from a successful assert_raise")
+ check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise")
+ check_nothing_fails(true) {
+ assert_raise(ArgumentError, "successful assert_raise") {
+ raise ArgumentError.new("Error")
+ }
+ }
+ check_nothing_fails(true) {
+ assert_raise(RuntimeError) {
+ raise "Error"
+ }
+ }
+ check_nothing_fails(true) {
+ assert_raise(RuntimeError, "successful assert_raise") {
+ raise "Error"
+ }
+ }
+ check_fails("<RuntimeError> exception expected but none was thrown.") {
+ assert_raise(RuntimeError) {
+ 1 + 1
+ }
+ }
+ check_fails(%r{\Afailed assert_raise.\n<ArgumentError> exception expected but was\nClass: <RuntimeError>\nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) {
+ assert_raise(ArgumentError, "failed assert_raise") {
+ raise "Error"
+ }
+ }
+ check_fails("Should expect a class of exception, Object.\n<false> is not true.") {
+ assert_nothing_raised(Object) {
+ 1 + 1
+ }
+ }
+
+ exceptions = [ArgumentError, TypeError]
+ modules = [Math, Comparable]
+ rescues = exceptions + modules
+ exceptions.each do |exc|
+ check_nothing_fails(true) {
+ return_value = assert_raise(*rescues) {
+ raise exc, "Error"
+ }
+ }
+ check(return_value.instance_of?(exc), "Should have returned #{exc} but was #{return_value.class}")
+ check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise")
+ end
+ modules.each do |mod|
+ check_nothing_fails(true) {
+ return_value = assert_raise(*rescues) {
+ raise Exception.new("Error").extend(mod)
+ }
+ }
+ check(mod === return_value, "Should have returned #{mod}")
+ check(return_value.message == "Error", "Should have returned the correct exception from a successful assert_raise")
+ end
+ check_fails("<[ArgumentError, TypeError, Math, Comparable]> exception expected but none was thrown.") {
+ assert_raise(*rescues) {
+ 1 + 1
+ }
+ }
+ check_fails(%r{\Afailed assert_raise.
+<\[ArgumentError, TypeError\]> exception expected but was
+Class: <RuntimeError>
+Message: <"Error">
+---Backtrace---
+.+
+---------------\Z}m) {
+ assert_raise(ArgumentError, TypeError, "failed assert_raise") {
+ raise "Error"
+ }
+ }
+ end
+
+ def test_assert_instance_of
+ check_nothing_fails {
+ assert_instance_of(String, "string")
+ }
+ check_nothing_fails {
+ assert_instance_of(String, "string", "successful assert_instance_of")
+ }
+ check_nothing_fails {
+ assert_instance_of(String, "string", "successful assert_instance_of")
+ }
+ check_fails(%Q{<"string"> expected to be an instance of\n<Hash> but was\n<String>.}) {
+ assert_instance_of(Hash, "string")
+ }
+ check_fails(%Q{failed assert_instance_of.\n<"string"> expected to be an instance of\n<Hash> but was\n<String>.}) {
+ assert_instance_of(Hash, "string", "failed assert_instance_of")
+ }
+ end
+
+ def test_assert_nil
+ check_nothing_fails {
+ assert_nil(nil)
+ }
+ check_nothing_fails {
+ assert_nil(nil, "successful assert_nil")
+ }
+ check_nothing_fails {
+ assert_nil(nil, "successful assert_nil")
+ }
+ check_fails(%Q{<nil> expected but was\n<"string">.}) {
+ assert_nil("string")
+ }
+ check_fails(%Q{failed assert_nil.\n<nil> expected but was\n<"string">.}) {
+ assert_nil("string", "failed assert_nil")
+ }
+ end
+
+ def test_assert_not_nil
+ check_nothing_fails{assert_not_nil(false)}
+ check_nothing_fails{assert_not_nil(false, "message")}
+ check_fails("<nil> expected to not be nil."){assert_not_nil(nil)}
+ check_fails("message.\n<nil> expected to not be nil.") {assert_not_nil(nil, "message")}
+ end
+
+ def test_assert_kind_of
+ check_nothing_fails {
+ assert_kind_of(Module, Array)
+ }
+ check_nothing_fails {
+ assert_kind_of(Object, "string", "successful assert_kind_of")
+ }
+ check_nothing_fails {
+ assert_kind_of(Object, "string", "successful assert_kind_of")
+ }
+ check_nothing_fails {
+ assert_kind_of(Comparable, 1)
+ }
+ check_fails(%Q{<"string">\nexpected to be kind_of?\n<Class> but was\n<String>.}) {
+ assert_kind_of(Class, "string")
+ }
+ check_fails(%Q{failed assert_kind_of.\n<"string">\nexpected to be kind_of?\n<Class> but was\n<String>.}) {
+ assert_kind_of(Class, "string", "failed assert_kind_of")
+ }
+ end
+
+ def test_assert_match
+ check_nothing_fails {
+ assert_match(/strin./, "string")
+ }
+ check_nothing_fails {
+ assert_match("strin", "string")
+ }
+ check_nothing_fails {
+ assert_match(/strin./, "string", "successful assert_match")
+ }
+ check_nothing_fails {
+ assert_match(/strin./, "string", "successful assert_match")
+ }
+ check_fails(%Q{<"string"> expected to be =~\n</slin./>.}) {
+ assert_match(/slin./, "string")
+ }
+ check_fails(%Q{<"string"> expected to be =~\n</strin\\./>.}) {
+ assert_match("strin.", "string")
+ }
+ check_fails(%Q{failed assert_match.\n<"string"> expected to be =~\n</slin./>.}) {
+ assert_match(/slin./, "string", "failed assert_match")
+ }
+ end
+
+ def test_assert_same
+ thing = "thing"
+ check_nothing_fails {
+ assert_same(thing, thing)
+ }
+ check_nothing_fails {
+ assert_same(thing, thing, "successful assert_same")
+ }
+ check_nothing_fails {
+ assert_same(thing, thing, "successful assert_same")
+ }
+ thing2 = "thing"
+ check_fails(%Q{<"thing">\nwith id <#{thing.__id__}> expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) {
+ assert_same(thing, thing2)
+ }
+ check_fails(%Q{failed assert_same.\n<"thing">\nwith id <#{thing.__id__}> expected to be equal? to\n<"thing">\nwith id <#{thing2.__id__}>.}) {
+ assert_same(thing, thing2, "failed assert_same")
+ }
+ end
+
+ def test_assert_nothing_raised
+ check_nothing_fails {
+ assert_nothing_raised {
+ 1 + 1
+ }
+ }
+ check_nothing_fails {
+ assert_nothing_raised("successful assert_nothing_raised") {
+ 1 + 1
+ }
+ }
+ check_nothing_fails {
+ assert_nothing_raised("successful assert_nothing_raised") {
+ 1 + 1
+ }
+ }
+ check_nothing_fails {
+ begin
+ assert_nothing_raised(RuntimeError, StandardError, Comparable, "successful assert_nothing_raised") {
+ raise ZeroDivisionError.new("ArgumentError")
+ }
+ rescue ZeroDivisionError
+ end
+ }
+ check_fails("Should expect a class of exception, Object.\n<false> is not true.") {
+ assert_nothing_raised(Object) {
+ 1 + 1
+ }
+ }
+ check_fails(%r{\AException raised:\nClass: <RuntimeError>\nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) {
+ assert_nothing_raised {
+ raise "Error"
+ }
+ }
+ check_fails(%r{\Afailed assert_nothing_raised\.\nException raised:\nClass: <RuntimeError>\nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) {
+ assert_nothing_raised("failed assert_nothing_raised") {
+ raise "Error"
+ }
+ }
+ check_fails(%r{\AException raised:\nClass: <RuntimeError>\nMessage: <"Error">\n---Backtrace---\n.+\n---------------\Z}m) {
+ assert_nothing_raised(StandardError, RuntimeError) {
+ raise "Error"
+ }
+ }
+ check_fails("Failure.") do
+ assert_nothing_raised do
+ flunk("Failure")
+ end
+ end
+ end
+
+ def test_flunk
+ check_fails("Flunked.") {
+ flunk
+ }
+ check_fails("flunk message.") {
+ flunk("flunk message")
+ }
+ end
+
+ def test_assert_not_same
+ thing = "thing"
+ thing2 = "thing"
+ check_nothing_fails {
+ assert_not_same(thing, thing2)
+ }
+ check_nothing_fails {
+ assert_not_same(thing, thing2, "message")
+ }
+ check_fails(%Q{<"thing">\nwith id <#{thing.__id__}> expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) {
+ assert_not_same(thing, thing)
+ }
+ check_fails(%Q{message.\n<"thing">\nwith id <#{thing.__id__}> expected to not be equal? to\n<"thing">\nwith id <#{thing.__id__}>.}) {
+ assert_not_same(thing, thing, "message")
+ }
+ end
+
+ def test_assert_not_equal
+ check_nothing_fails {
+ assert_not_equal("string1", "string2")
+ }
+ check_nothing_fails {
+ assert_not_equal("string1", "string2", "message")
+ }
+ check_fails(%Q{<"string"> expected to be != to\n<"string">.}) {
+ assert_not_equal("string", "string")
+ }
+ check_fails(%Q{message.\n<"string"> expected to be != to\n<"string">.}) {
+ assert_not_equal("string", "string", "message")
+ }
+ end
+
+ def test_assert_no_match
+ check_nothing_fails{assert_no_match(/sling/, "string")}
+ check_nothing_fails{assert_no_match(/sling/, "string", "message")}
+ check_fails(%Q{The first argument to assert_no_match should be a Regexp.\n<"asdf"> expected to be an instance of\n<Regexp> but was\n<String>.}) do
+ assert_no_match("asdf", "asdf")
+ end
+ check_fails(%Q{</string/> expected to not match\n<"string">.}) do
+ assert_no_match(/string/, "string")
+ end
+ check_fails(%Q{message.\n</string/> expected to not match\n<"string">.}) do
+ assert_no_match(/string/, "string", "message")
+ end
+ end
+
+ def test_assert_throws
+ check_nothing_fails {
+ assert_throws(:thing, "message") {
+ throw :thing
+ }
+ }
+ check_fails("message.\n<:thing> expected to be thrown but\n<:thing2> was thrown.") {
+ assert_throws(:thing, "message") {
+ throw :thing2
+ }
+ }
+ check_fails("message.\n<:thing> should have been thrown.") {
+ assert_throws(:thing, "message") {
+ 1 + 1
+ }
+ }
+ end
+
+ def test_assert_nothing_thrown
+ check_nothing_fails {
+ assert_nothing_thrown("message") {
+ 1 + 1
+ }
+ }
+ check_fails("message.\n<:thing> was thrown when nothing was expected.") {
+ assert_nothing_thrown("message") {
+ throw :thing
+ }
+ }
+ end
+
+ def test_assert_operator
+ check_nothing_fails {
+ assert_operator("thing", :==, "thing", "message")
+ }
+ check_fails(%Q{<0.15>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to?(:to_str).}) do
+ assert_operator("thing", 0.15, "thing")
+ end
+ check_fails(%Q{message.\n<"thing1"> expected to be\n==\n<"thing2">.}) {
+ assert_operator("thing1", :==, "thing2", "message")
+ }
+ end
+
+ def test_assert_respond_to
+ check_nothing_fails {
+ assert_respond_to("thing", :to_s, "message")
+ }
+ check_nothing_fails {
+ assert_respond_to("thing", "to_s", "message")
+ }
+ check_fails("<0.15>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to?(:to_str).") {
+ assert_respond_to("thing", 0.15)
+ }
+ check_fails("message.\n<:symbol>\nof type <Symbol>\nexpected to respond_to?<:non_existent>.") {
+ assert_respond_to(:symbol, :non_existent, "message")
+ }
+ end
+
+ def test_assert_in_delta
+ check_nothing_fails {
+ assert_in_delta(1.4, 1.4, 0)
+ }
+ check_nothing_fails {
+ assert_in_delta(0.5, 0.4, 0.1, "message")
+ }
+ check_nothing_fails {
+ float_thing = Object.new
+ def float_thing.to_f
+ 0.2
+ end
+ assert_in_delta(0.1, float_thing, 0.1)
+ }
+ check_fails("message.\n<0.5> and\n<0.4> expected to be within\n<0.05> of each other.") {
+ assert_in_delta(0.5, 0.4, 0.05, "message")
+ }
+ check_fails(%r{The arguments must respond to to_f; the first float did not\.\n<.+>\nof type <Object>\nexpected to respond_to\?<:to_f>.}) {
+ assert_in_delta(Object.new, 0.4, 0.1)
+ }
+ check_fails("The delta should not be negative.\n<-0.1> expected to be\n>=\n<0.0>.") {
+ assert_in_delta(0.5, 0.4, -0.1, "message")
+ }
+ end
+
+ def test_assert_send
+ object = Object.new
+ class << object
+ private
+ def return_argument(argument, bogus)
+ return argument
+ end
+ end
+ check_nothing_fails {
+ assert_send([object, :return_argument, true, "bogus"], "message")
+ }
+ check_fails(%r{\Amessage\.\n<.+> expected to respond to\n<return_argument\(\[false, "bogus"\]\)> with a true value.\Z}) {
+ assert_send([object, :return_argument, false, "bogus"], "message")
+ }
+ end
+
+ def test_condition_invariant
+ object = Object.new
+ def object.inspect
+ @changed = true
+ end
+ def object.==(other)
+ @changed ||= false
+ return (!@changed)
+ end
+ check_nothing_fails {
+ assert_equal(object, object, "message")
+ }
+ end
+
+ def add_failure(message, location=caller)
+ if (!@catch_assertions)
+ super
+ end
+ end
+
+ def add_assertion
+ if (!@catch_assertions)
+ super
+ else
+ @actual_assertion_count += 1
+ end
+ end
+end
42 spec/spec_helper.rb
@@ -0,0 +1,42 @@
+require 'rubygems'
+
+require 'rspec'
+gem 'mocha'
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+
+require 'rspec-unit'
+
+def remove_last_describe_from_world
+ Rspec::Core.world.example_groups.pop
+end
+
+def isolate_example_group
+ if block_given?
+ yield
+ Rspec::Core.world.example_groups.pop
+ end
+end
+
+def use_formatter(new_formatter)
+ original_formatter = Rspec::Core.configuration.formatter
+ Rspec::Core.configuration.instance_variable_set(:@formatter, new_formatter)
+ yield
+ensure
+ Rspec::Core.configuration.instance_variable_set(:@formatter, original_formatter)
+end
+
+def in_editor?
+ ENV.has_key?('TM_MODE') || ENV.has_key?('EMACS') || ENV.has_key?('VIM')
+end
+
+Rspec.configure do |c|
+ c.mock_framework = :mocha
+ c.filter_run :focused => true
+ c.run_all_when_everything_filtered = true
+ c.color_enabled = !in_editor?
+ c.alias_example_to :fit, :focused => true
+ c.profile_examples = false
+ c.formatter = :documentation # if ENV["RUN_CODE_RUN"] == "true"
+end
+
404 spec/test_case_spec.rb
@@ -0,0 +1,404 @@
+require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
+
+describe Rspec::Core::ExampleGroup do
+ it "supports using assertions in examples" do
+ lambda {assert_equal 1, 1}.should_not raise_error
+ end
+end
+
+describe Rspec::Unit::TestCase do
+ before do
+ @foo = Class.new(Rspec::Unit::TestCase)
+ @foo_definition_line = __LINE__ - 1
+ @caller_at_foo_definition = caller
+ @formatter = Rspec::Core::Formatters::BaseFormatter.new
+ end
+
+ after do
+ remove_last_describe_from_world
+ end
+
+ def run_tests(klass)
+ klass.examples_to_run.replace(klass.examples)
+ klass.run(@formatter)
+ end
+
+ describe "identifying test methods" do
+ it "ignores methods that don't begin with 'test_'" do
+ @foo.class_eval do
+ def bar; end
+ end
+ @foo.examples.should be_empty
+ end
+
+ it "notices methods that begin with 'test_'" do
+ @foo.class_eval do
+ def test_bar; end
+ end
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'test_bar'
+ end
+
+ it "ignores non-public test methods" do
+ @foo.class_eval do
+ protected
+ def test_foo; end
+ private
+ def test_bar; end
+ end
+ @foo.examples.should be_empty
+ end
+
+ it "ignores methods with good names but positive arity" do
+ @foo.class_eval do
+ def test_foo(a); end
+ def test_bar(a, *b); end
+ end
+ @foo.examples.should be_empty
+ end
+
+ it "creates an example to represent a test method" do
+ @foo.class_eval do
+ def test_bar; end
+ end
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'test_bar'
+ end
+
+ it "creates examples for inherited methods" do
+ @foo.class_eval do
+ def test_bar; end
+ end
+ isolate_example_group do
+ bar = Class.new(@foo)
+ bar.examples.size.should == 1
+ bar.examples.first.metadata[:description].should == 'test_bar'
+ end
+ end
+
+ it "creates examples for methods newly added to superclasses" do
+ isolate_example_group do
+ bar = Class.new(@foo)
+ @foo.class_eval do
+ def test_bar; end
+ end
+ bar.examples.size.should == 1
+ bar.examples.first.metadata[:description].should == 'test_bar'
+ end
+ end
+
+ it "creates examples for methods added by inclusion of a module" do
+ bar = Module.new do
+ def test_bar; end
+ end
+ @foo.send(:include, bar)
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'test_bar'
+ end
+ end
+
+ describe "running test methods" do
+ it "runs the test methods as examples" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ def test_bar; end
+ end
+ @foo.expects(:test_bar).once
+ run_tests(@foo)
+ end
+ end
+
+ it "brackets test methods with setup/teardown" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ def test_bar; end
+ def test_baz; end
+ end
+
+ test_run = sequence('test_run')
+
+ @foo.expects(:setup) .once.in_sequence(test_run)
+ @foo.expects(:test_bar).once.in_sequence(test_run)
+ @foo.expects(:teardown).once.in_sequence(test_run)
+ @foo.expects(:setup) .once.in_sequence(test_run)
+ @foo.expects(:test_baz).once.in_sequence(test_run)
+ @foo.expects(:teardown).once.in_sequence(test_run)
+
+ run_tests(@foo)
+ end
+ end
+
+ it "records failed tests in Rspec style" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ def test_bar; flunk; end
+ end
+ run_tests(@foo)
+ @formatter.failed_examples.size.should == 1
+ end
+ end
+
+ it "indicates failed tests in test/unit style" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ class <<self; attr_accessor :_passed; end
+ def test_bar; flunk; end
+ def teardown; self.class._passed = passed?; end
+ end
+ run_tests(@foo)
+ @foo._passed.should == false
+ end
+ end
+
+ it "records passed tests in Rspec style" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ def test_bar; assert true; end
+ end
+ run_tests(@foo)
+ @formatter.failed_examples.should be_empty
+ end
+ end
+
+ it "indicates passed tests in test/unit style" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ class <<self; attr_accessor :_passed; end
+ def test_bar; assert true; end
+ def teardown; self.class._passed = passed?; end
+ end
+ run_tests(@foo)
+ @foo._passed.should == true
+ end
+ end
+ end
+
+ describe "ancestors" do
+ before do
+ @bar = Class.new(@foo)
+ remove_last_describe_from_world
+ end
+
+ it "removes TestCase from the beginning if superclass_last is false" do
+ @bar.ancestors.should == [@foo, @bar]
+ end
+
+ it "removes TestCase from the end if superclass_last is true" do
+ @bar.ancestors(true).should == [@bar, @foo]
+ end
+ end
+
+ describe "test class metadata" do
+ isolate_example_group do
+ class SampleTestCaseForName < Rspec::Unit::TestCase
+ end
+ end
+
+ it "sets :name to 'TestCase' and the class name if the class has one" do
+ SampleTestCaseForName.metadata[:example_group][:name].should == "TestCase SampleTestCaseForName"
+ end
+
+ it "sets :name to 'Anonymous TestCase' for anonymous test classes" do
+ @foo.metadata[:example_group][:name].should == "Anonymous TestCase"
+ end
+
+ it "sets :description to be the same as :name" do
+ @foo.metadata[:example_group][:description].should == @foo.metadata[:example_group][:name]
+ SampleTestCaseForName.metadata[:example_group][:description].should == SampleTestCaseForName.metadata[:example_group][:name]
+ end
+
+ it "adds :test_unit => true" do
+ @foo.metadata[:example_group][:test_unit].should be_true
+ end
+
+ it "sets :file_path to the file in which the class is first defined" do
+ @foo.metadata[:example_group][:file_path].should == __FILE__
+ end
+
+ it "sets :line_number to the line where the class definition begins" do
+ @foo.metadata[:example_group][:line_number].should == @foo_definition_line
+ end
+
+ it "sets :location to file_path and line_number" do
+ @foo.metadata[:example_group][:location].should == "#{__FILE__}:#{@foo_definition_line}"
+ end
+
+ it "sets :caller" do
+ @foo.metadata[:example_group][:caller].first.should =~ Regexp.new(Regexp.escape(@foo.metadata[:example_group][:location]))
+ @foo.metadata[:example_group][:caller].size.should == @caller_at_foo_definition.size + 3
+ end
+
+ it "has nil for :block and :describes" do
+ @foo.metadata[:example_group][:block].should be_nil
+ @foo.metadata[:example_group][:describes].should be_nil
+ end
+
+ it "records test_case_info options" do
+ @foo.class_eval do
+ test_case_info :foo => :bar
+ end
+ @foo.metadata[:example_group][:foo].should == :bar
+ end
+ end
+
+ describe "test method metadata" do
+ def find_example(example_group, name)
+ example_group.examples.find{|e|e.description == name}
+ end
+
+ def test_baz_metadata
+ find_example(@foo, 'test_baz').metadata
+ end
+
+ it "uses a test method's name as its :description" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ @foo.examples.first.metadata[:description].should == 'test_baz'
+ end
+
+ it "uses a test method's name with the class name as its :full_description" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:full_description].should == 'Anonymous TestCase#test_baz'
+ end
+
+ it "adds :test_unit => true" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:test_unit].should be_true
+ end
+
+ it "sets :file_path to the file where the method is defined" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:file_path].should == __FILE__
+ end
+
+ it "sets :line_number to the line where the method definition begins" do
+ @foo.class_eval do
+ def test_baz
+ end
+ end
+ test_baz_metadata[:line_number].should == (__LINE__ - 3)
+ end
+
+ it "sets :location to file path and line number" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:location].should == "#{__FILE__}:#{__LINE__-2}"
+ end
+
+ it "sets :example_group and :behaviour to the test case class's metadata" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:example_group].should == @foo.metadata[:example_group]
+ test_baz_metadata[:behaviour].should == @foo.metadata[:example_group]
+ end
+
+ it "sets :caller" do
+ @foo.class_eval do
+ def test_baz; end
+ end
+ test_baz_metadata[:caller].first.should == @foo.examples.first.metadata[:location]
+ test_baz_metadata[:caller].size.should == caller.size + 3
+ end
+
+ it "records test_info options for next test method" do
+ @foo.class_eval do
+ test_info :foo => :bar
+ def test_baz; end
+ end
+ test_baz_metadata[:foo].should == :bar
+ end
+
+ it "records test_info options *only* for next test method" do
+ @foo.class_eval do
+ test_info :foo => :bar
+ def test_baz; end
+ def test_quux; end
+ end
+ find_example(@foo, 'test_quux').metadata[:foo].should be_nil
+ end
+ end
+
+ describe "examples within a test case" do
+ it "allows 'example' to create an example" do
+ @foo.class_eval do
+ example "should bar" do end
+ end
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'should bar'
+ end
+
+ it "supports 'test' as an alias of example" do
+ @foo.class_eval do
+ test "should bar" do end
+ end
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'should bar'
+ @foo.examples.first.metadata[:test_unit].should be_true
+ end
+
+ it "heeds 'alias_example_to'" do
+ @foo.class_eval do
+ alias_example_to :make_test
+ make_test "should bar" do end
+ end
+ @foo.examples.size.should == 1
+ @foo.examples.first.metadata[:description].should == 'should bar'
+ end
+
+ it "allows defining 'before' blocks" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ before {bar}
+ def test_bar; end
+ end
+
+ @foo.expects(:bar).once
+ run_tests(@foo)
+ end
+ end
+
+ it "allows defining 'after' blocks" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ after {bar}
+ def test_bar; end
+ end
+
+ @foo.expects(:bar).once
+ run_tests(@foo)
+ end
+ end
+
+ it "allows examples to use instance variables created in 'setup'" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ def setup; super; @quux = 42; end
+ it "quux" do @quux.should == 42 end
+ end
+ run_tests(@foo)
+ @formatter.failed_examples.should be_empty
+ end
+ end
+
+ it "allows test methods to use instance variables created in 'before' blocks" do
+ use_formatter(@formatter) do
+ @foo.class_eval do
+ before { @quux = 42 }
+ def test_quux; assert_equal 42, @quux; end
+ end
+ run_tests(@foo)
+ @formatter.failed_examples.should be_empty
+ end
+ end
+ end
+
+end

0 comments on commit 19f0aa8

Please sign in to comment.