jferris-rr 0.7.1.0.1239654108
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/CHANGES +196 -0
- data/README.rdoc +329 -0
- data/Rakefile +77 -0
- data/lib/rr.rb +84 -0
- data/lib/rr/adapters/rr_methods.rb +122 -0
- data/lib/rr/adapters/rspec.rb +58 -0
- data/lib/rr/adapters/test_unit.rb +29 -0
- data/lib/rr/double.rb +212 -0
- data/lib/rr/double_definitions/child_double_definition_creator.rb +27 -0
- data/lib/rr/double_definitions/double_definition.rb +346 -0
- data/lib/rr/double_definitions/double_definition_creator.rb +167 -0
- data/lib/rr/double_definitions/double_definition_creator_proxy.rb +37 -0
- data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
- data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
- data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
- data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +46 -0
- data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
- data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
- data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
- data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
- data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
- data/lib/rr/double_injection.rb +143 -0
- data/lib/rr/double_matches.rb +51 -0
- data/lib/rr/errors/argument_equality_error.rb +6 -0
- data/lib/rr/errors/double_definition_error.rb +6 -0
- data/lib/rr/errors/double_not_found_error.rb +6 -0
- data/lib/rr/errors/double_order_error.rb +6 -0
- data/lib/rr/errors/rr_error.rb +20 -0
- data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
- data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
- data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
- data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
- data/lib/rr/errors/times_called_error.rb +6 -0
- data/lib/rr/expectations/any_argument_expectation.rb +21 -0
- data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
- data/lib/rr/expectations/times_called_expectation.rb +57 -0
- data/lib/rr/hash_with_object_id_key.rb +41 -0
- data/lib/rr/recorded_calls.rb +103 -0
- data/lib/rr/space.rb +123 -0
- data/lib/rr/spy_verification.rb +48 -0
- data/lib/rr/spy_verification_proxy.rb +18 -0
- data/lib/rr/times_called_matchers/any_times_matcher.rb +18 -0
- data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
- data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
- data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
- data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
- data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
- data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
- data/lib/rr/times_called_matchers/terminal.rb +20 -0
- data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
- data/lib/rr/wildcard_matchers/anything.rb +18 -0
- data/lib/rr/wildcard_matchers/boolean.rb +23 -0
- data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
- data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
- data/lib/rr/wildcard_matchers/is_a.rb +25 -0
- data/lib/rr/wildcard_matchers/numeric.rb +13 -0
- data/lib/rr/wildcard_matchers/range.rb +7 -0
- data/lib/rr/wildcard_matchers/regexp.rb +7 -0
- data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
- data/spec/core_spec_suite.rb +19 -0
- data/spec/environment_fixture_setup.rb +6 -0
- data/spec/high_level_spec.rb +368 -0
- data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
- data/spec/rr/adapters/rr_methods_creator_spec.rb +149 -0
- data/spec/rr/adapters/rr_methods_space_spec.rb +115 -0
- data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
- data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +17 -0
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
- data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +155 -0
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +502 -0
- data/spec/rr/double_definitions/double_definition_spec.rb +1159 -0
- data/spec/rr/double_injection/double_injection_bind_spec.rb +111 -0
- data/spec/rr/double_injection/double_injection_dispatching_spec.rb +244 -0
- data/spec/rr/double_injection/double_injection_has_original_method_spec.rb +55 -0
- data/spec/rr/double_injection/double_injection_reset_spec.rb +90 -0
- data/spec/rr/double_injection/double_injection_spec.rb +77 -0
- data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
- data/spec/rr/double_spec.rb +352 -0
- data/spec/rr/errors/rr_error_spec.rb +67 -0
- data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
- data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
- data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
- data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
- data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
- data/spec/rr/expectations/hash_including_spec.rb +17 -0
- data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
- data/spec/rr/expectations/satisfy_spec.rb +14 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +46 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +69 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +23 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +104 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +81 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +83 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +38 -0
- data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
- data/spec/rr/rspec/rspec_adapter_spec.rb +66 -0
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +31 -0
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
- data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
- data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
- data/spec/rr/space/space_spec.rb +542 -0
- data/spec/rr/test_unit/test_helper.rb +7 -0
- data/spec/rr/test_unit/test_unit_backtrace_test.rb +35 -0
- data/spec/rr/test_unit/test_unit_integration_test.rb +57 -0
- data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
- data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
- data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
- data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
- data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
- data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
- data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
- data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
- data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
- data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
- data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
- data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
- data/spec/rr_spec.rb +28 -0
- data/spec/rspec_spec_suite.rb +16 -0
- data/spec/spec_helper.rb +107 -0
- data/spec/spec_suite.rb +27 -0
- data/spec/spy_verification_spec.rb +129 -0
- data/spec/test_unit_spec_suite.rb +21 -0
- metadata +187 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require "rake"
|
|
2
|
+
require 'rake/gempackagetask'
|
|
3
|
+
require 'rake/contrib/rubyforgepublisher'
|
|
4
|
+
require 'rake/clean'
|
|
5
|
+
require 'rake/testtask'
|
|
6
|
+
require 'rake/rdoctask'
|
|
7
|
+
|
|
8
|
+
desc "Runs the Rspec suite"
|
|
9
|
+
task(:default) do
|
|
10
|
+
run_suite
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "Runs the Rspec suite"
|
|
14
|
+
task(:spec) do
|
|
15
|
+
run_suite
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "Copies the trunk to a tag with the name of the current release"
|
|
19
|
+
task(:tag_release) do
|
|
20
|
+
tag_release
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def run_suite
|
|
24
|
+
dir = File.dirname(__FILE__)
|
|
25
|
+
system("ruby #{dir}/spec/spec_suite.rb") || raise("Spec Suite failed")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
PKG_NAME = "rr"
|
|
29
|
+
PKG_VERSION = "0.7.1"
|
|
30
|
+
PKG_FILES = FileList[
|
|
31
|
+
'[A-Z]*',
|
|
32
|
+
'*.rb',
|
|
33
|
+
'lib/**/*.rb',
|
|
34
|
+
'spec/**/*.rb'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
spec = Gem::Specification.new do |s|
|
|
38
|
+
s.name = PKG_NAME
|
|
39
|
+
s.version = "#{PKG_VERSION}.0.#{Time.now.to_i}"
|
|
40
|
+
s.summary = "RR (Double Ruby) is a double framework that features a rich " <<
|
|
41
|
+
"selection of double techniques and a terse syntax. " <<
|
|
42
|
+
"http://xunitpatterns.com/Test%20Double.html"
|
|
43
|
+
s.test_files = "spec/spec_suite.rb"
|
|
44
|
+
s.description = s.summary
|
|
45
|
+
|
|
46
|
+
s.files = PKG_FILES.to_a
|
|
47
|
+
s.require_path = 'lib'
|
|
48
|
+
|
|
49
|
+
s.has_rdoc = true
|
|
50
|
+
s.extra_rdoc_files = [ "README.rdoc", "CHANGES" ]
|
|
51
|
+
s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
|
|
52
|
+
|
|
53
|
+
s.test_files = Dir.glob('spec/*_spec.rb')
|
|
54
|
+
s.require_path = 'lib'
|
|
55
|
+
s.author = "Brian Takita"
|
|
56
|
+
s.email = "brian@pivotallabs.com"
|
|
57
|
+
s.homepage = "http://pivotallabs.com"
|
|
58
|
+
s.rubyforge_project = "pivotalrb"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
desc "Generate a gemspec file"
|
|
62
|
+
task :gemspec do
|
|
63
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
|
64
|
+
f.write spec.to_yaml
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
|
69
|
+
pkg.need_zip = true
|
|
70
|
+
pkg.need_tar = true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def tag_release
|
|
74
|
+
dashed_version = PKG_VERSION.gsub('.', '-')
|
|
75
|
+
svn_user = "#{ENV["SVN_USER"]}@" || ""
|
|
76
|
+
`svn cp svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/rr/trunk svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/rr/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
|
|
77
|
+
end
|
data/lib/rr.rb
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
|
|
4
|
+
require "#{dir}/rr/errors/rr_error"
|
|
5
|
+
require "#{dir}/rr/errors/subject_does_not_implement_method_error"
|
|
6
|
+
require "#{dir}/rr/errors/subject_has_different_arity_error"
|
|
7
|
+
require "#{dir}/rr/errors/double_definition_error"
|
|
8
|
+
require "#{dir}/rr/errors/double_not_found_error"
|
|
9
|
+
require "#{dir}/rr/errors/double_order_error"
|
|
10
|
+
require "#{dir}/rr/errors/argument_equality_error"
|
|
11
|
+
require "#{dir}/rr/errors/times_called_error"
|
|
12
|
+
require "#{dir}/rr/errors/spy_verification_errors/spy_verification_error"
|
|
13
|
+
require "#{dir}/rr/errors/spy_verification_errors/double_injection_not_found_error"
|
|
14
|
+
require "#{dir}/rr/errors/spy_verification_errors/invocation_count_error"
|
|
15
|
+
|
|
16
|
+
require "#{dir}/rr/space"
|
|
17
|
+
require "#{dir}/rr/double_injection"
|
|
18
|
+
require "#{dir}/rr/hash_with_object_id_key"
|
|
19
|
+
require "#{dir}/rr/recorded_calls"
|
|
20
|
+
|
|
21
|
+
require "#{dir}/rr/double_definitions/double_definition_creator_proxy"
|
|
22
|
+
require "#{dir}/rr/double_definitions/double_definition_creator"
|
|
23
|
+
require "#{dir}/rr/double_definitions/child_double_definition_creator"
|
|
24
|
+
require "#{dir}/rr/adapters/rr_methods"
|
|
25
|
+
|
|
26
|
+
require "#{dir}/rr/double"
|
|
27
|
+
require "#{dir}/rr/double_definitions/double_definition"
|
|
28
|
+
require "#{dir}/rr/double_definitions/strategies/strategy"
|
|
29
|
+
require "#{dir}/rr/double_definitions/strategies/verification/verification_strategy"
|
|
30
|
+
require "#{dir}/rr/double_definitions/strategies/verification/mock"
|
|
31
|
+
require "#{dir}/rr/double_definitions/strategies/verification/stub"
|
|
32
|
+
require "#{dir}/rr/double_definitions/strategies/verification/dont_allow"
|
|
33
|
+
require "#{dir}/rr/double_definitions/strategies/implementation/implementation_strategy"
|
|
34
|
+
require "#{dir}/rr/double_definitions/strategies/implementation/reimplementation"
|
|
35
|
+
require "#{dir}/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation"
|
|
36
|
+
require "#{dir}/rr/double_definitions/strategies/implementation/proxy"
|
|
37
|
+
require "#{dir}/rr/double_definitions/strategies/scope/scope_strategy"
|
|
38
|
+
require "#{dir}/rr/double_definitions/strategies/scope/instance"
|
|
39
|
+
require "#{dir}/rr/double_definitions/strategies/scope/instance_of_class"
|
|
40
|
+
require "#{dir}/rr/double_matches"
|
|
41
|
+
|
|
42
|
+
require "#{dir}/rr/expectations/argument_equality_expectation"
|
|
43
|
+
require "#{dir}/rr/expectations/any_argument_expectation"
|
|
44
|
+
require "#{dir}/rr/expectations/times_called_expectation"
|
|
45
|
+
|
|
46
|
+
require "#{dir}/rr/wildcard_matchers/anything"
|
|
47
|
+
require "#{dir}/rr/wildcard_matchers/is_a"
|
|
48
|
+
require "#{dir}/rr/wildcard_matchers/numeric"
|
|
49
|
+
require "#{dir}/rr/wildcard_matchers/boolean"
|
|
50
|
+
require "#{dir}/rr/wildcard_matchers/duck_type"
|
|
51
|
+
require "#{dir}/rr/wildcard_matchers/regexp"
|
|
52
|
+
require "#{dir}/rr/wildcard_matchers/range"
|
|
53
|
+
require "#{dir}/rr/wildcard_matchers/satisfy"
|
|
54
|
+
require "#{dir}/rr/wildcard_matchers/hash_including"
|
|
55
|
+
|
|
56
|
+
require "#{dir}/rr/times_called_matchers/terminal"
|
|
57
|
+
require "#{dir}/rr/times_called_matchers/non_terminal"
|
|
58
|
+
require "#{dir}/rr/times_called_matchers/times_called_matcher"
|
|
59
|
+
require "#{dir}/rr/times_called_matchers/any_times_matcher"
|
|
60
|
+
require "#{dir}/rr/times_called_matchers/integer_matcher"
|
|
61
|
+
require "#{dir}/rr/times_called_matchers/range_matcher"
|
|
62
|
+
require "#{dir}/rr/times_called_matchers/proc_matcher"
|
|
63
|
+
require "#{dir}/rr/times_called_matchers/at_least_matcher"
|
|
64
|
+
require "#{dir}/rr/times_called_matchers/at_most_matcher"
|
|
65
|
+
|
|
66
|
+
require "#{dir}/rr/spy_verification_proxy"
|
|
67
|
+
require "#{dir}/rr/spy_verification"
|
|
68
|
+
|
|
69
|
+
require "#{dir}/rr/adapters/rspec"
|
|
70
|
+
require "#{dir}/rr/adapters/test_unit"
|
|
71
|
+
|
|
72
|
+
module RR
|
|
73
|
+
class << self
|
|
74
|
+
include Adapters::RRMethods
|
|
75
|
+
(RR::Space.instance_methods - Object.instance_methods).each do |method_name|
|
|
76
|
+
returns_method = <<-METHOD
|
|
77
|
+
def #{method_name}(*args, &block)
|
|
78
|
+
RR::Space.instance.__send__(:#{method_name}, *args, &block)
|
|
79
|
+
end
|
|
80
|
+
METHOD
|
|
81
|
+
class_eval(returns_method, __FILE__, __LINE__ - 4)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module RR
|
|
2
|
+
module Adapters
|
|
3
|
+
module RRMethods
|
|
4
|
+
class << self
|
|
5
|
+
def register_strategy_class(strategy_class, method_name)
|
|
6
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
|
7
|
+
def #{method_name}(subject=DoubleDefinitions::DoubleDefinitionCreator::NO_SUBJECT, method_name=nil, &definition_eval_block)
|
|
8
|
+
creator = DoubleDefinitions::DoubleDefinitionCreator.new
|
|
9
|
+
creator.#{method_name}(subject, method_name, &definition_eval_block)
|
|
10
|
+
end
|
|
11
|
+
CLASS
|
|
12
|
+
|
|
13
|
+
class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
|
|
14
|
+
def #{method_name}!(method_name=nil, &definition_eval_block)
|
|
15
|
+
creator = DoubleDefinitions::DoubleDefinitionCreator.new
|
|
16
|
+
creator.#{method_name}!(method_name, &definition_eval_block)
|
|
17
|
+
end
|
|
18
|
+
CLASS
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Verifies all the DoubleInjection objects have met their
|
|
23
|
+
# TimesCalledExpectations.
|
|
24
|
+
def verify
|
|
25
|
+
RR::Space.instance.verify_doubles
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Resets the registered Doubles and ordered Doubles
|
|
29
|
+
def reset
|
|
30
|
+
RR::Space.instance.reset
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns a AnyTimesMatcher. This is meant to be passed in as an argument
|
|
34
|
+
# to Double#times.
|
|
35
|
+
#
|
|
36
|
+
# mock(object).method_name(anything).times(any_times) {return_value}
|
|
37
|
+
def any_times
|
|
38
|
+
TimesCalledMatchers::AnyTimesMatcher.new
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Sets up an Anything wildcard ArgumentEqualityExpectation
|
|
42
|
+
# that succeeds when passed any argument.
|
|
43
|
+
# mock(object).method_name(anything) {return_value}
|
|
44
|
+
# object.method_name("an arbitrary value") # passes
|
|
45
|
+
def anything
|
|
46
|
+
RR::WildcardMatchers::Anything.new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Sets up an IsA wildcard ArgumentEqualityExpectation
|
|
50
|
+
# that succeeds when passed an argument of a certain type.
|
|
51
|
+
# mock(object).method_name(is_a(String)) {return_value}
|
|
52
|
+
# object.method_name("A String") # passes
|
|
53
|
+
def is_a(klass)
|
|
54
|
+
RR::WildcardMatchers::IsA.new(klass)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Sets up an Numeric wildcard ArgumentEqualityExpectation
|
|
58
|
+
# that succeeds when passed an argument that is ::Numeric.
|
|
59
|
+
# mock(object).method_name(numeric) {return_value}
|
|
60
|
+
# object.method_name(99) # passes
|
|
61
|
+
def numeric
|
|
62
|
+
RR::WildcardMatchers::Numeric.new
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Sets up an Boolean wildcard ArgumentEqualityExpectation
|
|
66
|
+
# that succeeds when passed an argument that is a ::Boolean.
|
|
67
|
+
# mock(object).method_name(boolean) {return_value}
|
|
68
|
+
# object.method_name(false) # passes
|
|
69
|
+
def boolean
|
|
70
|
+
RR::WildcardMatchers::Boolean.new
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Sets up a DuckType wildcard ArgumentEqualityExpectation
|
|
74
|
+
# that succeeds when the passed argument implements the methods.
|
|
75
|
+
# arg = Object.new
|
|
76
|
+
# def arg.foo; end
|
|
77
|
+
# def arg.bar; end
|
|
78
|
+
# mock(object).method_name(duck_type(:foo, :bar)) {return_value}
|
|
79
|
+
# object.method_name(arg) # passes
|
|
80
|
+
def duck_type(*args)
|
|
81
|
+
RR::WildcardMatchers::DuckType.new(*args)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Sets up a HashIncluding wildcard ArgumentEqualityExpectation
|
|
85
|
+
# that succeeds when the passed argument contains at least those keys
|
|
86
|
+
# and values of the expectation.
|
|
87
|
+
# mock(object).method_name(hash_including(:foo => 1)) {return_value}
|
|
88
|
+
# object.method_name({:foo => 1, :bar => 2) # passes
|
|
89
|
+
def hash_including(expected_hash)
|
|
90
|
+
RR::WildcardMatchers::HashIncluding.new(expected_hash)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Sets up a Satisfy wildcard ArgumentEqualityExpectation
|
|
94
|
+
# that succeeds when the passed argument causes the expectation's
|
|
95
|
+
# proc to return true.
|
|
96
|
+
# mock(object).method_name(satisfy {|arg| arg == :foo}) {return_value}
|
|
97
|
+
# object.method_name(:foo) # passes
|
|
98
|
+
def satisfy(expectation_proc=nil, &block)
|
|
99
|
+
expectation_proc ||= block
|
|
100
|
+
RR::WildcardMatchers::Satisfy.new(expectation_proc)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def spy(subject)
|
|
104
|
+
methods_to_stub = subject.public_methods - ["methods", "==", "__send__", "__id__"]
|
|
105
|
+
methods_to_stub.each do |method|
|
|
106
|
+
stub.proxy(subject, method)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def received(subject)
|
|
111
|
+
RR::SpyVerificationProxy.new(subject)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
instance_methods.each do |name|
|
|
115
|
+
alias_method "rr_#{name}", name
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
module Extensions
|
|
120
|
+
InstanceMethods = Adapters::RRMethods
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module RR
|
|
2
|
+
module Adapters
|
|
3
|
+
module Rspec
|
|
4
|
+
def self.included(mod)
|
|
5
|
+
patterns = ::Spec::Runner::QuietBacktraceTweaker::IGNORE_PATTERNS
|
|
6
|
+
unless patterns.include?(RR::Errors::BACKTRACE_IDENTIFIER)
|
|
7
|
+
patterns.push(RR::Errors::BACKTRACE_IDENTIFIER)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
include RRMethods
|
|
12
|
+
def setup_mocks_for_rspec
|
|
13
|
+
RR.reset
|
|
14
|
+
end
|
|
15
|
+
def verify_mocks_for_rspec
|
|
16
|
+
RR.verify
|
|
17
|
+
end
|
|
18
|
+
def teardown_mocks_for_rspec
|
|
19
|
+
RR.reset
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def have_received(method = nil)
|
|
23
|
+
InvocationMatcher.new(method)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class InvocationMatcher < SpyVerificationProxy
|
|
27
|
+
attr_reader :failure_message
|
|
28
|
+
|
|
29
|
+
def initialize(method = nil)
|
|
30
|
+
method_missing(method) if method
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def matches?(subject)
|
|
34
|
+
@verification.subject = subject
|
|
35
|
+
if error = RR::Space.instance.recorded_calls.match_error(@verification)
|
|
36
|
+
@failure_message = error.message
|
|
37
|
+
false
|
|
38
|
+
else
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def nil?
|
|
44
|
+
false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(method_name, *args, &block)
|
|
48
|
+
if @verification
|
|
49
|
+
@verification.send(method_name, *args)
|
|
50
|
+
else
|
|
51
|
+
@verification = super
|
|
52
|
+
end
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module RR
|
|
2
|
+
module Adapters
|
|
3
|
+
module TestUnit
|
|
4
|
+
include RRMethods
|
|
5
|
+
def self.included(mod)
|
|
6
|
+
RR.trim_backtrace = true
|
|
7
|
+
mod.class_eval do
|
|
8
|
+
alias_method :setup_without_rr, :setup
|
|
9
|
+
def setup_with_rr
|
|
10
|
+
setup_without_rr
|
|
11
|
+
RR.reset
|
|
12
|
+
end
|
|
13
|
+
alias_method :setup, :setup_with_rr
|
|
14
|
+
|
|
15
|
+
alias_method :teardown_without_rr, :teardown
|
|
16
|
+
def teardown_with_rr
|
|
17
|
+
RR.verify
|
|
18
|
+
teardown_without_rr
|
|
19
|
+
end
|
|
20
|
+
alias_method :teardown, :teardown_with_rr
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def assert_received(subject, &block)
|
|
25
|
+
block.call(received(subject)).call
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/rr/double.rb
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
module RR
|
|
2
|
+
# RR::Double is the use case for a method call.
|
|
3
|
+
# It has the ArgumentEqualityExpectation, TimesCalledExpectation,
|
|
4
|
+
# and the implementation.
|
|
5
|
+
class Double
|
|
6
|
+
class << self
|
|
7
|
+
def formatted_name(method_name, args)
|
|
8
|
+
formatted_errors = args.collect {|arg| arg.inspect}.join(', ')
|
|
9
|
+
"#{method_name}(#{formatted_errors})"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def list_message_part(doubles)
|
|
13
|
+
doubles.collect do |double|
|
|
14
|
+
"- #{formatted_name(double.method_name, double.expected_arguments)}"
|
|
15
|
+
end.join("\n")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :times_called, :double_injection, :definition, :times_called_expectation
|
|
20
|
+
include Space::Reader
|
|
21
|
+
|
|
22
|
+
def initialize(double_injection, definition)
|
|
23
|
+
@double_injection = double_injection
|
|
24
|
+
@definition = definition
|
|
25
|
+
@times_called = 0
|
|
26
|
+
@times_called_expectation = Expectations::TimesCalledExpectation.new(self)
|
|
27
|
+
definition.double = self
|
|
28
|
+
verify_method_signature if definition.verify_method_signature?
|
|
29
|
+
double_injection.register_double self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Double#call calls the Double's implementation. The return
|
|
33
|
+
# value of the implementation is returned.
|
|
34
|
+
#
|
|
35
|
+
# A TimesCalledError is raised when the times called
|
|
36
|
+
# exceeds the expected TimesCalledExpectation.
|
|
37
|
+
def call(double_injection, *args, &block)
|
|
38
|
+
if verbose?
|
|
39
|
+
puts Double.formatted_name(double_injection.method_name, args)
|
|
40
|
+
end
|
|
41
|
+
times_called_expectation.attempt if definition.times_matcher
|
|
42
|
+
space.verify_ordered_double(self) if ordered?
|
|
43
|
+
yields!(block)
|
|
44
|
+
return_value = call_implementation(double_injection, *args, &block)
|
|
45
|
+
definition.after_call_proc ? extract_subject_from_return_value(definition.after_call_proc.call(return_value)) : return_value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Double#exact_match? returns true when the passed in arguments
|
|
49
|
+
# exactly match the ArgumentEqualityExpectation arguments.
|
|
50
|
+
def exact_match?(*arguments)
|
|
51
|
+
definition.exact_match?(*arguments)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Double#wildcard_match? returns true when the passed in arguments
|
|
55
|
+
# wildcard match the ArgumentEqualityExpectation arguments.
|
|
56
|
+
def wildcard_match?(*arguments)
|
|
57
|
+
definition.wildcard_match?(*arguments)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Double#attempt? returns true when the
|
|
61
|
+
# TimesCalledExpectation is satisfied.
|
|
62
|
+
def attempt?
|
|
63
|
+
verify_times_matcher_is_set
|
|
64
|
+
times_called_expectation.attempt?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Double#verify verifies the the TimesCalledExpectation
|
|
68
|
+
# is satisfied for this double. A TimesCalledError
|
|
69
|
+
# is raised if the TimesCalledExpectation is not met.
|
|
70
|
+
def verify
|
|
71
|
+
verify_times_matcher_is_set
|
|
72
|
+
times_called_expectation.verify!
|
|
73
|
+
true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def terminal?
|
|
77
|
+
verify_times_matcher_is_set
|
|
78
|
+
times_called_expectation.terminal?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The method name that this Double is attatched to
|
|
82
|
+
def method_name
|
|
83
|
+
double_injection.method_name
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# The Arguments that this Double expects
|
|
87
|
+
def expected_arguments
|
|
88
|
+
verify_argument_expectation_is_set
|
|
89
|
+
argument_expectation.expected_arguments
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The TimesCalledMatcher for the TimesCalledExpectation
|
|
93
|
+
def times_matcher
|
|
94
|
+
definition.times_matcher
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def formatted_name
|
|
98
|
+
self.class.formatted_name(method_name, expected_arguments)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
protected
|
|
102
|
+
def ordered?
|
|
103
|
+
definition.ordered?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def verbose?
|
|
107
|
+
definition.verbose?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def yields!(block)
|
|
111
|
+
if definition.yields_value
|
|
112
|
+
if block
|
|
113
|
+
block.call(*definition.yields_value)
|
|
114
|
+
else
|
|
115
|
+
raise ArgumentError, "A Block must be passed into the method call when using yields"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def call_implementation(double_injection, *args, &block)
|
|
121
|
+
return_value = do_call_implementation_and_get_return_value(double_injection, *args, &block)
|
|
122
|
+
extract_subject_from_return_value(return_value)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def verify_times_matcher_is_set
|
|
126
|
+
unless definition.times_matcher
|
|
127
|
+
raise RR::Errors::DoubleDefinitionError, "#definition.times_matcher is not set"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def verify_argument_expectation_is_set
|
|
132
|
+
unless definition.argument_expectation
|
|
133
|
+
raise RR::Errors::DoubleDefinitionError, "#definition.argument_expectation is not set"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def verify_method_signature
|
|
138
|
+
raise RR::Errors::SubjectDoesNotImplementMethodError unless definition.subject.respond_to?(double_injection.send(:original_method_name))
|
|
139
|
+
raise RR::Errors::SubjectHasDifferentArityError unless arity_matches?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def subject_arity
|
|
143
|
+
definition.subject.method(double_injection.send(:original_method_name)).arity
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def subject_accepts_only_varargs?
|
|
147
|
+
subject_arity == -1
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def subject_accepts_varargs?
|
|
151
|
+
subject_arity < 0
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def arity_matches?
|
|
155
|
+
return true if subject_accepts_only_varargs?
|
|
156
|
+
if subject_accepts_varargs?
|
|
157
|
+
return ((subject_arity * -1) - 1) <= args.size
|
|
158
|
+
else
|
|
159
|
+
return subject_arity == args.size
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def args
|
|
164
|
+
definition.argument_expectation.expected_arguments
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def do_call_implementation_and_get_return_value(double_injection, *args, &block)
|
|
168
|
+
if definition.implementation_is_original_method?
|
|
169
|
+
if double_injection.object_has_original_method?
|
|
170
|
+
double_injection.call_original_method(*args, &block)
|
|
171
|
+
else
|
|
172
|
+
double_injection.subject.__send__(
|
|
173
|
+
:method_missing,
|
|
174
|
+
method_name,
|
|
175
|
+
*args,
|
|
176
|
+
&block
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
else
|
|
180
|
+
if implementation
|
|
181
|
+
if implementation.is_a?(Method)
|
|
182
|
+
implementation.call(*args, &block)
|
|
183
|
+
else
|
|
184
|
+
args << block if block
|
|
185
|
+
implementation.call(*args)
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
nil
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def extract_subject_from_return_value(return_value)
|
|
194
|
+
case return_value
|
|
195
|
+
when DoubleDefinitions::DoubleDefinition
|
|
196
|
+
return_value.root_subject
|
|
197
|
+
when DoubleDefinitions::DoubleDefinitionCreatorProxy
|
|
198
|
+
return_value.__creator__.root_subject
|
|
199
|
+
else
|
|
200
|
+
return_value
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def implementation
|
|
205
|
+
definition.implementation
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def argument_expectation
|
|
209
|
+
definition.argument_expectation
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|