Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit, port from micronaut-unit to rspec 2

  • Loading branch information...
commit 19f0aa8a7f3991eece21dc98c417d52355aa5709 0 parents
Glenn Vanderburg authored February 21, 2010
5  .document
... ...
@@ -0,0 +1,5 @@
  1
+README.rdoc
  2
+lib/**/*.rb
  3
+bin/*
  4
+features/**/*.feature
  5
+LICENSE
5  .gitignore
... ...
@@ -0,0 +1,5 @@
  1
+*.sw?
  2
+.DS_Store
  3
+coverage
  4
+rdoc
  5
+pkg
20  LICENSE
... ...
@@ -0,0 +1,20 @@
  1
+Copyright (c) 2009 Glenn Vanderburg
  2
+
  3
+Permission is hereby granted, free of charge, to any person obtaining
  4
+a copy of this software and associated documentation files (the
  5
+"Software"), to deal in the Software without restriction, including
  6
+without limitation the rights to use, copy, modify, merge, publish,
  7
+distribute, sublicense, and/or sell copies of the Software, and to
  8
+permit persons to whom the Software is furnished to do so, subject to
  9
+the following conditions:
  10
+
  11
+The above copyright notice and this permission notice shall be
  12
+included in all copies or substantial portions of the Software.
  13
+
  14
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
82  README.md
Source Rendered
... ...
@@ -0,0 +1,82 @@
  1
+# rspec-unit
  2
+
  3
+Test::Unit compatibility for rspec.
  4
+
  5
+Just add this to your code:
  6
+
  7
+    require 'rspec/unit'
  8
+
  9
+and then you can write test classes like this:
  10
+
  11
+    class FooTest < Rspec::Unit::TestCase
  12
+      def test_foo
  13
+        assert_equal 3, Foo::major_version
  14
+      end
  15
+    end
  16
+
  17
+Using the `test_info` method, you can attach metadata to the next
  18
+defined test (this works much the same way Rake's `desc` method
  19
+attaches a description string to the next defined task):
  20
+
  21
+    test_info :speed => 'slow', :run => 'nightly'
  22
+    def test_tarantula_multipass
  23
+      # ...
  24
+    end
  25
+    
  26
+You can also attach metadata to the entire class with the
  27
+`test_case_info` method:
  28
+
  29
+    class BarTest < Rspec::Unit::TestCase
  30
+      test_case_info :integration => true
  31
+      
  32
+      # ...
  33
+    end
  34
+
  35
+Each instance of `Rspec::Unit::TestCase` is equivalent to a
  36
+rspec `describe` block, so it can also include `it` blocks,
  37
+`before` and `after` blocks, and nested `describe` blocks.  Test
  38
+methods and `it` blocks can contain either assertions or `should`
  39
+expressions.  `test` blocks (as found in Rails 2.x) also work.
  40
+
  41
+Additionally, assertions can be used inside ordinary rspec
  42
+examples.
  43
+
  44
+## Rationale
  45
+
  46
+The point of this gem is not that I think test/unit is a better way
  47
+to write tests than the RSpec style.  I admit that I'm a TDD oldtimer
  48
+who sees RSpec as mostly a cosmetic (rather than fundamental) change,
  49
+but that doesn't mean it's not an important change.  My curmudgeonly
  50
+nature has its limits, and I do find specs a big improvement.
  51
+
  52
+So why rspec-unit?  Three reasons:
  53
+
  54
+1. I wanted to show off the generality of Rspec's architecture.
  55
+   On the surface, Rspec might not seem all that compelling
  56
+   (since it's basically an RSpec work-alike).  But it's really a
  57
+   fantastic tool; it's just that the 
  58
+   [innovation is all under the hood][uth], in a way that makes it
  59
+   easy to change the surface aspects.  I hope rspec-unit can
  60
+   serve as an example for anyone who wants to experiment with new
  61
+   ways of expressing tests and specs on top of Rspec.
  62
+2. Many projects with existing test/unit test suites might want to
  63
+   benefit from Rspec's [metadata goodness][metadata], or begin
  64
+   a gradual, piecemeal change to an RSpec style.  That's pretty
  65
+   easy to do with rspec-unit.
  66
+3. Even when writing specs and examples, I frequently encounter
  67
+   cases where an assertion is more expressive than a `should`
  68
+   expression.  It's nice just to have assertions supported within
  69
+   Rspec examples.
  70
+      
  71
+[uth]: http://blog.thinkrelevance.com/2009/4/1/micronaut-innovation-under-the-hood
  72
+[metadata]: http://blog.thinkrelevance.com/2009/3/26/introducing-micronaut-a-lightweight-bdd-framework
  73
+
  74
+## To Do
  75
+
  76
+It would be nice to try using the assertion code from minitest,
  77
+which is much more compact and seems less coupled than that from
  78
+test/unit.
  79
+
  80
+### Copyright
  81
+
  82
+Copyright (c) 2009 Glenn Vanderburg. See LICENSE for details.
53  Rakefile
... ...
@@ -0,0 +1,53 @@
  1
+require 'rubygems'
  2
+require 'rake'
  3
+
  4
+begin
  5
+  require 'jeweler'
  6
+  Jeweler::Tasks.new do |gem|
  7
+    gem.name = "rspec-unit"
  8
+    gem.summary = %Q{Adds test/unit compatibility to Rspec.}
  9
+    gem.email = "glv@vanderburg.org"
  10
+    gem.homepage = "http://github.com/glv/rspec-unit"
  11
+    gem.authors = ["Glenn Vanderburg"]
  12
+    gem.rubyforge_project = "rspec-unit"
  13
+    gem.add_dependency('rspec', '>= 2.0.0.a7')
  14
+    gem.has_rdoc = false
  15
+    gem.files =  FileList["[A-Z]*", "{bin,lib,examples}/**/*"] 
  16
+    gem.rubyforge_project = 'glv' 
  17
+    # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
  18
+  end
  19
+
  20
+  Jeweler::RubyforgeTasks.new
  21
+rescue LoadError
  22
+  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
  23
+end
  24
+
  25
+require 'rspec/core/rake_task'
  26
+Rspec::Core::RakeTask.new(:examples) do |examples|
  27
+  examples.pattern = 'spec/**/*_spec.rb'
  28
+  examples.ruby_opts = '-Ilib -Ispec'
  29
+end
  30
+
  31
+Rspec::Core::RakeTask.new(:rcov) do |examples|
  32
+  examples.pattern = 'spec/**/*_spec.rb'
  33
+  examples.rcov_opts = '-Ilib -Ispec -x "/Library/Ruby/Gems,^spec/"'
  34
+  examples.rcov = true
  35
+end
  36
+
  37
+task :default => :examples
  38
+
  39
+require 'rake/rdoctask'
  40
+Rake::RDocTask.new do |rdoc|
  41
+  if File.exist?('VERSION.yml')
  42
+    config = YAML.load(File.read('VERSION.yml'))
  43
+    version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
  44
+  else
  45
+    version = ""
  46
+  end
  47
+
  48
+  rdoc.rdoc_dir = 'rdoc'
  49
+  rdoc.title = "rspec-unit #{version}"
  50
+  rdoc.rdoc_files.include('README*')
  51
+  rdoc.rdoc_files.include('lib/**/*.rb')
  52
+end
  53
+
4  VERSION.yml
... ...
@@ -0,0 +1,4 @@
  1
+--- 
  2
+:patch: 0
  3
+:major: 0
  4
+:minor: 1
1  lib/rspec-unit.rb
... ...
@@ -0,0 +1 @@
  1
+require 'rspec/unit'
3  lib/rspec/unit.rb
... ...
@@ -0,0 +1,3 @@
  1
+# This file may be the starting point in some cases, so pull in all of micronaut:
  2
+require 'rspec'
  3
+require 'rspec/unit/test_case'
651  lib/rspec/unit/assertions.rb
... ...
@@ -0,0 +1,651 @@
  1
+# Author:: Nathaniel Talbott.
  2
+# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
  3
+# License:: Ruby license.
  4
+
  5
+module Rspec
  6
+  module Unit
  7
+
  8
+    ##
  9
+    # Test::Unit::Assertions contains the standard Test::Unit assertions.
  10
+    # Assertions is included in Test::Unit::TestCase.
  11
+    #
  12
+    # To include it in your own code and use its functionality, you simply
  13
+    # need to rescue Test::Unit::AssertionFailedError. Additionally you may
  14
+    # override add_assertion to get notified whenever an assertion is made.
  15
+    #
  16
+    # Notes:
  17
+    # * The message to each assertion, if given, will be propagated with the
  18
+    #   failure.
  19
+    # * It is easy to add your own assertions based on assert_block().
  20
+    #
  21
+    # = Example Custom Assertion
  22
+    #
  23
+    #   def deny(boolean, message = nil)
  24
+    #     message = build_message message, '<?> is not false or nil.', boolean
  25
+    #     assert_block message do
  26
+    #       not boolean
  27
+    #     end
  28
+    #   end
  29
+
  30
+    module Assertions
  31
+
  32
+      ##
  33
+      # The assertion upon which all other assertions are based. Passes if the
  34
+      # block yields true.
  35
+      #
  36
+      # Example:
  37
+      #   assert_block "Couldn't do the thing" do
  38
+      #     do_the_thing
  39
+      #   end
  40
+
  41
+      public
  42
+      def assert_block(message="assert_block failed.") # :yields: 
  43
+        _wrap_assertion do
  44
+          if (! yield)
  45
+            raise AssertionFailedError.new(message.to_s)
  46
+          end
  47
+        end
  48
+      end
  49
+
  50
+      ##
  51
+      # Asserts that +boolean+ is not false or nil.
  52
+      #
  53
+      # Example:
  54
+      #   assert [1, 2].include?(5)
  55
+
  56
+      public
  57
+      def assert(boolean, message=nil)
  58
+        _wrap_assertion do
  59
+          assert_block("assert should not be called with a block.") { !block_given? }
  60
+          assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
  61
+        end
  62
+      end
  63
+
  64
+      ##
  65
+      # Passes if +expected+ == +actual.
  66
+      #
  67
+      # Note that the ordering of arguments is important, since a helpful
  68
+      # error message is generated when this one fails that tells you the
  69
+      # values of expected and actual.
  70
+      #
  71
+      # Example:
  72
+      #   assert_equal 'MY STRING', 'my string'.upcase
  73
+
  74
+      public
  75
+      def assert_equal(expected, actual, message=nil)
  76
+        full_message = build_message(message, <<EOT, expected, actual)
  77
+<?> expected but was
  78
+<?>.
  79
+EOT
  80
+        assert_block(full_message) { expected == actual }
  81
+      end
  82
+
  83
+      private
  84
+      def _check_exception_class(args) # :nodoc:
  85
+        args.partition do |klass|
  86
+          next if klass.instance_of?(Module)
  87
+          assert(Exception >= klass, "Should expect a class of exception, #{klass}")
  88
+          true
  89
+        end
  90
+      end
  91
+
  92
+      private
  93
+      def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
  94
+        exceptions.include?(actual_exception.class) or
  95
+          modules.any? {|mod| actual_exception.is_a?(mod)}
  96
+      end
  97
+
  98
+      ##
  99
+      # Passes if the block raises one of the given exceptions.
  100
+      #
  101
+      # Example:
  102
+      #   assert_raise RuntimeError, LoadError do
  103
+      #     raise 'Boom!!!'
  104
+      #   end
  105
+
  106
+      public
  107
+      def assert_raise(*args)
  108
+        _wrap_assertion do
  109
+          if Module === args.last
  110
+            message = ""
  111
+          else
  112
+            message = args.pop
  113
+          end
  114
+          exceptions, modules = _check_exception_class(args)
  115
+          expected = args.size == 1 ? args.first : args
  116
+          actual_exception = nil
  117
+          full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
  118
+          assert_block(full_message) do
  119
+            begin
  120
+              yield
  121
+            rescue Exception => actual_exception
  122
+              break
  123
+            end
  124
+            false
  125
+          end
  126
+          full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
  127
+          assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
  128
+          actual_exception
  129
+        end
  130
+      end
  131
+
  132
+      ##
  133
+      # Alias of assert_raise.
  134
+      #
  135
+      # Will be deprecated in 1.9, and removed in 2.0.
  136
+
  137
+      public
  138
+      def assert_raises(*args, &block)
  139
+        assert_raise(*args, &block)
  140
+      end
  141
+
  142
+      ##
  143
+      # Passes if +object+ .instance_of? +klass+
  144
+      #
  145
+      # Example:
  146
+      #   assert_instance_of String, 'foo'
  147
+
  148
+      public
  149
+      def assert_instance_of(klass, object, message="")
  150
+        _wrap_assertion do
  151
+          assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
  152
+          full_message = build_message(message, <<EOT, object, klass, object.class)
  153
+<?> expected to be an instance of
  154
+<?> but was
  155
+<?>.
  156
+EOT
  157
+          assert_block(full_message){object.instance_of?(klass)}
  158
+        end
  159
+      end
  160
+
  161
+      ##
  162
+      # Passes if +object+ is nil.
  163
+      #
  164
+      # Example:
  165
+      #   assert_nil [1, 2].uniq!
  166
+
  167
+      public
  168
+      def assert_nil(object, message="")
  169
+        assert_equal(nil, object, message)
  170
+      end
  171
+
  172
+      ##
  173
+      # Passes if +object+ .kind_of? +klass+
  174
+      #
  175
+      # Example:
  176
+      #   assert_kind_of Object, 'foo'
  177
+
  178
+      public
  179
+      def assert_kind_of(klass, object, message="")
  180
+        _wrap_assertion do
  181
+          assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
  182
+          full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
  183
+          assert_block(full_message){object.kind_of?(klass)}
  184
+        end
  185
+      end
  186
+
  187
+      ##
  188
+      # Passes if +object+ .respond_to? +method+
  189
+      #
  190
+      # Example:
  191
+      #   assert_respond_to 'bugbear', :slice
  192
+
  193
+      public
  194
+      def assert_respond_to(object, method, message="")
  195
+        _wrap_assertion do
  196
+          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)
  197
+
  198
+          assert_block(full_message) do
  199
+            method.kind_of?(Symbol) || method.respond_to?(:to_str)
  200
+          end
  201
+          full_message = build_message(message, <<EOT, object, object.class, method)
  202
+<?>
  203
+of type <?>
  204
+expected to respond_to\\?<?>.
  205
+EOT
  206
+          assert_block(full_message) { object.respond_to?(method) }
  207
+        end
  208
+      end
  209
+
  210
+      ##
  211
+      # Passes if +string+ =~ +pattern+.
  212
+      #
  213
+      # Example:
  214
+      #   assert_match(/\d+/, 'five, 6, seven')
  215
+
  216
+      public
  217
+      def assert_match(pattern, string, message="")
  218
+        _wrap_assertion do
  219
+          pattern = case(pattern)
  220
+            when String
  221
+              Regexp.new(Regexp.escape(pattern))
  222
+            else
  223
+              pattern
  224
+          end
  225
+          full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
  226
+          assert_block(full_message) { string =~ pattern }
  227
+        end
  228
+      end
  229
+
  230
+      ##
  231
+      # Passes if +actual+ .equal? +expected+ (i.e. they are the same
  232
+      # instance).
  233
+      #
  234
+      # Example:
  235
+      #   o = Object.new
  236
+      #   assert_same o, o
  237
+
  238
+      public
  239
+      def assert_same(expected, actual, message="")
  240
+        full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
  241
+<?>
  242
+with id <?> expected to be equal\\? to
  243
+<?>
  244
+with id <?>.
  245
+EOT
  246
+        assert_block(full_message) { actual.equal?(expected) }
  247
+      end
  248
+
  249
+      ##
  250
+      # Compares the +object1+ with +object2+ using +operator+.
  251
+      #
  252
+      # Passes if object1.__send__(operator, object2) is true.
  253
+      #
  254
+      # Example:
  255
+      #   assert_operator 5, :>=, 4
  256
+
  257
+      public
  258
+      def assert_operator(object1, operator, object2, message="")
  259
+        _wrap_assertion do
  260
+          full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
  261
+          assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
  262
+          full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
  263
+<?> expected to be
  264
+?
  265
+<?>.
  266
+EOT
  267
+          assert_block(full_message) { object1.__send__(operator, object2) }
  268
+        end
  269
+      end
  270
+
  271
+      ##
  272
+      # Passes if block does not raise an exception.
  273
+      #
  274
+      # Example:
  275
+      #   assert_nothing_raised do
  276
+      #     [1, 2].uniq
  277
+      #   end
  278
+
  279
+      public
  280
+      def assert_nothing_raised(*args)
  281
+        _wrap_assertion do
  282
+          if Module === args.last
  283
+            message = ""
  284
+          else
  285
+            message = args.pop
  286
+          end
  287
+          exceptions, modules = _check_exception_class(args)
  288
+          begin
  289
+            yield
  290
+          rescue Exception => e
  291
+            if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
  292
+                _expected_exception?(e, exceptions, modules))
  293
+              assert_block(build_message(message, "Exception raised:\n?", e)){false}
  294
+            else
  295
+              raise
  296
+            end
  297
+          end
  298
+          nil
  299
+        end
  300
+      end
  301
+
  302
+      ##
  303
+      # Flunk always fails.
  304
+      #
  305
+      # Example:
  306
+      #   flunk 'Not done testing yet.'
  307
+
  308
+      public
  309
+      def flunk(message="Flunked")
  310
+        assert_block(build_message(message)){false}
  311
+      end
  312
+
  313
+      ##
  314
+      # Passes if ! +actual+ .equal? +expected+
  315
+      #
  316
+      # Example:
  317
+      #   assert_not_same Object.new, Object.new
  318
+
  319
+      public
  320
+      def assert_not_same(expected, actual, message="")
  321
+        full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
  322
+<?>
  323
+with id <?> expected to not be equal\\? to
  324
+<?>
  325
+with id <?>.
  326
+EOT
  327
+        assert_block(full_message) { !actual.equal?(expected) }
  328
+      end
  329
+
  330
+      ##
  331
+      # Passes if +expected+ != +actual+
  332
+      #
  333
+      # Example:
  334
+      #   assert_not_equal 'some string', 5
  335
+
  336
+      public
  337
+      def assert_not_equal(expected, actual, message="")
  338
+        full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
  339
+        assert_block(full_message) { expected != actual }
  340
+      end
  341
+
  342
+      ##
  343
+      # Passes if ! +object+ .nil?
  344
+      #
  345
+      # Example:
  346
+      #   assert_not_nil '1 two 3'.sub!(/two/, '2')
  347
+
  348
+      public
  349
+      def assert_not_nil(object, message="")
  350
+        full_message = build_message(message, "<?> expected to not be nil.", object)
  351
+        assert_block(full_message){!object.nil?}
  352
+      end
  353
+
  354
+      ##
  355
+      # Passes if +regexp+ !~ +string+ 
  356
+      #
  357
+      # Example:
  358
+      #   assert_no_match(/two/, 'one 2 three')
  359
+
  360
+      public
  361
+      def assert_no_match(regexp, string, message="")
  362
+        _wrap_assertion do
  363
+          assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
  364
+          full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
  365
+          assert_block(full_message) { regexp !~ string }
  366
+        end
  367
+      end
  368
+
  369
+      UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
  370
+                       ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
  371
+
  372
+      ##
  373
+      # Passes if the block throws +expected_symbol+
  374
+      #
  375
+      # Example:
  376
+      #   assert_throws :done do
  377
+      #     throw :done
  378
+      #   end
  379
+
  380
+      public
  381
+      def assert_throws(expected_symbol, message="", &proc)
  382
+        _wrap_assertion do
  383
+          assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
  384
+          assert_block("Should have passed a block to assert_throws."){block_given?}
  385
+          caught = true
  386
+          begin
  387
+            catch(expected_symbol) do
  388
+              proc.call
  389
+              caught = false
  390
+            end
  391
+            full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
  392
+            assert_block(full_message){caught}
  393
+          rescue NameError, ThreadError => error
  394
+            if UncaughtThrow[error.class] !~ error.message
  395
+              raise error
  396
+            end
  397
+            full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
  398
+            flunk(full_message)
  399
+          end
  400
+        end
  401
+      end
  402
+
  403
+      ##
  404
+      # Passes if block does not throw anything.
  405
+      #
  406
+      # Example:
  407
+      #  assert_nothing_thrown do
  408
+      #    [1, 2].uniq
  409
+      #  end
  410
+
  411
+      public
  412
+      def assert_nothing_thrown(message="", &proc)
  413
+        _wrap_assertion do
  414
+          assert(block_given?, "Should have passed a block to assert_nothing_thrown")
  415
+          begin
  416
+            proc.call
  417
+          rescue NameError, ThreadError => error
  418
+            if UncaughtThrow[error.class] !~ error.message
  419
+              raise error
  420
+            end
  421
+            full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
  422
+            flunk(full_message)
  423
+          end
  424
+          assert(true, "Expected nothing to be thrown")
  425
+        end
  426
+      end
  427
+
  428
+      ##
  429
+      # Passes if +expected_float+ and +actual_float+ are equal
  430
+      # within +delta+ tolerance.
  431
+      #
  432
+      # Example:
  433
+      #   assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
  434
+
  435
+      public
  436
+      def assert_in_delta(expected_float, actual_float, delta, message="")
  437
+        _wrap_assertion do
  438
+          {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
  439
+            assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
  440
+          end
  441
+          assert_operator(delta, :>=, 0.0, "The delta should not be negative")
  442
+          full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
  443
+<?> and
  444
+<?> expected to be within
  445
+<?> of each other.
  446
+EOT
  447
+          assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
  448
+        end
  449
+      end
  450
+
  451
+      ##
  452
+      # Passes if the method send returns a true value.
  453
+      #
  454
+      # +send_array+ is composed of:
  455
+      # * A receiver
  456
+      # * A method
  457
+      # * Arguments to the method
  458
+      #
  459
+      # Example:
  460
+      #   assert_send [[1, 2], :include?, 4]
  461
+
  462
+      public
  463
+      def assert_send(send_array, message="")
  464
+        _wrap_assertion do
  465
+          assert_instance_of(Array, send_array, "assert_send requires an array of send information")
  466
+          assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
  467
+          full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
  468
+<?> expected to respond to
  469
+<?(?)> with a true value.
  470
+EOT
  471
+          assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
  472
+        end
  473
+      end
  474
+
  475
+      ##
  476
+      # Builds a failure message.  +head+ is added before the +template+ and
  477
+      # +arguments+ replaces the '?'s positionally in the template.
  478
+
  479
+      public
  480
+      def build_message(head, template=nil, *arguments)
  481
+        template &&= template.chomp
  482
+        return AssertionMessage.new(head, template, arguments)
  483
+      end
  484
+
  485
+      private
  486
+      def _wrap_assertion
  487
+        @_assertion_wrapped ||= false
  488
+        unless (@_assertion_wrapped)
  489
+          @_assertion_wrapped = true
  490
+          begin
  491
+            add_assertion
  492
+            return yield
  493
+          ensure
  494
+            @_assertion_wrapped = false
  495
+          end
  496
+        else
  497
+          return yield
  498
+        end
  499
+      end
  500
+      
  501
+      ##
  502
+      # Called whenever an assertion is made.  Define this in classes that
  503
+      # include Test::Unit::Assertions to record assertion counts.
  504
+
  505
+      private
  506
+      def add_assertion
  507
+      end
  508
+
  509
+      ##
  510
+      # Select whether or not to use the pretty-printer. If this option is set
  511
+      # to false before any assertions are made, pp.rb will not be required.
  512
+
  513
+      public
  514
+      def self.use_pp=(value)
  515
+        AssertionMessage.use_pp = value
  516
+      end
  517
+      
  518
+      # :stopdoc:
  519
+
  520
+      class AssertionMessage
  521
+        @use_pp = true
  522
+        class << self
  523
+          attr_accessor :use_pp
  524
+        end
  525
+
  526
+        class Literal
  527
+          def initialize(value)
  528
+            @value = value
  529
+          end
  530
+          
  531
+          def inspect
  532
+            @value.to_s
  533
+          end
  534
+        end
  535
+
  536
+        class Template
  537
+          def self.create(string)
  538
+            parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
  539
+            self.new(parts)
  540
+          end
  541
+
  542
+          attr_reader :count
  543
+
  544
+          def initialize(parts)
  545
+            @parts = parts
  546
+            @count = parts.find_all{|e| e == '?'}.size
  547
+          end
  548
+
  549
+          def result(parameters)
  550
+            raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
  551
+            params = parameters.dup
  552
+            @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
  553
+          end
  554
+        end
  555
+
  556
+        def self.literal(value)
  557
+          Literal.new(value)
  558
+        end
  559
+
  560
+        def initialize(head, template_string, parameters)
  561
+          @head = head
  562
+          @template_string = template_string
  563
+          @parameters = parameters
  564
+        end
  565
+
  566
+        def convert(object)
  567
+          case object
  568
+            when Exception
  569
+              <<EOM.chop
  570
+Class: <#{convert(object.class)}>
  571
+Message: <#{convert(object.message)}>
  572
+---Backtrace---
  573
+#{filter_backtrace(object.backtrace).join("\n")}
  574
+---------------
  575
+EOM
  576
+            else
  577
+              if(self.class.use_pp)
  578
+                begin
  579
+                  require 'pp'
  580
+                rescue LoadError
  581
+                  self.class.use_pp = false
  582
+                  return object.inspect
  583
+                end unless(defined?(PP))
  584
+                PP.pp(object, '').chomp
  585
+              else
  586
+                object.inspect
  587
+              end
  588
+          end
  589
+        end
  590
+
  591
+        def template
  592
+          @template ||= Template.create(@template_string)
  593
+        end
  594
+
  595
+        def add_period(string)
  596
+          (string =~ /\.\Z/ ? string : string + '.')
  597
+        end
  598
+
  599
+        def to_s
  600
+          message_parts = []
  601
+          if (@head)
  602
+            head = @head.to_s 
  603
+            unless(head.empty?)
  604
+              message_parts << add_period(head)
  605
+            end
  606
+          end
  607
+          tail = template.result(@parameters.collect{|e| convert(e)})
  608
+          message_parts << tail unless(tail.empty?)
  609
+          message_parts.join("\n")
  610
+        end
  611
+
  612
+        MICRONAUTUNIT_FILE_SEPARATORS = %r{[\\/:]}
  613
+        MICRONAUTUNIT_PREFIX = __FILE__.split(MICRONAUTUNIT_FILE_SEPARATORS)[0..-3]
  614
+        MICRONAUTUNIT_RB_FILE = /\.rb\Z/
  615
+      
  616
+        def filter_backtrace(backtrace, prefix=nil)
  617
+          return ["No backtrace"] unless(backtrace)
  618
+          split_p = if(prefix)
  619
+            prefix.split(MICRONAUTUNIT_FILE_SEPARATORS)
  620
+          else
  621
+            MICRONAUTUNIT_PREFIX
  622
+          end
  623
+          match = proc do |e|
  624
+            split_e = e.split(MICRONAUTUNIT_FILE_SEPARATORS)[0, split_p.size]
  625
+            next false unless(split_e[0..-2] == split_p[0..-2])
  626
+            split_e[-1].sub(MICRONAUTUNIT_RB_FILE, '') == split_p[-1]
  627
+          end
  628
+          return backtrace unless(backtrace.detect(&match))
  629
+          found_prefix = false
  630
+          new_backtrace = backtrace.reverse.reject do |e|
  631
+            if(match[e])
  632
+              found_prefix = true
  633
+              true
  634
+            elsif(found_prefix)
  635
+              false
  636
+            else
  637
+              true
  638
+            end
  639
+          end.reverse
  640
+          new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
  641
+          new_backtrace = new_backtrace.reject(&match)
  642
+          new_backtrace.empty? ? backtrace : new_backtrace
  643
+        end
  644
+        
  645
+      end
  646
+
  647
+      # :startdoc:
  648
+
  649
+    end
  650
+  end
  651
+end
208  lib/rspec/unit/test_case.rb
... ...
@@ -0,0 +1,208 @@
  1
+require 'rspec/unit/assertions'
  2
+
  3
+module Rspec
  4
+  
  5
+  module Core
  6
+    class ExampleGroup
  7
+      include ::Rspec::Unit::Assertions
  8
+    end
  9
+  
  10
+    class <<Runner
  11
+      alias :rspec_unit_original_installed_at_exit? :installed_at_exit?
  12
+      def installed_at_exit?; true; end
  13
+    end
  14
+  end
  15
+  
  16
+  module Unit
  17
+    class AssertionFailedError < Rspec::Matchers::MatcherError
  18
+    end
  19
+    
  20
+    class TestCase < Rspec::Core::ExampleGroup
  21
+      
  22
+      TEST_METHOD_PATTERN = /^test_/
  23
+
  24
+      alias_example_to :test, :test_unit => true
  25
+      
  26
+      @configuration = Rspec::Core.configuration
  27
+      
  28
+      class <<self
  29
+        def inherited(klass)
  30
+          super
  31
+          
  32
+          install_setup_and_teardown(klass)
  33
+                    
  34
+          # extra_metadata = {
  35
+          #   :test_unit => true,
  36
+          #   :caller => caller
  37
+          # }
  38
+          # extra_metadata[:file_path]   = extra_metadata[:caller][0].split(":")[0].strip
  39
+          # extra_metadata[:line_number] = extra_metadata[:caller][0].split(":")[1].to_i
  40
+          # 
  41
+          # klass_name = klass.name(false)
  42
+          # desc = (klass_name.nil? || klass_name.empty?) ? 'Anonymous TestCase' : "TestCase #{klass_name}"
  43
+          # klass.set_it_up(desc, extra_metadata)
  44
+          name = test_case_name(klass)
  45
+          _build(klass, caller, [name, {}])
  46
+          klass.metadata[:example_group][:test_unit] = true
  47
+        end
  48
+        
  49
+        def test_case_name(klass)
  50
+          class_name = klass.name(false)
  51
+          (class_name.nil? || class_name.empty?) ? 'Anonymous TestCase' : "TestCase #{class_name}"
  52
+        end
  53
+        
  54
+        def test_case_info(options)
  55
+          metadata[:example_group].update(options)
  56
+        end
  57
+        
  58
+        def test_info(options)
  59
+          @_metadata_for_next = options
  60
+        end
  61
+        
  62
+        def method_added(id)
  63
+          name = id.to_s
  64
+          caller_lines[name] = caller
  65
+          if test_method?(name)
  66
+            test_method_metadata[name] = @_metadata_for_next
  67
+            @_metadata_for_next = nil
  68
+          end
  69
+        end
  70
+        
  71
+        def examples
  72
+          @tc_examples ||= ExamplesCollection.new(self, super)
  73
+        end
  74
+        
  75
+        def ancestors(superclass_last=false)
  76
+          superclass_last ? super[0..-2] : super[1..-1]
  77
+        end
  78
+        
  79
+        def to_s
  80
+          self == Rspec::Unit::TestCase ? 'Rspec::Unit::TestCase' : super
  81
+        end
  82
+        
  83
+        private
  84
+        
  85
+        def caller_lines
  86
+          @_caller_lines ||= {}
  87
+        end
  88
+        
  89
+        def test_method_metadata
  90
+          @_test_method_metadata ||= {}
  91
+        end
  92
+        
  93
+        def install_setup_and_teardown(klass)
  94
+          # Only do this for direct descendants, because test/unit chains
  95
+          # fixtures through explicit calls to super.
  96
+          if self == Rspec::Unit::TestCase
  97
+            klass.class_eval do
  98
+              before {setup}
  99
+              after {teardown}
  100
+            end
  101
+          end
  102
+        end
  103
+        
  104
+        def test_method?(method_name)
  105
+          method_name =~ TEST_METHOD_PATTERN &&
  106
+          public_method_defined?(method_name) &&
  107
+          (-1..0).include?(instance_method(method_name).arity)
  108
+        end
  109
+                
  110
+        def test_methods
  111
+          public_instance_methods(true).select{|m| test_method?(m)}
  112
+        end
  113
+        
  114
+        def number_of_tests
  115
+          test_methods.size
  116
+        end
  117
+        
  118
+        def tests
  119
+          @tests ||= test_methods.sort.map do |m|
  120
+            name = "#{metadata[:example_group][:name]}##{m}"
  121
+            meta = (test_method_metadata[m] || {}).merge({:caller => caller_lines[m], 
  122
+                                                          :full_description => name,
  123
+                                                          :test_unit => true})
  124
+            Core::Example.new(self, m, meta, proc{execute(m)})
  125
+          end
  126
+        end
  127
+        
  128
+      end
  129
+          
  130
+      def initialize
  131
+        @test_passed = true
  132
+        super
  133
+      end
  134
+      
  135
+      def setup
  136
+      end
  137
+
  138
+      def teardown
  139
+      end    
  140
+      
  141
+      def execute(method)
  142
+        begin
  143
+          send(method.to_sym)
  144
+        rescue
  145
+          @test_passed = false
  146
+          raise
  147
+        end
  148
+      end
  149
+      
  150
+      private
  151
+
  152
+      def passed?  
  153
+        @test_passed
  154
+      end
  155
+      
  156
+      class ExamplesCollection
  157
+        include Enumerable
  158
+
  159
+        attr_accessor :testcase, :core_examples
  160
+        
  161
+        def initialize(testcase, core_examples)
  162
+          @testcase, @core_examples = testcase, core_examples
  163
+        end
  164
+        
  165
+        def tests
  166
+          testcase.send(:tests)
  167
+        end
  168
+        
  169
+        def number_of_tests
  170
+          testcase.send(:number_of_tests)
  171
+        end
  172
+        
  173
+        def size
  174
+          core_examples.size + number_of_tests
  175
+        end
  176
+        
  177
+        def empty?
  178
+          core_examples.empty? && number_of_tests == 0
  179
+        end
  180
+        
  181
+        def first
  182
+          core_examples.first || tests.first
  183
+        end
  184
+        
  185
+        def <<(example)
  186
+          core_examples << example
  187
+        end
  188
+        
  189
+        def each
  190
+          core_examples.each{|ex| yield(ex)}
  191
+          tests.each{|test| yield(test)}
  192
+        end
  193
+        
  194
+        def to_ary
  195
+          core_examples + tests
  196
+        end
  197
+      end
  198
+    
  199
+    end
  200
+  end
  201
+  
  202
+  module Core
  203
+    class <<Runner
  204
+      alias :installed_at_exit? :rspec_unit_original_installed_at_exit?
  205
+      remove_method :rspec_unit_original_installed_at_exit?
  206
+    end
  207
+  end
  208
+end
52  rspec-unit.gemspec
... ...
@@ -0,0 +1,52 @@
  1
+# -*- encoding: utf-8 -*-
  2
+
  3
+Gem::Specification.new do |s|
  4
+  s.name = %q{micronaut-unit}
  5
+  s.version = "0.2.0"
  6
+
  7
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
  8
+  s.authors = ["Glenn Vanderburg"]
  9
+  s.date = %q{2009-05-23}
  10
+  s.email = %q{glv@vanderburg.org}
  11
+  s.extra_rdoc_files = [
  12
+     "LICENSE",
  13
+     "README.md"
  14
+  ]
  15
+  s.files = [
  16
+     "LICENSE",
  17
+     "README.md",
  18
+     "Rakefile",
  19
+     "VERSION.yml",
  20
+     "examples/assertions_example.rb",
  21
+     "examples/example_helper.rb",
  22
+     "examples/test_case_example.rb",
  23
+     "lib/micronaut-unit.rb",
  24
+     "lib/micronaut/unit.rb",
  25
+     "lib/micronaut/unit/assertions.rb",
  26
+     "lib/micronaut/unit/test_case.rb"
  27
+  ]
  28
+  s.homepage = %q{http://github.com/glv/micronaut-unit}
  29
+  s.rdoc_options = ["--charset=UTF-8"]
  30
+  s.require_paths = ["lib"]
  31
+  s.rubyforge_project = %q{glv}
  32
+  s.rubygems_version = %q{1.3.3}
  33
+  s.summary = %q{Adds test/unit compatibility to Micronaut.}
  34
+  s.test_files = [
  35
+    "examples/assertions_example.rb",
  36
+     "examples/example_helper.rb",
  37
+     "examples/test_case_example.rb"
  38
+  ]
  39
+
  40
+  if s.respond_to? :specification_version then
  41
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
  42
+    s.specification_version = 3
  43
+
  44
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
  45
+      s.add_runtime_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
  46
+    else
  47
+      s.add_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
  48
+    end
  49
+  else
  50
+    s.add_dependency(%q<spicycode-micronaut>, [">= 0.2.9"])
  51
+  end
  52
+end
528  spec/assertions_spec.rb
... ...
@@ -0,0 +1,528 @@
  1
+# Author:: Nathaniel Talbott.
  2
+# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
  3
+# License:: Ruby license.
  4
+
  5
+require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
  6
+
  7
+# This is borrowed with minor changes from test/unit.  I'm leaving it in test/unit format
  8
+# rather than converting to rspec-style.  ---glv
  9
+class TC_Assertions < Rspec::Unit::TestCase
  10
+  AssertionFailedError = Rspec::Unit::AssertionFailedError
  11
+  
  12
+  def check(value, message="")
  13
+    add_assertion
  14
+    if (!value)
  15
+      raise AssertionFailedError.new(message)
  16
+    end
  17
+  end
  18
+
  19
+  def check_assertions(expect_fail, expected_message="", return_value_expected=false)
  20
+    @actual_assertion_count = 0
  21
+    failed = true
  22
+    actual_message = nil
  23
+    @catch_assertions = true
  24
+    return_value = nil
  25
+    begin
  26
+      return_value = yield
  27
+      failed = false
  28
+    rescue AssertionFailedError => error
  29
+      actual_message = error.message
  30
+    end
  31
+    @catch_assertions = false
  32
+    check(expect_fail == failed, (expect_fail ? "Should have failed, but didn't" : "Should not have failed, but did with message\n<#{actual_message}>"))
  33
+    check(1 == @actual_assertion_count, "Should have made one assertion but made <#{@actual_assertion_count}>")
  34
+    if (expect_fail)
  35
+      case expected_message
  36
+        when String
  37
+          check(actual_message == expected_message, "Should have the correct message.\n<#{expected_message.inspect}> expected but was\n<#{actual_message.inspect}>")
  38
+        when Regexp
  39
+          check(actual_message =~ expected_message, "The message should match correctly.\n</#{expected_message.source}/> expected to match\n<#{actual_message.inspect}>")
  40
+        else
  41
+          check(false, "Incorrect expected message type in assert_nothing_failed")
  42
+      end
  43
+    else
  44
+      if (!return_value_expected)
  45
+        check(return_value.nil?, "Should not return a value but returned <#{return_value}>")
  46
+      else
  47
+        check(!return_value.nil?, "Should return a value")
  48
+      end
  49
+    end
  50
+    return return_value
  51
+  end
  52
+  
  53
+  def check_nothing_fails(return_value_expected=false, &proc)
  54
+    check_assertions(false, "", return_value_expected, &proc)
  55
+  end
  56
+  
  57
+  def check_fails(expected_message="", &proc)
  58
+    check_assertions(true, expected_message, &proc)
  59
+  end
  60
+  
  61
+  def test_assert_block
  62
+    check_nothing_fails {
  63
+      assert_block {true}
  64
+    }
  65
+    check_nothing_fails {
  66
+      assert_block("successful assert_block") {true}
  67
+    }
  68
+    check_nothing_fails {
  69
+      assert_block("successful assert_block") {true}
  70
+    }
  71
+    check_fails("assert_block failed.") {
  72
+      assert_block {false}
  73
+    }
  74
+    check_fails("failed assert_block") {
  75
+      assert_block("failed assert_block") {false}
  76
+    }
  77
+  end