handoff 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -3,7 +3,9 @@ stdlib module +Forwardable+ makes implementing delegation simple and readable.
3
3
  Handoff is intended to make the code to test it just as simple and
4
4
  readable.
5
5
 
6
- Handoff depends on Mocha and Stubba (http://mocha.rubyforge.org).
6
+ You can install the latest gem using <code>gem install handoff</code> or download the .gem file from http://rubyforge.org/projects/handoff.
7
+
8
+ As of 0.2.0, Handoff no longer depends on Mocha and Stubba.
7
9
 
8
10
  Here's example_test.rb to give you an idea of what you can do:
9
11
 
@@ -1,4 +1,4 @@
1
- require 'handoff/assertion'
1
+ require File.expand_path(File.dirname(__FILE__) + '/handoff/assertion')
2
2
 
3
3
  # +require+ (or +require_gem+) 'handoff' and #assert_handoff can
4
4
  # be called from any Test::Unit::TestCase test method to create
@@ -7,14 +7,28 @@ require 'handoff/assertion'
7
7
  # After defining Handoff, this file includes it in Test::Unit::TestCase.
8
8
  module Handoff
9
9
 
10
+ TEARDOWN_ALIAS = :teardown_before_handoff_rewrite
11
+
10
12
  # Creates an Assertion, handing a it a mock named 'handoff delegate' on which
11
13
  # expectations will be set.
12
14
  def assert_handoff
13
- a = Handoff::Assertion.new(self.mock('handoff delegate'))
15
+ ensure_handoff_teardown_defined
16
+ a = Handoff::Assertion.new(self)
14
17
  handoff_assertions << a
15
18
  a
16
19
  end
17
20
 
21
+ def ensure_handoff_teardown_defined
22
+ return if respond_to?(TEARDOWN_ALIAS)
23
+ class << self
24
+ alias_method TEARDOWN_ALIAS, :teardown
25
+ def teardown
26
+ conduct_and_clear_handoffs
27
+ send TEARDOWN_ALIAS
28
+ end
29
+ end
30
+ end
31
+
18
32
  def handoff_assertions
19
33
  @handoff_assertions ||= []
20
34
  end
@@ -27,12 +41,6 @@ module Handoff
27
41
  end
28
42
  end
29
43
 
30
- def self.included(base)
31
- base.class_eval do
32
- add_teardown_method :conduct_and_clear_handoffs
33
- end
34
- end
35
-
36
44
  end
37
45
 
38
46
  class Test::Unit::TestCase
@@ -1,5 +1,6 @@
1
- require 'handoff/argument_normalizer'
2
- require 'handoff/usage_error'
1
+ require File.expand_path(File.dirname(__FILE__) + '/argument_normalizer')
2
+ require File.expand_path(File.dirname(__FILE__) + '/usage_error')
3
+ require File.expand_path(File.dirname(__FILE__) + '/verifying_delegate')
3
4
 
4
5
  module Handoff
5
6
  # This is where the fluent stuff is.
@@ -9,7 +10,7 @@ module Handoff
9
10
  # * +to+,
10
11
  # * +for+, +for_method+ or +for_methods+, and
11
12
  # * (optionally) +with+ or +with_arguments+.
12
- class Assertion
13
+ class Assertion < Struct.new(:test)
13
14
 
14
15
  # :stopdoc:
15
16
 
@@ -17,10 +18,6 @@ module Handoff
17
18
  attr_reader :delegator
18
19
  private :method_map, :delegator
19
20
 
20
- def initialize mock_delegate
21
- @mock_delegate = mock_delegate
22
- end
23
-
24
21
  # :startdoc:
25
22
 
26
23
  # Creates an instance of +class_under_test+ with no arguments and uses it
@@ -64,7 +61,6 @@ module Handoff
64
61
 
65
62
  # Specifies that the assertion should pass no arguments to the delegating method and
66
63
  # require that no arguments are sent to the target method.
67
- # Equivalent to calling +with_arguments+ with no arguments.
68
64
  def with_no_arguments
69
65
  with_arguments
70
66
  end
@@ -73,19 +69,19 @@ module Handoff
73
69
 
74
70
  def conduct
75
71
  validate_sufficiently_specified
76
- @delegator.expects(@delegate_accessor).at_least_once.returns(@mock_delegate)
77
- expected_returns = {}
78
- method_map.each_pair do |delegating_method, target|
79
- expected_returns[delegating_method] = "#{delegating_method.to_s}_return"
80
- expectation = @mock_delegate.expects(target).returns(expected_returns[delegating_method])
81
- expectation.with(*@args) unless @args.nil?
82
- end
83
- method_map.each_pair do |delegating_method, target|
84
- send_args = [delegating_method, @args].flatten
85
- actual = delegator.send(*send_args)
86
- unless actual.equal? expected_returns[delegating_method]
87
- raise "expected #{delegating_method.to_s} to return #{expected_returns[delegating_method]}, but was #{actual}"
72
+ method_map.each do |delegating_method, target_method|
73
+ mock_delegate = VerifyingDelegate.new(target_method, @args||[])
74
+ accessor = @delegate_accessor
75
+ (class << @delegator; self; end).class_eval do
76
+ define_method(accessor) { mock_delegate }
88
77
  end
78
+ send_args = [delegating_method]
79
+ if @args
80
+ send_args << @args
81
+ send_args.flatten!
82
+ end
83
+ actual_return = @delegator.send *send_args
84
+ test.assert_equal mock_delegate.happy_return, actual_return
89
85
  end
90
86
  end
91
87
 
@@ -95,6 +91,7 @@ module Handoff
95
91
  raise UsageError, "Delegate accessor must be specified with 'to'" unless @delegate_accessor
96
92
  raise UsageError, "Delegating methods must be specified with 'for_method' or 'for_methods'" unless @method_map
97
93
  end
94
+
98
95
  # :startdoc:
99
96
  end
100
97
  end
@@ -0,0 +1,21 @@
1
+ module Handoff
2
+ class VerifyingDelegate
3
+ def initialize target_method, expected_args
4
+ @target_method = target_method
5
+ (class << self; self; end).class_eval do
6
+ define_method target_method do |*actual_args|
7
+ raise( ArgumentError, "expected arguments: '#{expected_args}' but got '#{actual_args}'") unless expected_args == actual_args
8
+ happy_return
9
+ end
10
+ end
11
+ end
12
+
13
+ def happy_return
14
+ "return value from #{to_s}"
15
+ end
16
+
17
+ def method_missing method, *args
18
+ raise NoMethodError, "Expected handoff to method `#{@target_method}', but `#{method}' was called"
19
+ end
20
+ end
21
+ end
@@ -19,12 +19,8 @@ class Foo
19
19
  end
20
20
 
21
21
  require 'test/unit'
22
- require 'rubygems'
23
22
 
24
- require 'mocha' # You need to require mocha and stubba in your test.
25
- require 'stubba' # ditto
26
-
27
- require File.dirname(__FILE__) + '/../lib/handoff' # I require it this way because I don't want the installed gem.
23
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/handoff') # I require it this way because I don't want the installed gem.
28
24
  # require 'handoff' # This is how you'd require handoff (or do require_gem w/ a version).
29
25
 
30
26
  class ExampleTest < Test::Unit::TestCase
@@ -1,20 +1,20 @@
1
- require 'test/unit'
2
- require File.dirname(__FILE__) + '/../../lib/handoff/argument_normalizer'
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/handoff/argument_normalizer')
3
3
 
4
4
  module Handoff
5
5
  class ArgumentNormalizerTest < Test::Unit::TestCase
6
6
 
7
- def test_should_return_hash_at_front_of_one_element_array
7
+ test "should return hash at front of one element array" do
8
8
  hash = {}
9
9
  assert_same hash, [hash].extend(ArgumentNormalizer).to_method_map
10
10
  end
11
11
 
12
- def test_should_return_self_referencing_hash_for_array_of_symbols
12
+ test "should return self referencing hash for array of symbols" do
13
13
  args = [:bar, :foo].extend(ArgumentNormalizer)
14
14
  assert_equal({:foo => :foo, :bar => :bar}, args.to_method_map)
15
15
  end
16
16
 
17
- def test_should_return_self_referencing_hash_for_one_element_array_with_symbol
17
+ test "should return self referencing hash for one element array with symbol" do
18
18
  args = [:foo].extend(ArgumentNormalizer)
19
19
  assert_equal({:foo => :foo}, args.to_method_map)
20
20
  end
@@ -1,6 +1,5 @@
1
- require 'test/unit'
2
- require File.dirname(__FILE__) + '/../test_helper'
3
- require File.dirname(__FILE__) + '/../../lib/handoff/assertion'
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/handoff/assertion')
4
3
  require 'rubygems'
5
4
  require 'mocha'
6
5
  require 'stubba'
@@ -13,63 +12,73 @@ module Handoff
13
12
  assert_same assertion, assertion.from_any(mock('class under test', :new => nil))
14
13
  end
15
14
 
16
- test 'should create expectations on mock_delegate and object under test upon conduct' do
17
- cut = Class.new do
18
- extend Forwardable
19
- def_delegator :asdf, :meth
20
- attr_reader :asdf
21
- end
22
- mock_delegate = mock
23
- object_under_test = cut.new
24
- assertion = Assertion.new(mock_delegate).from(object_under_test).to(:asdf).for_method(:meth)
25
- assertion.conduct
26
- assert_equal :asdf, object_under_test.mocha.expectations.first.method_name
27
- assert_equal :meth, mock_delegate.expectations.last.method_name
28
- end
29
-
30
- test 'should create mock_delegate expectation with arguments when supplied' do
15
+ test 'conduct should pass with one Test::Unit assertion if delegator does its job' do
31
16
  delegator = Class.new do
32
- extend Forwardable
33
- def_delegator :delegate, :meth
34
- attr_reader :delegate
17
+ def foo; delegate.foo; end
18
+ def delegate; nil; end
35
19
  end.new
36
- assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
37
- assertion.with('arg1', :arg2, 3)
20
+ assertion = Assertion.new(mock(:assert_equal => nil))
21
+ assertion.from(delegator).to(:delegate).for(:foo)
38
22
  assertion.conduct
39
- assert_true mock_delegate.expectations.first.match?(:meth, 'arg1', :arg2, 3)
40
- assert_false mock_delegate.expectations.first.match?(:meth)
41
- assert_false mock_delegate.expectations.first.match?(:meth, 'arg1')
42
- end
43
-
44
- {
45
- :with => lambda {|assertion| assertion.with},
46
- :with_no_arguments => lambda {|assertion| assertion.with_no_arguments}
47
- }.each_pair do |method, proc|
48
- test "should force no args when #{method} is used to specify none" do
49
- delegator = Class.new do
50
- extend Forwardable
51
- def_delegator :delegate, :meth
52
- attr_reader :delegate
53
- end.new
54
- assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
55
- proc.call(assertion)
56
- assertion.conduct
57
- assert_true mock_delegate.expectations.first.match?(:meth)
58
- assert_false mock_delegate.expectations.first.match?(:meth, 'arg1')
59
- end
60
23
  end
61
24
 
62
- test 'should allow for args or no args if nothing specified' do
63
- delegator = Class.new do
64
- extend Forwardable
65
- def_delegator :delegate, :meth
66
- attr_reader :delegate
67
- end.new
68
- assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
69
- assertion.conduct
70
- assert_true mock_delegate.expectations.first.match?(:meth)
71
- assert_true mock_delegate.expectations.first.match?(:meth, 'arg1')
72
- end
25
+ # test 'should create expectations on mock_delegate and object under test upon conduct' do
26
+ # cut = Class.new do
27
+ # extend Forwardable
28
+ # def_delegator :asdf, :meth
29
+ # attr_reader :asdf
30
+ # end
31
+ # mock_delegate = mock
32
+ # object_under_test = cut.new
33
+ # assertion = Assertion.new(mock_delegate).from(object_under_test).to(:asdf).for_method(:meth)
34
+ # assertion.conduct
35
+ # assert_equal :asdf, object_under_test.mocha.expectations.first.method_name
36
+ # assert_equal :meth, mock_delegate.expectations.last.method_name
37
+ # end
38
+ #
39
+ # test 'should create mock_delegate expectation with arguments when supplied' do
40
+ # delegator = Class.new do
41
+ # extend Forwardable
42
+ # def_delegator :delegate, :meth
43
+ # attr_reader :delegate
44
+ # end.new
45
+ # assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
46
+ # assertion.with('arg1', :arg2, 3)
47
+ # assertion.conduct
48
+ # assert_true mock_delegate.expectations.first.match?(:meth, 'arg1', :arg2, 3)
49
+ # assert_false mock_delegate.expectations.first.match?(:meth)
50
+ # assert_false mock_delegate.expectations.first.match?(:meth, 'arg1')
51
+ # end
52
+ #
53
+ # {
54
+ # :with => lambda {|assertion| assertion.with},
55
+ # :with_no_arguments => lambda {|assertion| assertion.with_no_arguments}
56
+ # }.each_pair do |method, proc|
57
+ # test "should force no args when #{method} is used to specify none" do
58
+ # delegator = Class.new do
59
+ # extend Forwardable
60
+ # def_delegator :delegate, :meth
61
+ # attr_reader :delegate
62
+ # end.new
63
+ # assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
64
+ # proc.call(assertion)
65
+ # assertion.conduct
66
+ # assert_true mock_delegate.expectations.first.match?(:meth)
67
+ # assert_false mock_delegate.expectations.first.match?(:meth, 'arg1')
68
+ # end
69
+ # end
70
+ #
71
+ # test 'should allow for args or no args if nothing specified' do
72
+ # delegator = Class.new do
73
+ # extend Forwardable
74
+ # def_delegator :delegate, :meth
75
+ # attr_reader :delegate
76
+ # end.new
77
+ # assertion = Assertion.new(mock_delegate = mock).from(delegator).to(:delegate).for(:meth)
78
+ # assertion.conduct
79
+ # assert_true mock_delegate.expectations.first.match?(:meth)
80
+ # assert_true mock_delegate.expectations.first.match?(:meth, 'arg1')
81
+ # end
73
82
 
74
83
  test 'validates presence of delegator, delegate accessor, and delegating methods' do
75
84
  assertion = Assertion.new(mock).from(nil).to(:asdf).for_method(:meth)
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/handoff/verifying_delegate')
3
+
4
+ module Handoff
5
+ class VerifyingDelegateTest < Test::Unit::TestCase
6
+ test "happy_return value" do
7
+ d = VerifyingDelegate.new(:foo, [])
8
+ assert_equal "return value from #{d.to_s}", d.happy_return
9
+ end
10
+
11
+ test 'responds to target method with happy_return value' do
12
+ d = VerifyingDelegate.new(:foo, [])
13
+ assert_equal d.happy_return, d.foo
14
+ end
15
+
16
+ test 'happy if args match' do
17
+ d = VerifyingDelegate.new(:foo, [1])
18
+ assert_equal d.happy_return, d.foo(1)
19
+ end
20
+
21
+ test 'raises if args dont match' do
22
+ d = VerifyingDelegate.new(:foo, [1])
23
+ assert_raises(ArgumentError) { d.foo }
24
+ end
25
+
26
+ test 'raises NoMethodError with helpful message if wrong method is invoked' do
27
+ d = VerifyingDelegate.new(:foo, [])
28
+ begin
29
+ d.foob
30
+ fail
31
+ rescue NoMethodError => e
32
+ assert_equal "Expected handoff to method `foo', but `foob' was called", e.message
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,26 +1,9 @@
1
- require File.dirname(__FILE__) + '/test_helper'
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
  require 'rubygems'
3
3
  require 'mocha'
4
- require 'stubba'
5
- require File.dirname(__FILE__) + '/../lib/handoff'
4
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/handoff')
6
5
 
7
6
  class HandoffTest < Test::Unit::TestCase
8
- test 'should create a mock named "handoff delegate" and hand it to a new Assertion' do
9
- given_name = nil
10
- def self.mock name
11
- assert_equal 'handoff delegate', name
12
- :mock_return
13
- end
14
- Assertion.expects(:new).with(:mock_return).returns(:new_assertion)
15
- assert_equal :new_assertion, assert_handoff
16
- assert_equal :new_assertion, handoff_assertions.delete(:new_assertion)
17
- assert_true handoff_assertions.empty?
18
- end
19
-
20
- test 'should add a teardown method for conducting handoff assertions' do
21
- assert_true self.class.teardown_methods.include?(:conduct_and_clear_handoffs)
22
- end
23
-
24
7
  test 'should conduct each assertion in conduct_and_clear_handoffs' do
25
8
  handoff_assertions << assertion1 = mock(:conduct => nil)
26
9
  handoff_assertions << assertion2 = mock(:conduct => nil)
@@ -29,4 +12,27 @@ class HandoffTest < Test::Unit::TestCase
29
12
  assertion1.verify
30
13
  assertion2.verify
31
14
  end
15
+
16
+ def blank_test_case
17
+ Class.new(Test::Unit::TestCase) do
18
+ define_method(:initialize) { super(:test_foo) }
19
+ define_method(:test_foo) {}
20
+ end
21
+ end
22
+
23
+ test 'first call to assert_handoff in a test aliases and defines new teardown' do
24
+ test = blank_test_case.new
25
+ assert_equal [], test.singleton_methods
26
+ test.assert_handoff
27
+ assert_equal %w(teardown teardown_before_handoff_rewrite ), test.singleton_methods.sort
28
+ end
29
+
30
+ test 'handoff-defined teardown does conduct_and_clear_handoffs then calls original teardown' do
31
+ test = blank_test_case.new
32
+ test.assert_handoff
33
+ test.expects(:conduct_and_clear_handoffs)
34
+ test.expects(:teardown_before_handoff_rewrite)
35
+ test.teardown
36
+ end
37
+
32
38
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/test_helper'
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
 
3
3
  class TestHelperTest < Test::Unit::TestCase
4
4
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: handoff
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-02-17 00:00:00 -05:00
6
+ version: 0.2.0
7
+ date: 2007-05-18 00:00:00 -07:00
8
8
  summary: Handoff is a fluent interface for making test assertions about delegation.
9
9
  require_paths:
10
10
  - lib
@@ -12,7 +12,7 @@ email: ""
12
12
  homepage: http://handoff.rubyforge.org/
13
13
  rubyforge_project:
14
14
  description:
15
- autorequire: hand_off
15
+ autorequire: handoff
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
@@ -34,6 +34,7 @@ files:
34
34
  - lib/handoff/argument_normalizer.rb
35
35
  - lib/handoff/assertion.rb
36
36
  - lib/handoff/usage_error.rb
37
+ - lib/handoff/verifying_delegate.rb
37
38
  - README
38
39
  test_files:
39
40
  - test/example_test.rb
@@ -41,6 +42,7 @@ test_files:
41
42
  - test/test_helper_test.rb
42
43
  - test/handoff/argument_normalizer_test.rb
43
44
  - test/handoff/assertion_test.rb
45
+ - test/handoff/verifying_delegate_test.rb
44
46
  rdoc_options: []
45
47
 
46
48
  extra_rdoc_files:
@@ -51,13 +53,5 @@ extensions: []
51
53
 
52
54
  requirements: []
53
55
 
54
- dependencies:
55
- - !ruby/object:Gem::Dependency
56
- name: mocha
57
- version_requirement:
58
- version_requirements: !ruby/object:Gem::Version::Requirement
59
- requirements:
60
- - - ">"
61
- - !ruby/object:Gem::Version
62
- version: 0.0.0
63
- version:
56
+ dependencies: []
57
+