opal-rspec-cj 0.4.4
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.gitmodules +15 -0
- data/.travis.yml +13 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +8 -0
- data/README.md +147 -0
- data/Rakefile +26 -0
- data/config.ru +10 -0
- data/example/Gemfile +4 -0
- data/example/README.md +13 -0
- data/example/Rakefile +8 -0
- data/example/opal/user.rb +11 -0
- data/example/spec/user_spec.rb +15 -0
- data/lib/opal-rspec.rb +2 -0
- data/lib/opal/rspec.rb +20 -0
- data/lib/opal/rspec/rake_task.rb +63 -0
- data/lib/opal/rspec/version.rb +5 -0
- data/opal-rspec.gemspec +21 -0
- data/opal/opal-rspec.rb +1 -0
- data/opal/opal/rspec.rb +25 -0
- data/opal/opal/rspec/async.rb +289 -0
- data/opal/opal/rspec/browser_formatter.rb +188 -0
- data/opal/opal/rspec/fixes.rb +116 -0
- data/opal/opal/rspec/requires.rb +45 -0
- data/opal/opal/rspec/runner.rb +69 -0
- data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
- data/opal/opal/rspec/text_formatter.rb +74 -0
- data/spec/async_spec.rb +38 -0
- data/spec/example_spec.rb +163 -0
- data/spec/matchers_spec.rb +201 -0
- data/spec/mock_spec.rb +63 -0
- data/spec/named_subject_spec.rb +11 -0
- data/spec/should_syntax_spec.rb +17 -0
- data/vendor/spec_runner.js +50 -0
- data/vendor_lib/rspec-expectations.rb +1 -0
- data/vendor_lib/rspec.rb +3 -0
- data/vendor_lib/rspec/autorun.rb +2 -0
- data/vendor_lib/rspec/core.rb +203 -0
- data/vendor_lib/rspec/core/backport_random.rb +302 -0
- data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
- data/vendor_lib/rspec/core/command_line.rb +36 -0
- data/vendor_lib/rspec/core/configuration.rb +1129 -0
- data/vendor_lib/rspec/core/configuration_options.rb +143 -0
- data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
- data/vendor_lib/rspec/core/drb_options.rb +87 -0
- data/vendor_lib/rspec/core/dsl.rb +26 -0
- data/vendor_lib/rspec/core/example.rb +312 -0
- data/vendor_lib/rspec/core/example_group.rb +540 -0
- data/vendor_lib/rspec/core/filter_manager.rb +224 -0
- data/vendor_lib/rspec/core/flat_map.rb +17 -0
- data/vendor_lib/rspec/core/formatters.rb +54 -0
- data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
- data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
- data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
- data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
- data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
- data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
- data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
- data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
- data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
- data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
- data/vendor_lib/rspec/core/hooks.rb +535 -0
- data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
- data/vendor_lib/rspec/core/metadata.rb +313 -0
- data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
- data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
- data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
- data/vendor_lib/rspec/core/option_parser.rb +234 -0
- data/vendor_lib/rspec/core/ordering.rb +154 -0
- data/vendor_lib/rspec/core/pending.rb +110 -0
- data/vendor_lib/rspec/core/project_initializer.rb +88 -0
- data/vendor_lib/rspec/core/rake_task.rb +128 -0
- data/vendor_lib/rspec/core/reporter.rb +132 -0
- data/vendor_lib/rspec/core/ruby_project.rb +44 -0
- data/vendor_lib/rspec/core/runner.rb +97 -0
- data/vendor_lib/rspec/core/shared_context.rb +53 -0
- data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
- data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
- data/vendor_lib/rspec/core/version.rb +7 -0
- data/vendor_lib/rspec/core/warnings.rb +22 -0
- data/vendor_lib/rspec/core/world.rb +131 -0
- data/vendor_lib/rspec/expectations.rb +75 -0
- data/vendor_lib/rspec/expectations/differ.rb +154 -0
- data/vendor_lib/rspec/expectations/errors.rb +9 -0
- data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
- data/vendor_lib/rspec/expectations/extensions.rb +1 -0
- data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
- data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
- data/vendor_lib/rspec/expectations/handler.rb +68 -0
- data/vendor_lib/rspec/expectations/syntax.rb +182 -0
- data/vendor_lib/rspec/expectations/version.rb +8 -0
- data/vendor_lib/rspec/matchers.rb +633 -0
- data/vendor_lib/rspec/matchers/built_in.rb +39 -0
- data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
- data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
- data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
- data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
- data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
- data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
- data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
- data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
- data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
- data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
- data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
- data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
- data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
- data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
- data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
- data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
- data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
- data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
- data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
- data/vendor_lib/rspec/matchers/configuration.rb +113 -0
- data/vendor_lib/rspec/matchers/dsl.rb +23 -0
- data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
- data/vendor_lib/rspec/matchers/matcher.rb +301 -0
- data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
- data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
- data/vendor_lib/rspec/matchers/pretty.rb +70 -0
- data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
- data/vendor_lib/rspec/mocks.rb +100 -0
- data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
- data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
- data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
- data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
- data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
- data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
- data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
- data/vendor_lib/rspec/mocks/configuration.rb +111 -0
- data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
- data/vendor_lib/rspec/mocks/errors.rb +12 -0
- data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
- data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
- data/vendor_lib/rspec/mocks/framework.rb +36 -0
- data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
- data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
- data/vendor_lib/rspec/mocks/method_double.rb +209 -0
- data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
- data/vendor_lib/rspec/mocks/mock.rb +7 -0
- data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
- data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
- data/vendor_lib/rspec/mocks/order_group.rb +82 -0
- data/vendor_lib/rspec/mocks/proxy.rb +269 -0
- data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
- data/vendor_lib/rspec/mocks/space.rb +95 -0
- data/vendor_lib/rspec/mocks/standalone.rb +3 -0
- data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
- data/vendor_lib/rspec/mocks/syntax.rb +374 -0
- data/vendor_lib/rspec/mocks/targets.rb +90 -0
- data/vendor_lib/rspec/mocks/test_double.rb +109 -0
- data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
- data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/vendor_lib/rspec/mocks/version.rb +7 -0
- data/vendor_lib/rspec/support.rb +6 -0
- data/vendor_lib/rspec/support/caller_filter.rb +56 -0
- data/vendor_lib/rspec/support/spec.rb +14 -0
- data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
- data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
- data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
- data/vendor_lib/rspec/support/version.rb +7 -0
- data/vendor_lib/rspec/support/warnings.rb +41 -0
- data/vendor_lib/rspec/version.rb +5 -0
- metadata +268 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def method_missing(method, *args, &block)
|
|
7
|
+
return Matchers::BuiltIn::BePredicate.new(method, *args, &block) if method.to_s =~ /^be_/
|
|
8
|
+
return Matchers::BuiltIn::Has.new(method, *args, &block) if method.to_s =~ /^have_/
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
class OperatorMatcher
|
|
4
|
+
class << self
|
|
5
|
+
def registry
|
|
6
|
+
@registry ||= {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def register(klass, operator, matcher)
|
|
10
|
+
registry[klass] ||= {}
|
|
11
|
+
registry[klass][operator] = matcher
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def unregister(klass, operator)
|
|
15
|
+
registry[klass] && registry[klass].delete(operator)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get(klass, operator)
|
|
19
|
+
klass.ancestors.each { |ancestor|
|
|
20
|
+
matcher = registry[ancestor] && registry[ancestor][operator]
|
|
21
|
+
return matcher if matcher
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(actual)
|
|
29
|
+
@actual = actual
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.use_custom_matcher_or_delegate(operator)
|
|
33
|
+
define_method(operator) do |expected|
|
|
34
|
+
if uses_generic_implementation_of?(operator) && matcher = OperatorMatcher.get(@actual.class, operator)
|
|
35
|
+
@actual.__send__(::RSpec::Matchers.last_should, matcher.new(expected))
|
|
36
|
+
else
|
|
37
|
+
eval_match(@actual, operator, expected)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
negative_operator = operator.sub(/^=/, '!')
|
|
42
|
+
if negative_operator != operator && respond_to?(negative_operator)
|
|
43
|
+
define_method(negative_operator) do |expected|
|
|
44
|
+
opposite_should = ::RSpec::Matchers.last_should == :should ? :should_not : :should
|
|
45
|
+
raise "RSpec does not support `#{::RSpec::Matchers.last_should} #{negative_operator} expected`. " +
|
|
46
|
+
"Use `#{opposite_should} #{operator} expected` instead."
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
['==', '===', '=~', '>', '>=', '<', '<='].each do |operator|
|
|
52
|
+
use_custom_matcher_or_delegate operator
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def fail_with_message(message)
|
|
56
|
+
RSpec::Expectations.fail_with(message, @expected, @actual)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def description
|
|
60
|
+
"#{@operator} #{@expected.inspect}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def uses_generic_implementation_of?(op)
|
|
66
|
+
Expectations.method_handle_for(@actual, op).owner == ::Kernel
|
|
67
|
+
rescue NameError
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def eval_match(actual, operator, expected)
|
|
72
|
+
::RSpec::Matchers.last_matcher = self
|
|
73
|
+
@operator, @expected = operator, expected
|
|
74
|
+
__delegate_operator(actual, operator, expected)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module BuiltIn
|
|
79
|
+
class PositiveOperatorMatcher < OperatorMatcher
|
|
80
|
+
def __delegate_operator(actual, operator, expected)
|
|
81
|
+
if actual.__send__(operator, expected)
|
|
82
|
+
true
|
|
83
|
+
elsif ['==','===', '=~'].include?(operator)
|
|
84
|
+
fail_with_message("expected: #{expected.inspect}\n got: #{actual.inspect} (using #{operator})")
|
|
85
|
+
else
|
|
86
|
+
fail_with_message("expected: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class NegativeOperatorMatcher < OperatorMatcher
|
|
92
|
+
def __delegate_operator(actual, operator, expected)
|
|
93
|
+
return false unless actual.__send__(operator, expected)
|
|
94
|
+
return fail_with_message("expected not: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
module Pretty
|
|
4
|
+
def split_words(sym)
|
|
5
|
+
sym.to_s.gsub(/_/,' ')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def to_sentence(words)
|
|
9
|
+
return "" unless words
|
|
10
|
+
words = Array(words).map { |w| to_word(w) }
|
|
11
|
+
case words.length
|
|
12
|
+
when 0
|
|
13
|
+
""
|
|
14
|
+
when 1
|
|
15
|
+
" #{words[0]}"
|
|
16
|
+
when 2
|
|
17
|
+
" #{words[0]} and #{words[1]}"
|
|
18
|
+
else
|
|
19
|
+
" #{words[0...-1].join(', ')}, and #{words[-1]}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def _pretty_print(array)
|
|
24
|
+
result = ""
|
|
25
|
+
array.each_with_index do |item, index|
|
|
26
|
+
if index < (array.length - 2)
|
|
27
|
+
result << "#{item.inspect}, "
|
|
28
|
+
elsif index < (array.length - 1)
|
|
29
|
+
result << "#{item.inspect} and "
|
|
30
|
+
else
|
|
31
|
+
result << "#{item.inspect}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_word(item)
|
|
38
|
+
is_matcher_with_description?(item) ? item.description : item.inspect
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def name_to_sentence
|
|
42
|
+
split_words(name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def expected_to_sentence
|
|
46
|
+
to_sentence(@expected) if defined?(@expected)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def name
|
|
50
|
+
defined?(@name) ? @name : underscore(self.class.name.split("::").last)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Borrowed from ActiveSupport
|
|
54
|
+
def underscore(camel_cased_word)
|
|
55
|
+
word = camel_cased_word.to_s.dup
|
|
56
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
|
57
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
|
58
|
+
word.tr!("-", "_")
|
|
59
|
+
word.downcase!
|
|
60
|
+
word
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def is_matcher_with_description?(object)
|
|
66
|
+
RSpec::Matchers.is_a_matcher?(object) && object.respond_to?(:description)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Include Matchers for other test frameworks. Note that MiniTest _must_
|
|
2
|
+
# come before TU because on ruby 1.9, T::U::TC is a subclass of MT::U::TC
|
|
3
|
+
# and a 1.9 bug can lead to infinite recursion from the `super` call in our
|
|
4
|
+
# method_missing hook. See this gist for more info:
|
|
5
|
+
# https://gist.github.com/845896
|
|
6
|
+
if defined?(MiniTest::Unit::TestCase)
|
|
7
|
+
MiniTest::Unit::TestCase.send(:include, RSpec::Matchers)
|
|
8
|
+
end
|
|
9
|
+
if defined?(Test::Unit::TestCase)
|
|
10
|
+
Test::Unit::TestCase.send(:include, RSpec::Matchers)
|
|
11
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'rspec/mocks/framework'
|
|
2
|
+
require 'rspec/mocks/version'
|
|
3
|
+
|
|
4
|
+
module RSpec
|
|
5
|
+
|
|
6
|
+
module Mocks
|
|
7
|
+
class << self
|
|
8
|
+
attr_accessor :space
|
|
9
|
+
|
|
10
|
+
def setup(host)
|
|
11
|
+
(class << host; self; end).class_exec do
|
|
12
|
+
include RSpec::Mocks::ExampleMethods
|
|
13
|
+
end
|
|
14
|
+
self.space ||= RSpec::Mocks::Space.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def verify
|
|
18
|
+
space.verify_all
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def teardown
|
|
22
|
+
space.reset_all
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def proxy_for(object)
|
|
26
|
+
space.proxy_for(object)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def proxies_of(klass)
|
|
30
|
+
space.proxies_of(klass)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def any_instance_recorder_for(klass)
|
|
34
|
+
space.any_instance_recorder_for(klass)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Adds an allowance (stub) on `subject`
|
|
38
|
+
#
|
|
39
|
+
# @param subject the subject to which the message will be added
|
|
40
|
+
# @param message a symbol, representing the message that will be
|
|
41
|
+
# added.
|
|
42
|
+
# @param opts a hash of options, :expected_from is used to set the
|
|
43
|
+
# original call site
|
|
44
|
+
# @param block an optional implementation for the allowance
|
|
45
|
+
#
|
|
46
|
+
# @example Defines the implementation of `foo` on `bar`, using the passed block
|
|
47
|
+
# x = 0
|
|
48
|
+
# RSpec::Mocks.allow_message(bar, :foo) { x += 1 }
|
|
49
|
+
def allow_message(subject, message, opts={}, &block)
|
|
50
|
+
orig_caller = opts.fetch(:expected_from) {
|
|
51
|
+
CallerFilter.first_non_rspec_line
|
|
52
|
+
}
|
|
53
|
+
::RSpec::Mocks.proxy_for(subject).
|
|
54
|
+
add_stub(orig_caller, message, opts, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Sets a message expectation on `subject`.
|
|
58
|
+
# @param subject the subject on which the message will be expected
|
|
59
|
+
# @param message a symbol, representing the message that will be
|
|
60
|
+
# expected.
|
|
61
|
+
# @param opts a hash of options, :expected_from is used to set the
|
|
62
|
+
# original call site
|
|
63
|
+
# @param block an optional implementation for the expectation
|
|
64
|
+
#
|
|
65
|
+
# @example Expect the message `foo` to receive `bar`, then call it
|
|
66
|
+
# RSpec::Mocks.expect_message(bar, :foo)
|
|
67
|
+
# bar.foo
|
|
68
|
+
def expect_message(subject, message, opts={}, &block)
|
|
69
|
+
orig_caller = opts.fetch(:expected_from) {
|
|
70
|
+
CallerFilter.first_non_rspec_line
|
|
71
|
+
}
|
|
72
|
+
::RSpec::Mocks.proxy_for(subject).
|
|
73
|
+
add_message_expectation(orig_caller, message, opts, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @api private
|
|
77
|
+
KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
|
|
78
|
+
|
|
79
|
+
# @api private
|
|
80
|
+
# Used internally to get a method handle for a particular object
|
|
81
|
+
# and method name.
|
|
82
|
+
#
|
|
83
|
+
# Includes handling for a few special cases:
|
|
84
|
+
#
|
|
85
|
+
# - Objects that redefine #method (e.g. an HTTPRequest struct)
|
|
86
|
+
# - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
|
|
87
|
+
def method_handle_for(object, method_name)
|
|
88
|
+
if ::Kernel === object
|
|
89
|
+
KERNEL_METHOD_METHOD.bind(object).call(method_name)
|
|
90
|
+
else
|
|
91
|
+
object.method(method_name)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @private
|
|
97
|
+
IGNORED_BACKTRACE_LINE = 'this backtrace line is ignored'
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
class Chain
|
|
5
|
+
def initialize(recorder, *args, &block)
|
|
6
|
+
@recorder = recorder
|
|
7
|
+
@expectation_args = args
|
|
8
|
+
@expectation_block = block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Customizations
|
|
12
|
+
# @macro [attach] record
|
|
13
|
+
# @method $1(*args, &block)
|
|
14
|
+
# Records the `$1` message for playback against an instance that
|
|
15
|
+
# invokes a method stubbed or mocked using `any_instance`.
|
|
16
|
+
#
|
|
17
|
+
# @see RSpec::Mocks::MessageExpectation#$1
|
|
18
|
+
#
|
|
19
|
+
def self.record(method_name)
|
|
20
|
+
define_method(method_name) do |*args, &block|
|
|
21
|
+
record(method_name, *args, &block)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
record :and_return
|
|
26
|
+
record :and_raise
|
|
27
|
+
record :and_throw
|
|
28
|
+
record :and_yield
|
|
29
|
+
record :and_call_original
|
|
30
|
+
record :with
|
|
31
|
+
record :once
|
|
32
|
+
record :twice
|
|
33
|
+
record :any_number_of_times
|
|
34
|
+
record :exactly
|
|
35
|
+
record :times
|
|
36
|
+
record :never
|
|
37
|
+
record :at_least
|
|
38
|
+
record :at_most
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
include Customizations
|
|
42
|
+
|
|
43
|
+
# @private
|
|
44
|
+
def playback!(instance)
|
|
45
|
+
message_expectation = create_message_expectation_on(instance)
|
|
46
|
+
messages.inject(message_expectation) do |object, message|
|
|
47
|
+
object.__send__(*message.first, &message.last)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @private
|
|
52
|
+
def constrained_to_any_of?(*constraints)
|
|
53
|
+
constraints.any? do |constraint|
|
|
54
|
+
messages.any? do |message|
|
|
55
|
+
message.first.first == constraint
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @private
|
|
61
|
+
def expectation_fulfilled!
|
|
62
|
+
@expectation_fulfilled = true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def never
|
|
66
|
+
ErrorGenerator.raise_double_negation_error("expect_any_instance_of(MyClass)") if negated?
|
|
67
|
+
super
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def negated?
|
|
73
|
+
messages.any? { |(message, *_), _| message == :never }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def messages
|
|
77
|
+
@messages ||= []
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def last_message
|
|
81
|
+
messages.last.first.first unless messages.empty?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def record(rspec_method_name, *args, &block)
|
|
85
|
+
verify_invocation_order(rspec_method_name, *args, &block)
|
|
86
|
+
messages << [args.unshift(rspec_method_name), block]
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
# @api private
|
|
5
|
+
class ExpectationChain < Chain
|
|
6
|
+
def expectation_fulfilled?
|
|
7
|
+
@expectation_fulfilled || constrained_to_any_of?(:never, :any_number_of_times)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(*args, &block)
|
|
11
|
+
@expectation_fulfilled = false
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @api private
|
|
21
|
+
class PositiveExpectationChain < ExpectationChain
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def create_message_expectation_on(instance)
|
|
26
|
+
proxy = ::RSpec::Mocks.proxy_for(instance)
|
|
27
|
+
expected_from = IGNORED_BACKTRACE_LINE
|
|
28
|
+
me = proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
|
|
29
|
+
if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
|
|
30
|
+
me.and_yield_receiver_to_implementation
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
me
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def invocation_order
|
|
37
|
+
@invocation_order ||= {
|
|
38
|
+
:with => [nil],
|
|
39
|
+
:and_return => [:with, nil],
|
|
40
|
+
:and_raise => [:with, nil]
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
# @private
|
|
5
|
+
class MessageChains
|
|
6
|
+
def initialize
|
|
7
|
+
@chains_by_method_name = Hash.new { |h, k| h[k] = [] }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @private
|
|
11
|
+
def [](method_name)
|
|
12
|
+
@chains_by_method_name[method_name]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @private
|
|
16
|
+
def add(method_name, chain)
|
|
17
|
+
@chains_by_method_name[method_name] << chain
|
|
18
|
+
chain
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @private
|
|
22
|
+
def remove_stub_chains_for!(method_name)
|
|
23
|
+
@chains_by_method_name[method_name].reject! do |chain|
|
|
24
|
+
StubChain === chain
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @private
|
|
29
|
+
def has_expectation?(method_name)
|
|
30
|
+
@chains_by_method_name[method_name].find do |chain|
|
|
31
|
+
ExpectationChain === chain
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @private
|
|
36
|
+
def all_expectations_fulfilled?
|
|
37
|
+
@chains_by_method_name.all? do |method_name, chains|
|
|
38
|
+
chains.all? { |chain| chain.expectation_fulfilled? }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @private
|
|
43
|
+
def unfulfilled_expectations
|
|
44
|
+
@chains_by_method_name.map do |method_name, chains|
|
|
45
|
+
method_name.to_s if ExpectationChain === chains.last unless chains.last.expectation_fulfilled?
|
|
46
|
+
end.compact
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @private
|
|
50
|
+
def received_expected_message!(method_name)
|
|
51
|
+
@chains_by_method_name[method_name].each do |chain|
|
|
52
|
+
chain.expectation_fulfilled!
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @private
|
|
57
|
+
def playback!(instance, method_name)
|
|
58
|
+
raise_if_second_instance_to_receive_message(instance)
|
|
59
|
+
@chains_by_method_name[method_name].each do |chain|
|
|
60
|
+
chain.playback!(instance)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def raise_if_second_instance_to_receive_message(instance)
|
|
67
|
+
@instance_with_expectation ||= instance if ExpectationChain === instance
|
|
68
|
+
if ExpectationChain === instance && !@instance_with_expectation.equal?(instance)
|
|
69
|
+
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|