handoff 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007 John D. Hume
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README CHANGED
@@ -9,5 +9,5 @@ As of 0.2.0, Handoff no longer depends on Mocha and Stubba.
9
9
 
10
10
  Here's example_test.rb to give you an idea of what you can do:
11
11
 
12
- :include: test/example_test.rb
12
+ :include: examples/example_test.rb
13
13
 
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test/test_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/handoff')
3
+ require 'forwardable'
4
+
5
+ class BadDelegator
6
+ extend Forwardable
7
+ def_delegators :a, :foo, :bar
8
+ def_delegators :b, :foo, :bar
9
+ def a; Struct.new(:foo, :bar).new; end
10
+ def b; Struct.new(:foo, :bar).new; end
11
+ end
12
+
13
+ class BadHandoffsTest < Test::Unit::TestCase
14
+
15
+ def test_with_multiple_redefined_handoffs
16
+ bad = BadDelegator.new
17
+ assert_handoff.from(bad).to(:a).for(:foo, :bar)
18
+ end
19
+
20
+ def test_with_multiple_unimplemented_handoffs
21
+ assert_handoff.from(BadDelegator.new).to(:a).for(:baz, :bat)
22
+ end
23
+
24
+ end
File without changes
@@ -9,11 +9,9 @@ module Handoff
9
9
 
10
10
  TEARDOWN_ALIAS = :teardown_before_handoff_rewrite
11
11
 
12
- # Creates an Assertion, handing a it a mock named 'handoff delegate' on which
13
- # expectations will be set.
14
12
  def assert_handoff
15
13
  ensure_handoff_teardown_defined
16
- a = Handoff::Assertion.new(self)
14
+ a = Handoff::Assertion.new(self, caller)
17
15
  handoff_assertions << a
18
16
  a
19
17
  end
@@ -44,5 +42,5 @@ module Handoff
44
42
  end
45
43
 
46
44
  class Test::Unit::TestCase
47
- include Handoff unless ancestors.include?(Handoff)
45
+ include Handoff
48
46
  end
@@ -1,15 +1,15 @@
1
1
  module Handoff
2
2
  # Handoff internal.
3
3
  module ArgumentNormalizer
4
-
5
- def to_method_map
6
- return first if size == 1 && first.respond_to?(:each_pair)
7
- to_self_referencing_hash
4
+ module_function
5
+ def to_method_map args
6
+ return args.first if args.size == 1 && args.first.respond_to?(:each_pair)
7
+ to_self_referencing_hash args
8
8
  end
9
9
 
10
- def to_self_referencing_hash
10
+ def to_self_referencing_hash args
11
11
  hash = Hash.new
12
- each {|method_symbol| hash[method_symbol] = method_symbol}
12
+ args.each {|method_symbol| hash[method_symbol] = method_symbol}
13
13
  hash
14
14
  end
15
15
 
@@ -10,13 +10,11 @@ module Handoff
10
10
  # * +to+,
11
11
  # * +for+, +for_method+ or +for_methods+, and
12
12
  # * (optionally) +with+ or +with_arguments+.
13
- class Assertion < Struct.new(:test)
13
+ class Assertion < Struct.new(:test, :backtrace)
14
14
 
15
15
  # :stopdoc:
16
-
17
16
  attr_reader :method_map
18
17
  attr_reader :delegator
19
- private :method_map, :delegator
20
18
 
21
19
  # :startdoc:
22
20
 
@@ -48,7 +46,7 @@ module Handoff
48
46
  # +args+:: symbols representing the delegating methods if they are not renamed, or
49
47
  # a Hash mapping methods in the delegating class to methods in the delegate.
50
48
  def for_methods(*args)
51
- @method_map = args.extend(ArgumentNormalizer).to_method_map
49
+ @method_map = ArgumentNormalizer.to_method_map(args)
52
50
  self
53
51
  end
54
52
  alias for_method for_methods
@@ -56,6 +54,7 @@ module Handoff
56
54
 
57
55
  def with_arguments *args
58
56
  @args = args
57
+ self
59
58
  end
60
59
  alias with with_arguments
61
60
 
@@ -70,18 +69,23 @@ module Handoff
70
69
  def conduct
71
70
  validate_sufficiently_specified
72
71
  method_map.each do |delegating_method, target_method|
73
- mock_delegate = VerifyingDelegate.new(target_method, @args||[])
72
+ verifying_delegate = VerifyingDelegate.new(target_method, @args||[])
74
73
  accessor = @delegate_accessor
75
74
  (class << @delegator; self; end).class_eval do
76
- define_method(accessor) { mock_delegate }
75
+ define_method(accessor) { verifying_delegate }
77
76
  end
78
77
  send_args = [delegating_method]
79
- if @args
80
- send_args << @args
81
- send_args.flatten!
82
- end
78
+ send_args.concat @args if @args
83
79
  actual_return = @delegator.send *send_args
84
- test.assert_equal mock_delegate.happy_return, actual_return
80
+ test.instance_eval {add_assertion}
81
+ expected_return = verifying_delegate.happy_return
82
+ if expected_return != actual_return
83
+ backtrace = self.backtrace
84
+ delegate_accessor = @delegate_accessor
85
+ test.instance_eval do
86
+ add_failure "`#{delegating_method}' didn't delegate to `#{delegate_accessor}.#{target_method}'", backtrace
87
+ end
88
+ end
85
89
  end
86
90
  end
87
91
 
@@ -4,14 +4,15 @@ module Handoff
4
4
  @target_method = target_method
5
5
  (class << self; self; end).class_eval do
6
6
  define_method target_method do |*actual_args|
7
+ raise 'called twice' if @returned
7
8
  raise( ArgumentError, "expected arguments: '#{expected_args}' but got '#{actual_args}'") unless expected_args == actual_args
8
- happy_return
9
+ @returned = true and happy_return
9
10
  end
10
11
  end
11
12
  end
12
13
 
13
14
  def happy_return
14
- "return value from #{to_s}"
15
+ "handoff return value from #{to_s}"
15
16
  end
16
17
 
17
18
  def method_missing method, *args
@@ -3,21 +3,19 @@ require File.expand_path(File.dirname(__FILE__) + '/../../lib/handoff/argument_n
3
3
 
4
4
  module Handoff
5
5
  class ArgumentNormalizerTest < Test::Unit::TestCase
6
-
6
+
7
7
  test "should return hash at front of one element array" do
8
8
  hash = {}
9
- assert_same hash, [hash].extend(ArgumentNormalizer).to_method_map
9
+ assert_same hash, ArgumentNormalizer.to_method_map([hash])
10
10
  end
11
11
 
12
12
  test "should return self referencing hash for array of symbols" do
13
- args = [:bar, :foo].extend(ArgumentNormalizer)
14
- assert_equal({:foo => :foo, :bar => :bar}, args.to_method_map)
13
+ assert_equal({:foo => :foo, :bar => :bar}, ArgumentNormalizer.to_method_map([:bar, :foo]))
15
14
  end
16
15
 
17
16
  test "should return self referencing hash for one element array with symbol" do
18
- args = [:foo].extend(ArgumentNormalizer)
19
- assert_equal({:foo => :foo}, args.to_method_map)
17
+ assert_equal({:foo => :foo}, ArgumentNormalizer.to_method_map([:foo]))
20
18
  end
21
-
19
+
22
20
  end
23
21
  end
@@ -9,84 +9,63 @@ module Handoff
9
9
 
10
10
  test 'should construct instance to test and return self when from_any is called' do
11
11
  assertion = Assertion.new(nil)
12
- assert_same assertion, assertion.from_any(mock('class under test', :new => nil))
12
+ assert_same assertion, assertion.from_any(mock('class under test', :new => :created_object))
13
13
  end
14
14
 
15
- test 'conduct should pass with one Test::Unit assertion if delegator does its job' do
16
- delegator = Class.new do
17
- def foo; delegate.foo; end
18
- def delegate; nil; end
19
- end.new
20
- assertion = Assertion.new(mock(:assert_equal => nil))
21
- assertion.from(delegator).to(:delegate).for(:foo)
15
+ test 'conduct adds failure for bad return value' do
16
+ test_case = mock
17
+ delegator = mock
18
+ verifying_delegate = mock
19
+
20
+ assertion = Assertion.new(test_case, :backtrace).from(delegator).to(:delegate).for(:method)
21
+
22
+ VerifyingDelegate.expects(:new).returns(verifying_delegate)
23
+ delegator.expects(:method).returns("something other than the verifying delegate's happy_return")
24
+ verifying_delegate.expects(:happy_return).returns(:the_expected_return_value)
25
+ test_case.expects(:add_assertion)
26
+ test_case.expects(:add_failure).with("`method' didn't delegate to `delegate.method'", :backtrace)
27
+
22
28
  assertion.conduct
23
29
  end
24
30
 
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
31
+ test 'for each method, conduct attaches verifying delegate to delegator and invokes method' do
32
+ test_case = mock
33
+ delegator = mock
34
+ verifying_delegate1 = mock
35
+ verifying_delegate2 = mock
36
+ method_map = mock
37
+
38
+ assertion = Assertion.new(test_case).from(delegator).to(:delegate).for(:method1 => :target_method1, :method2 => :target_method2).with('the args')
39
+ VerifyingDelegate.expects(:new).with(:target_method1, ['the args']).returns(verifying_delegate1)
40
+ delegator.expects(:method1).with('the args').returns(:return_value1)
41
+ verifying_delegate1.expects(:happy_return).returns(:return_value1)
42
+ test_case.expects(:add_assertion)
43
+ VerifyingDelegate.expects(:new).with(:target_method2, ['the args']).returns(verifying_delegate2)
44
+ delegator.expects(:method2).with('the args').returns(:return_value2)
45
+ verifying_delegate2.expects(:happy_return).returns(:return_value2)
46
+ test_case.expects(:add_assertion)
47
+
48
+ assertion.conduct
49
+ end
82
50
 
83
- test 'validates presence of delegator, delegate accessor, and delegating methods' do
84
- assertion = Assertion.new(mock).from(nil).to(:asdf).for_method(:meth)
85
- assert_raises(UsageError) { assertion.conduct }
51
+ test 'converts method list or hash into method map with ArgumentNormalizer' do
52
+ ArgumentNormalizer.expects(:to_method_map).with([:args]).returns(:the_method_map)
86
53
 
87
- assertion = Assertion.new(mock).from("whatever").to(nil).for_method(:meth)
54
+ assertion = Assertion.new(mock).for_methods(:args)
55
+ assert_equal :the_method_map, assertion.method_map
56
+ end
57
+
58
+ test 'validates presence of delegator' do
59
+ assertion = Assertion.new(mock).to(:asdf).for_method(:meth)
88
60
  assert_raises(UsageError) { assertion.conduct }
89
-
61
+ end
62
+
63
+ test 'validates presence of delegate accessor' do
64
+ assertion = Assertion.new(mock).from("whatever").for_method(:meth)
65
+ assert_raises(UsageError) { assertion.conduct }
66
+ end
67
+
68
+ test 'validates presence of delegating methods' do
90
69
  assertion = Assertion.new(mock).from("whatever").to(:asdf)
91
70
  assert_raises(UsageError) { assertion.conduct }
92
71
  end
@@ -5,7 +5,7 @@ module Handoff
5
5
  class VerifyingDelegateTest < Test::Unit::TestCase
6
6
  test "happy_return value" do
7
7
  d = VerifyingDelegate.new(:foo, [])
8
- assert_equal "return value from #{d.to_s}", d.happy_return
8
+ assert_equal "handoff return value from #{d.to_s}", d.happy_return
9
9
  end
10
10
 
11
11
  test 'responds to target method with happy_return value' do
@@ -23,6 +23,12 @@ module Handoff
23
23
  assert_raises(ArgumentError) { d.foo }
24
24
  end
25
25
 
26
+ test 'raises if target invoked twice' do
27
+ d = VerifyingDelegate.new(:foo, [])
28
+ d.foo
29
+ assert_raises(RuntimeError) { d.foo }
30
+ end
31
+
26
32
  test 'raises NoMethodError with helpful message if wrong method is invoked' do
27
33
  d = VerifyingDelegate.new(:foo, [])
28
34
  begin
@@ -4,13 +4,11 @@ require 'mocha'
4
4
  require File.expand_path(File.dirname(__FILE__) + '/../lib/handoff')
5
5
 
6
6
  class HandoffTest < Test::Unit::TestCase
7
- test 'should conduct each assertion in conduct_and_clear_handoffs' do
7
+ test 'conducts each assertion in conduct_and_clear_handoffs' do
8
8
  handoff_assertions << assertion1 = mock(:conduct => nil)
9
9
  handoff_assertions << assertion2 = mock(:conduct => nil)
10
10
  conduct_and_clear_handoffs
11
11
  assert_true handoff_assertions.empty?
12
- assertion1.verify
13
- assertion2.verify
14
12
  end
15
13
 
16
14
  def blank_test_case
@@ -7,4 +7,8 @@ class TestHelperTest < Test::Unit::TestCase
7
7
  assert_raises(Test::Unit::AssertionFailedError) { assert_true 'foo' }
8
8
  end
9
9
 
10
+ test "assert_false fails on nil" do
11
+ assert_raises(Test::Unit::AssertionFailedError) { assert_false nil }
12
+ end
13
+
10
14
  end
metadata CHANGED
@@ -3,9 +3,9 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: handoff
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.0
7
- date: 2007-05-18 00:00:00 -07:00
8
- summary: Handoff is a fluent interface for making test assertions about delegation.
6
+ version: 1.0.0
7
+ date: 2007-10-26 00:00:00 -04:00
8
+ summary: Handoff is a fluent interface for making Test::Unit assertions about delegation.
9
9
  require_paths:
10
10
  - lib
11
11
  email: ""
@@ -35,9 +35,11 @@ files:
35
35
  - lib/handoff/assertion.rb
36
36
  - lib/handoff/usage_error.rb
37
37
  - lib/handoff/verifying_delegate.rb
38
+ - examples/bad_handoffs_test.rb
39
+ - examples/example_test.rb
38
40
  - README
41
+ - LICENSE
39
42
  test_files:
40
- - test/example_test.rb
41
43
  - test/handoff_test.rb
42
44
  - test/test_helper_test.rb
43
45
  - test/handoff/argument_normalizer_test.rb
@@ -47,6 +49,7 @@ rdoc_options: []
47
49
 
48
50
  extra_rdoc_files:
49
51
  - README
52
+ - LICENSE
50
53
  executables: []
51
54
 
52
55
  extensions: []