├── .gemtest
├── docs
├── CNAME
├── css
│ └── common.css
├── frames.html
├── file.COPYING.html
├── file_list.html
└── top-level-namespace.html
├── .github
└── FUNDING.yml
├── lib
├── mocha.rb
└── mocha
│ ├── version.rb
│ ├── is_a.rb
│ ├── ruby_version.rb
│ ├── macos_version.rb
│ ├── logger.rb
│ ├── minitest.rb
│ ├── test_unit.rb
│ ├── debug.rb
│ ├── raised_exception.rb
│ ├── not_initialized_error.rb
│ ├── stubbing_error.rb
│ ├── thrown_object.rb
│ ├── thrower.rb
│ ├── single_return_value.rb
│ ├── integration
│ ├── assertion_counter.rb
│ ├── minitest
│ │ ├── exception_translation.rb
│ │ └── adapter.rb
│ ├── monkey_patcher.rb
│ ├── minitest.rb
│ ├── test_unit.rb
│ └── test_unit
│ │ └── adapter.rb
│ ├── change_state_side_effect.rb
│ ├── error_with_filtered_backtrace.rb
│ ├── in_state_ordering_constraint.rb
│ ├── instance_method.rb
│ ├── expectation_error.rb
│ ├── any_instance_method.rb
│ ├── argument_iterator.rb
│ ├── method_matcher.rb
│ ├── backtrace_filter.rb
│ ├── exception_raiser.rb
│ ├── yield_parameters.rb
│ ├── deprecation.rb
│ ├── detection
│ ├── minitest.rb
│ └── test_unit.rb
│ ├── block_matcher.rb
│ ├── return_values.rb
│ ├── parameter_matchers
│ ├── instance_methods.rb
│ ├── anything.rb
│ ├── any_parameters.rb
│ ├── equals.rb
│ ├── is_a.rb
│ ├── not.rb
│ ├── instance_of.rb
│ ├── all_of.rb
│ ├── kind_of.rb
│ ├── has_key.rb
│ ├── regexp_matches.rb
│ ├── has_value.rb
│ ├── any_of.rb
│ ├── yaml_equivalent.rb
│ ├── has_keys.rb
│ ├── equivalent_uri.rb
│ ├── has_entries.rb
│ ├── optionally.rb
│ ├── positional_or_keyword_hash.rb
│ └── base.rb
│ ├── names.rb
│ ├── receivers.rb
│ ├── central.rb
│ ├── parameters_matcher.rb
│ ├── sequence.rb
│ ├── parameter_matchers.rb
│ ├── expectation_error_factory.rb
│ ├── expectation_list.rb
│ ├── inspect.rb
│ ├── invocation.rb
│ ├── class_methods.rb
│ ├── hooks.rb
│ └── stubbed_method.rb
├── .gitignore
├── gemfiles
├── Gemfile.minitest.latest
└── Gemfile.test-unit.latest
├── test
├── simple_counter.rb
├── hashlike.rb
├── assertions.rb
├── integration
│ ├── minitest_test.rb
│ └── test_unit_test.rb
├── unit
│ ├── string_inspect_test.rb
│ ├── parameter_matchers
│ │ ├── stub_matcher.rb
│ │ ├── anything_test.rb
│ │ ├── equals_test.rb
│ │ ├── is_a_test.rb
│ │ ├── kind_of_test.rb
│ │ ├── instance_of_test.rb
│ │ ├── not_test.rb
│ │ ├── yaml_equivalent_test.rb
│ │ ├── all_of_test.rb
│ │ ├── any_of_test.rb
│ │ ├── regexp_matches_test.rb
│ │ ├── equivalent_uri_test.rb
│ │ ├── responds_with_test.rb
│ │ ├── has_key_test.rb
│ │ ├── has_value_test.rb
│ │ └── has_keys_test.rb
│ ├── single_return_value_test.rb
│ ├── module_methods_test.rb
│ ├── array_inspect_test.rb
│ ├── date_time_inspect_test.rb
│ ├── thrower_test.rb
│ ├── change_state_side_effect_test.rb
│ ├── hash_inspect_test.rb
│ ├── hooks_test.rb
│ ├── method_matcher_test.rb
│ ├── backtrace_filter_test.rb
│ ├── in_state_ordering_constraint_test.rb
│ ├── object_inspect_test.rb
│ ├── exception_raiser_test.rb
│ ├── object_methods_test.rb
│ ├── class_methods_test.rb
│ ├── configuration_test.rb
│ └── receivers_test.rb
├── deprecation_disabler.rb
├── acceptance
│ ├── bug_21563_test.rb
│ ├── unexpected_invocation_test.rb
│ ├── bug_21465_test.rb
│ ├── issue_457_test.rb
│ ├── array_flatten_test.rb
│ ├── bug_18914_test.rb
│ ├── issue_524_test.rb
│ ├── stubbing_same_class_method_on_parent_and_child_classes_test.rb
│ ├── acceptance_test_helper.rb
│ ├── stub_method_defined_on_module_and_aliased_test.rb
│ ├── throw_test.rb
│ ├── raise_exception_test.rb
│ ├── partial_mocks_test.rb
│ ├── issue_272_test.rb
│ ├── stub_test.rb
│ ├── exception_rescue_test.rb
│ ├── stub_everything_test.rb
│ ├── return_value_test.rb
│ ├── issue_70_test.rb
│ ├── issue_65_test.rb
│ ├── stubbing_method_accepting_block_parameter_test.rb
│ ├── expectations_on_multiple_methods_test.rb
│ ├── multiple_yielding_test.rb
│ ├── states_test.rb
│ ├── stub_instance_method_defined_on_active_record_association_proxy_test.rb
│ ├── stubba_test_result_test.rb
│ ├── stub_any_instance_method_defined_on_superclass_test.rb
│ ├── stubbing_nil_test.rb
│ ├── prepend_test.rb
│ ├── stub_class_method_defined_on_active_record_association_proxy_test.rb
│ ├── optional_parameters_test.rb
│ ├── yielding_test.rb
│ ├── stub_class_method_defined_on_module_test.rb
│ ├── stubbing_method_unnecessarily_test.rb
│ ├── stub_instance_method_defined_on_singleton_class_test.rb
│ ├── mocked_methods_dispatch_test.rb
│ ├── stub_instance_method_defined_on_class_and_aliased_test.rb
│ ├── stub_instance_method_defined_on_class_test.rb
│ ├── stub_instance_method_defined_on_superclass_test.rb
│ ├── stubbing_error_backtrace_test.rb
│ ├── mocha_test_result_test.rb
│ └── failure_messages_test.rb
├── test_unit_result.rb
├── method_definer.rb
├── execution_point.rb
├── minitest_result.rb
├── test_helper.rb
└── test_runner.rb
├── COPYING.md
├── CONTRIBUTING.md
├── .yardopts
├── Gemfile
├── .rubocop_todo.yml
├── mocha.gemspec
├── MIT-LICENSE.md
└── .rubocop.yml
/.gemtest:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | mocha.jamesmead.org
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: floehopper
2 |
--------------------------------------------------------------------------------
/lib/mocha.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/version'
2 |
--------------------------------------------------------------------------------
/docs/css/common.css:
--------------------------------------------------------------------------------
1 | /* Override this file with custom rules */
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | TODO
2 | Gemfile*.lock
3 | pkg
4 | tmp
5 | .yardoc
6 |
--------------------------------------------------------------------------------
/lib/mocha/version.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | VERSION = '2.4.5'.freeze
3 | end
4 |
--------------------------------------------------------------------------------
/lib/mocha/is_a.rb:
--------------------------------------------------------------------------------
1 | class Object
2 | # :stopdoc:
3 |
4 | alias_method :__is_a__, :is_a?
5 |
6 | # :startdoc:
7 | end
8 |
--------------------------------------------------------------------------------
/lib/mocha/ruby_version.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | RUBY_V27_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.7')
3 | end
4 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile.minitest.latest:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec :path=>"../"
4 |
5 | group :development do
6 | gem "rake"
7 | gem "minitest"
8 | end
9 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile.test-unit.latest:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec :path=>"../"
4 |
5 | group :development do
6 | gem "rake"
7 | gem "test-unit"
8 | end
9 |
--------------------------------------------------------------------------------
/lib/mocha/macos_version.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | MACOS = /darwin/.match(RUBY_PLATFORM)
3 | MACOS_VERSION = MACOS && /darwin(\d+)/.match(RUBY_PLATFORM)[1].to_i
4 | MACOS_MOJAVE_VERSION = 18
5 | end
6 |
--------------------------------------------------------------------------------
/test/simple_counter.rb:
--------------------------------------------------------------------------------
1 | class SimpleCounter
2 | attr_reader :count
3 |
4 | def initialize
5 | @count = 0
6 | end
7 |
8 | def increment
9 | @count += 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/mocha/logger.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class Logger
3 | def initialize(io)
4 | @io = io
5 | end
6 |
7 | def warn(message)
8 | @io.puts "WARNING: #{message}"
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/hashlike.rb:
--------------------------------------------------------------------------------
1 | require 'forwardable'
2 |
3 | class Hashlike
4 | extend Forwardable
5 |
6 | def_delegators :@hash, :keys, :[]
7 |
8 | def initialize(hash = {})
9 | @hash = hash
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/mocha/minitest.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/ruby_version'
2 | require 'mocha/integration/minitest'
3 |
4 | unless Mocha::Integration::Minitest.activate
5 | raise "Minitest must be loaded *before* `require 'mocha/minitest'`."
6 | end
7 |
--------------------------------------------------------------------------------
/COPYING.md:
--------------------------------------------------------------------------------
1 | Copyright James Mead 2006
2 |
3 | You may use, copy and redistribute this library under the same terms as [Ruby itself](https://www.ruby-lang.org/en/about/license.txt) or under the [MIT license](https://mit-license.org/).
4 |
--------------------------------------------------------------------------------
/lib/mocha/test_unit.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/ruby_version'
2 | require 'mocha/integration/test_unit'
3 |
4 | unless Mocha::Integration::TestUnit.activate
5 | raise "Test::Unit must be loaded *before* `require 'mocha/test_unit'`."
6 | end
7 |
--------------------------------------------------------------------------------
/test/assertions.rb:
--------------------------------------------------------------------------------
1 | module Assertions
2 | def assert_method_visibility(object, method_name, visibility)
3 | assert object.send("#{visibility}_methods").include?(method_name), "#{method_name} is not #{visibility}"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/mocha/debug.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | module Debug
3 | OPTIONS = (ENV['MOCHA_OPTIONS'] || '').split(',').freeze
4 |
5 | def self.puts(message)
6 | warn(message) if OPTIONS.include?('debug')
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/integration/minitest_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/minitest'
4 | require 'integration/shared_tests'
5 |
6 | class MinitestTest < Mocha::TestCase
7 | include SharedTests
8 | end
9 |
--------------------------------------------------------------------------------
/test/integration/test_unit_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/test_unit'
4 | require 'integration/shared_tests'
5 |
6 | class TestUnitTest < Mocha::TestCase
7 | include SharedTests
8 | end
9 |
--------------------------------------------------------------------------------
/lib/mocha/raised_exception.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class RaisedException
3 | def initialize(exception)
4 | @exception = exception
5 | end
6 |
7 | def mocha_inspect
8 | "raised #{@exception}"
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/mocha/not_initialized_error.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/error_with_filtered_backtrace'
2 |
3 | module Mocha
4 | # Exception raised when Mocha has not been initialized, e.g. outside the
5 | # context of a test.
6 | class NotInitializedError < ErrorWithFilteredBacktrace; end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/mocha/stubbing_error.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/error_with_filtered_backtrace'
2 |
3 | module Mocha
4 | # Exception raised when stubbing a particular method is not allowed.
5 | #
6 | # @see Configuration.prevent
7 | class StubbingError < ErrorWithFilteredBacktrace; end
8 | end
9 |
--------------------------------------------------------------------------------
/lib/mocha/thrown_object.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ThrownObject
3 | def initialize(tag, value = nil)
4 | @tag = tag
5 | @value = value
6 | end
7 |
8 | def mocha_inspect
9 | "threw (#{@tag.mocha_inspect}, #{@value.mocha_inspect})"
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/mocha/thrower.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class Thrower
3 | def initialize(tag, object = nil)
4 | @tag = tag
5 | @object = object
6 | end
7 |
8 | def evaluate(invocation)
9 | invocation.threw(@tag, @object)
10 | throw @tag, @object
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/mocha/single_return_value.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/is_a'
2 |
3 | module Mocha
4 | class SingleReturnValue
5 | def initialize(value)
6 | @value = value
7 | end
8 |
9 | def evaluate(invocation)
10 | invocation.returned(@value)
11 | @value
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/mocha/integration/assertion_counter.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | module Integration
3 | class AssertionCounter
4 | def initialize(test_case)
5 | @test_case = test_case
6 | end
7 |
8 | def increment
9 | @test_case.assert(true)
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/mocha/change_state_side_effect.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ChangeStateSideEffect
3 | def initialize(state)
4 | @state = state
5 | end
6 |
7 | def perform
8 | @state.activate
9 | end
10 |
11 | def mocha_inspect
12 | "then #{@state.mocha_inspect}"
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/unit/string_inspect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/inspect'
3 |
4 | class StringInspectTest < Mocha::TestCase
5 | def test_should_use_default_inspect_method
6 | string = 'my_string'
7 | assert_equal %("my_string"), string.mocha_inspect
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | * Pull requests are welcomed.
2 | * Fork the repository.
3 | * Make your changes in a branch.
4 | * Add/modify/remove tests as appropriate.
5 | * Open a pull request based on a branch on your fork.
6 | * Wait for your pull request build to pass on [Circle CI](https://app.circleci.com/pipelines/github/freerange/mocha).
7 | * Pull requests with failing tests will not be accepted.
8 |
--------------------------------------------------------------------------------
/lib/mocha/error_with_filtered_backtrace.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/backtrace_filter'
2 |
3 | module Mocha
4 | # @private
5 | class ErrorWithFilteredBacktrace < StandardError
6 | # @private
7 | def initialize(message = nil, backtrace = [])
8 | super(message)
9 | filter = BacktraceFilter.new
10 | set_backtrace(filter.filtered(backtrace))
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/mocha/in_state_ordering_constraint.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class InStateOrderingConstraint
3 | def initialize(state_predicate)
4 | @state_predicate = state_predicate
5 | end
6 |
7 | def allows_invocation_now?
8 | @state_predicate.active?
9 | end
10 |
11 | def mocha_inspect
12 | "when #{@state_predicate.mocha_inspect}"
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/deprecation_disabler.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/deprecation'
2 |
3 | module DeprecationDisabler
4 | def disable_deprecations
5 | original_mode = Mocha::Deprecation.mode
6 | Mocha::Deprecation.mode = :disabled
7 | begin
8 | yield
9 | ensure
10 | Mocha::Deprecation.mode = original_mode
11 | end
12 | end
13 |
14 | module_function :disable_deprecations
15 | end
16 |
--------------------------------------------------------------------------------
/lib/mocha/instance_method.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/stubbed_method'
2 |
3 | module Mocha
4 | class InstanceMethod < StubbedMethod
5 | private
6 |
7 | def mock_owner
8 | stubbee
9 | end
10 |
11 | def stubbee_method(method_name)
12 | stubbee._method(method_name)
13 | end
14 |
15 | def original_method_owner
16 | stubbee.singleton_class
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/mocha/expectation_error.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | # Default exception class raised when an unexpected invocation or an unsatisfied expectation occurs.
3 | #
4 | # Authors of test libraries may use +Mocha::ExpectationErrorFactory+ to have Mocha raise a different exception.
5 | #
6 | # @see Mocha::ExpectationErrorFactory
7 | class ExpectationError < Exception; end # rubocop:disable Lint/InheritException
8 | end
9 |
--------------------------------------------------------------------------------
/lib/mocha/any_instance_method.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/stubbed_method'
2 |
3 | module Mocha
4 | class AnyInstanceMethod < StubbedMethod
5 | private
6 |
7 | def mock_owner
8 | stubbee.any_instance
9 | end
10 |
11 | def stubbee_method(method_name)
12 | stubbee.instance_method(method_name)
13 | end
14 |
15 | def original_method_owner
16 | stubbee
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/mocha/argument_iterator.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ArgumentIterator
3 | def initialize(argument)
4 | @argument = argument
5 | end
6 |
7 | def each
8 | if @argument.is_a?(Hash)
9 | @argument.each do |method_name, return_value|
10 | yield method_name, return_value
11 | end
12 | else
13 | yield @argument
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/mocha/method_matcher.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class MethodMatcher
3 | attr_reader :expected_method_name
4 |
5 | def initialize(expected_method_name)
6 | @expected_method_name = expected_method_name
7 | end
8 |
9 | def match?(actual_method_name)
10 | @expected_method_name == actual_method_name.to_sym
11 | end
12 |
13 | def mocha_inspect
14 | @expected_method_name.to_s
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/mocha/backtrace_filter.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class BacktraceFilter
3 | LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..')) + File::SEPARATOR
4 |
5 | def initialize(lib_directory = LIB_DIRECTORY)
6 | @lib_directory = lib_directory
7 | end
8 |
9 | def filtered(backtrace)
10 | backtrace.reject { |location| File.expand_path(location).start_with?(@lib_directory) }
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/mocha/exception_raiser.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ExceptionRaiser
3 | def initialize(exception, message)
4 | @exception = exception
5 | @message = message
6 | end
7 |
8 | def evaluate(invocation)
9 | invocation.raised(@exception)
10 | raise @exception, @exception.to_s if @exception.is_a?(Module) && (@exception < Interrupt)
11 | raise @exception, @message if @message
12 | raise @exception
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/stub_matcher.rb:
--------------------------------------------------------------------------------
1 | module Stub
2 | class Matcher
3 | attr_accessor :value
4 |
5 | def initialize(matches)
6 | @matches = matches
7 | end
8 |
9 | def matches?(available_parameters)
10 | value = available_parameters.shift
11 | @value = value
12 | @matches
13 | end
14 |
15 | def mocha_inspect
16 | "matcher(#{@matches})"
17 | end
18 |
19 | def to_matcher
20 | self
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/mocha/integration/minitest/exception_translation.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/expectation_error'
2 |
3 | module Mocha
4 | module Integration
5 | module Minitest
6 | def self.translate(exception)
7 | return exception unless exception.is_a?(::Mocha::ExpectationError)
8 | translated_exception = ::Minitest::Assertion.new(exception.message)
9 | translated_exception.set_backtrace(exception.backtrace)
10 | translated_exception
11 | end
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/unit/single_return_value_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/invocation'
4 | require 'mocha/single_return_value'
5 |
6 | class SingleReturnValueTest < Mocha::TestCase
7 | include Mocha
8 |
9 | def new_invocation
10 | Invocation.new(:irrelevant, :irrelevant)
11 | end
12 |
13 | def test_should_return_value
14 | value = SingleReturnValue.new('value')
15 | assert_equal 'value', value.evaluate(new_invocation)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/unit/module_methods_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/object_methods'
3 |
4 | class ModuleMethodsTest < Mocha::TestCase
5 | def setup
6 | @module = Module.new.extend(Mocha::ObjectMethods)
7 | end
8 |
9 | def test_should_use_stubba_module_method_for_module
10 | assert_equal Mocha::InstanceMethod, @module.stubba_method
11 | end
12 |
13 | def test_should_stub_self_for_module
14 | assert_equal @module, @module.stubba_object
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/mocha/yield_parameters.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class YieldParameters
3 | def initialize
4 | @parameter_groups = []
5 | end
6 |
7 | def next_invocation
8 | case @parameter_groups.length
9 | when 0 then []
10 | when 1 then @parameter_groups.first
11 | else @parameter_groups.shift
12 | end
13 | end
14 |
15 | def add(*parameter_groups)
16 | @parameter_groups << parameter_groups.map do |pg|
17 | pg.is_a?(Array) ? pg : [pg]
18 | end
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/mocha/deprecation.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/backtrace_filter'
2 |
3 | module Mocha
4 | class Deprecation
5 | class << self
6 | attr_accessor :mode, :messages
7 |
8 | def warning(*messages)
9 | message = messages.join
10 | @messages << message
11 | return if mode == :disabled
12 | filter = BacktraceFilter.new
13 | location = filter.filtered(caller)[0]
14 | warn "Mocha deprecation warning at #{location}: #{message}"
15 | end
16 | end
17 |
18 | self.mode = :enabled
19 | self.messages = []
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/acceptance/bug_21563_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Bug21563Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_allow_stubbing_of_verified_method
15 | test_result = run_as_test do
16 | object = Object.new
17 | object.stubs(:verified?).returns(false)
18 | assert !object.verified?
19 | end
20 | assert_passed(test_result)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/test_unit_result.rb:
--------------------------------------------------------------------------------
1 | require 'test/unit/testresult'
2 |
3 | class TestUnitResult
4 | def self.build_test_result
5 | test_result = Test::Unit::TestResult.new
6 | class << test_result
7 | attr_reader :failures, :errors
8 | def failure_messages
9 | failures.map(&:message)
10 | end
11 |
12 | def failure_message_lines
13 | failure_messages.map { |message| message.split("\n") }.flatten
14 | end
15 |
16 | def error_messages
17 | errors.map(&:message)
18 | end
19 | end
20 | test_result
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/anything_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/anything'
4 | require 'mocha/inspect'
5 |
6 | class AnythingTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_anything
10 | matcher = anything
11 | assert matcher.matches?([:something])
12 | assert matcher.matches?([{ 'x' => 'y' }])
13 | end
14 |
15 | def test_should_describe_matcher
16 | matcher = anything
17 | assert_equal 'anything', matcher.mocha_inspect
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/test/method_definer.rb:
--------------------------------------------------------------------------------
1 | module MethodDefiner
2 | def define_instance_method(object, method_symbol, &block)
3 | object.singleton_class.send(:define_method, method_symbol, block)
4 | end
5 |
6 | def replace_instance_method(object, method_symbol, &block)
7 | raise "Cannot replace #{method_symbol} as #{self} does not respond to it." unless object.respond_to?(method_symbol)
8 | define_instance_method(object, method_symbol, &block)
9 | end
10 |
11 | def define_instance_accessor(object, *symbols)
12 | symbols.each { |symbol| object.singleton_class.send(:attr_accessor, symbol) }
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/mocha/detection/minitest.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | module Detection
3 | module Minitest
4 | def self.testcase
5 | if defined?(::Minitest::Test)
6 | ::Minitest::Test
7 | elsif defined?(::Minitest::Unit::TestCase)
8 | ::Minitest::Unit::TestCase
9 | end
10 | end
11 |
12 | def self.version
13 | if defined?(::Minitest::Unit::VERSION)
14 | ::Minitest::Unit::VERSION
15 | elsif defined?(::Minitest::VERSION)
16 | ::Minitest::VERSION
17 | else
18 | '0.0.0'
19 | end
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/unit/array_inspect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/inspect'
3 |
4 | class ArrayInspectTest < Mocha::TestCase
5 | def test_should_return_string_representation_of_array
6 | array = [1, 2]
7 | assert_equal '[1, 2]', array.mocha_inspect
8 | end
9 |
10 | def test_should_return_unwrapped_array_when_wrapped_is_false
11 | array = [1, 2]
12 | assert_equal '1, 2', array.mocha_inspect(false)
13 | end
14 |
15 | def test_should_use_mocha_inspect_on_each_item
16 | array = [1, 2, 'chris']
17 | assert_equal %([1, 2, "chris"]), array.mocha_inspect
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/mocha/block_matcher.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | module BlockMatchers
3 | class OptionalBlock
4 | def match?(_actual_block)
5 | true
6 | end
7 |
8 | def mocha_inspect; end
9 | end
10 |
11 | class BlockGiven
12 | def match?(actual_block)
13 | !actual_block.nil?
14 | end
15 |
16 | def mocha_inspect
17 | 'with block given'
18 | end
19 | end
20 |
21 | class NoBlockGiven
22 | def match?(actual_block)
23 | actual_block.nil?
24 | end
25 |
26 | def mocha_inspect
27 | 'with no block given'
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/docs/frames.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mocha 2.4.5
6 |
7 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/.yardopts:
--------------------------------------------------------------------------------
1 | --output-dir docs
2 | --no-private
3 | lib/mocha/api.rb
4 | lib/mocha/hooks.rb
5 | lib/mocha/mock.rb
6 | lib/mocha/expectation.rb
7 | lib/mocha/object_methods.rb
8 | lib/mocha/class_methods.rb
9 | lib/mocha/parameter_matchers.rb
10 | lib/mocha/parameter_matchers
11 | lib/mocha/state_machine.rb
12 | lib/mocha/sequence.rb
13 | lib/mocha/configuration.rb
14 | lib/mocha/expectation_error_factory.rb
15 | lib/mocha/expectation_error.rb
16 | lib/mocha/stubbing_error.rb
17 | lib/mocha/unexpected_invocation.rb
18 | lib/mocha/integration/test_unit/adapter.rb
19 | lib/mocha/integration/minitest/adapter.rb
20 | -
21 | RELEASE.md
22 | COPYING.md
23 | MIT-LICENSE.md
24 |
--------------------------------------------------------------------------------
/lib/mocha/return_values.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/single_return_value'
2 |
3 | module Mocha
4 | class ReturnValues
5 | def self.build(*values)
6 | new(*values.map { |value| SingleReturnValue.new(value) })
7 | end
8 |
9 | attr_accessor :values
10 |
11 | def initialize(*values)
12 | @values = values
13 | end
14 |
15 | def next(invocation)
16 | case @values.length
17 | when 0 then nil
18 | when 1 then @values.first.evaluate(invocation)
19 | else @values.shift.evaluate(invocation)
20 | end
21 | end
22 |
23 | def +(other)
24 | self.class.new(*(@values + other.values))
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/unit/date_time_inspect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/inspect'
3 |
4 | class DateTimeInspectTest < Mocha::TestCase
5 | def test_should_use_include_date_in_seconds
6 | time = Time.now
7 | assert_equal "#{time.inspect} (#{time.to_f} secs)", time.mocha_inspect
8 | end
9 |
10 | def test_should_use_to_s_for_date
11 | date = Date.new(2006, 1, 1)
12 | assert_equal date.to_s, date.mocha_inspect
13 | end
14 |
15 | def test_should_use_to_s_for_datetime
16 | datetime = DateTime.new(2006, 1, 1) # rubocop:disable Style/DateTime
17 | assert_equal datetime.to_s, datetime.mocha_inspect
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/equals_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/equals'
4 | require 'mocha/inspect'
5 |
6 | class EqualsTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_object_that_equals_value
10 | matcher = equals('x')
11 | assert matcher.matches?(['x'])
12 | end
13 |
14 | def test_should_not_match_object_that_does_not_equal_value
15 | matcher = equals('x')
16 | assert !matcher.matches?(['y'])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = equals('x')
21 | assert_equal %("x"), matcher.mocha_inspect
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/unit/thrower_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/invocation'
4 | require 'mocha/thrower'
5 |
6 | class ThrowerTest < Mocha::TestCase
7 | include Mocha
8 |
9 | def new_invocation
10 | Invocation.new(:irrelevant, :irrelevant)
11 | end
12 |
13 | def test_should_throw_tag
14 | thrower = Thrower.new(:tag)
15 | assert_throws(:tag) { thrower.evaluate(new_invocation) }
16 | end
17 |
18 | def test_should_throw_tag_with_return_value
19 | thrower = Thrower.new(:tag, 'return-value')
20 | return_value = catch(:tag) { thrower.evaluate(new_invocation) }
21 | assert_equal 'return-value', return_value
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
5 | # rubocop:disable Bundler/DuplicatedGem
6 | if RUBY_VERSION < '2.2'
7 | gem 'rake', '~> 12.3.3'
8 | else
9 | gem 'rake'
10 | end
11 | # rubocop:enable Bundler/DuplicatedGem
12 |
13 | gem 'introspection', '~> 0.0.1'
14 |
15 | # Avoid breaking change in psych v4 (https://bugs.ruby-lang.org/issues/17866)
16 | if RUBY_VERSION >= '3.1.0'
17 | gem 'psych', '< 4'
18 | end
19 |
20 | if RUBY_VERSION >= '2.2.0'
21 | # No test libraries in standard library
22 | gem 'minitest'
23 | end
24 | if RUBY_VERSION >= '2.2.0'
25 | gem 'rubocop', '<= 0.58.2'
26 | end
27 | if ENV['MOCHA_GENERATE_DOCS']
28 | gem 'redcarpet'
29 | gem 'yard'
30 | end
31 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/is_a_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/is_a'
4 | require 'mocha/inspect'
5 |
6 | class IsATest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_object_that_is_a_specified_class
10 | matcher = is_a(Integer)
11 | assert matcher.matches?([99])
12 | end
13 |
14 | def test_should_not_match_object_that_is_not_a_specified_class
15 | matcher = is_a(Integer)
16 | assert !matcher.matches?(['string'])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = is_a(Integer)
21 | assert_equal 'is_a(Integer)', matcher.mocha_inspect
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/kind_of_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/kind_of'
4 | require 'mocha/inspect'
5 |
6 | class KindOfTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_object_that_is_a_kind_of_specified_class
10 | matcher = kind_of(Integer)
11 | assert matcher.matches?([99])
12 | end
13 |
14 | def test_should_not_match_object_that_is_not_a_kind_of_specified_class
15 | matcher = kind_of(Integer)
16 | assert !matcher.matches?(['string'])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = kind_of(Integer)
21 | assert_equal 'kind_of(Integer)', matcher.mocha_inspect
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/acceptance/unexpected_invocation_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class UnexpectedInvocationTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_avoid_recursion_when_unexpected_invocation_exception_message_depends_on_uninspectable_object
15 | test_result = run_as_test do
16 | instance = Class.new.new
17 | instance.expects(:inspect).never
18 | instance.inspect(1, 2, 'foo')
19 | end
20 | assert_failed(test_result)
21 | assert_equal 'unexpected invocation: inspect(1, 2, foo)', test_result.failure_message_lines[0]
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/instance_of_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/instance_of'
4 | require 'mocha/inspect'
5 |
6 | class InstanceOfTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_object_that_is_an_instance_of_specified_class
10 | matcher = instance_of(String)
11 | assert matcher.matches?(['string'])
12 | end
13 |
14 | def test_should_not_match_object_that_is_not_an_instance_of_specified_class
15 | matcher = instance_of(String)
16 | assert !matcher.matches?([99])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = instance_of(String)
21 | assert_equal 'instance_of(String)', matcher.mocha_inspect
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/not_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/not'
4 | require 'mocha/inspect'
5 | require 'stub_matcher'
6 |
7 | class NotTest < Mocha::TestCase
8 | include Mocha::ParameterMatchers
9 |
10 | def test_should_match_if_matcher_does_not_match
11 | matcher = Not(Stub::Matcher.new(false))
12 | assert matcher.matches?(['any_old_value'])
13 | end
14 |
15 | def test_should_not_match_if_matcher_does_match
16 | matcher = Not(Stub::Matcher.new(true))
17 | assert !matcher.matches?(['any_old_value'])
18 | end
19 |
20 | def test_should_describe_matcher
21 | matcher = Not(Stub::Matcher.new(true))
22 | assert_equal 'Not(matcher(true))', matcher.mocha_inspect
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/acceptance/bug_21465_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Bug21465Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_allow_expected_method_name_to_be_a_string
15 | test_result = run_as_test do
16 | mock = mock()
17 | mock.expects('wibble')
18 | mock.wibble
19 | end
20 | assert_passed(test_result)
21 | end
22 |
23 | def test_should_allow_stubbed_method_name_to_be_a_string
24 | test_result = run_as_test do
25 | mock = mock()
26 | mock.stubs('wibble')
27 | mock.wibble
28 | end
29 | assert_passed(test_result)
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/instance_methods.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 | require 'mocha/parameter_matchers/equals'
3 | require 'mocha/parameter_matchers/positional_or_keyword_hash'
4 |
5 | module Mocha
6 | module ParameterMatchers
7 | # @private
8 | module InstanceMethods
9 | # @private
10 | def to_matcher(expectation: nil, top_level: false)
11 | if Base === self
12 | self
13 | elsif Hash === self && top_level
14 | Mocha::ParameterMatchers::PositionalOrKeywordHash.new(self, expectation)
15 | else
16 | Mocha::ParameterMatchers::Equals.new(self)
17 | end
18 | end
19 | end
20 | end
21 | end
22 |
23 | # @private
24 | class Object
25 | include Mocha::ParameterMatchers::InstanceMethods
26 | end
27 |
--------------------------------------------------------------------------------
/test/acceptance/issue_457_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Issue457Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_only_inspect_objects_when_necessary
15 | test_result = run_as_test do
16 | klass = Class.new do
17 | def message
18 | raise 'Not inspectable in this state!'
19 | end
20 |
21 | def inspect
22 | message
23 | end
24 | end
25 | instance = klass.new
26 | instance.stubs(:message).returns('message')
27 | assert_equal 'message', instance.inspect
28 | end
29 | assert_passed(test_result)
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/acceptance/array_flatten_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class ArrayFlattenTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_flattens_array_containing_mock_which_responds_like_active_record_model
15 | model = Class.new do
16 | # Ref: https://github.com/rails/rails/blob/7db044f38594eb43e1d241cc82025155666cc6f1/activerecord/lib/active_record/core.rb#L734-L745
17 | def to_ary
18 | nil
19 | end
20 | private :to_ary
21 | end.new
22 | test_result = run_as_test do
23 | m = mock.responds_like(model)
24 | assert_equal [m], [m].flatten
25 | end
26 | assert_passed(test_result)
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/mocha/integration/monkey_patcher.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/api'
2 |
3 | module Mocha
4 | module Integration
5 | module MonkeyPatcher
6 | def self.apply(mod, run_method_patch)
7 | if mod < Mocha::API
8 | Debug.puts "Mocha::API already included in #{mod}"
9 | else
10 | mod.send(:include, Mocha::API)
11 | end
12 | if mod.method_defined?(:run_before_mocha)
13 | Debug.puts "#{mod}#run_before_mocha method already defined"
14 | elsif mod.method_defined?(:run)
15 | mod.send(:alias_method, :run_before_mocha, :run)
16 | mod.send(:remove_method, :run)
17 | mod.send(:include, run_method_patch)
18 | else
19 | raise "Unable to monkey-patch #{mod}, because it does not define a `#run` method"
20 | end
21 | end
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/yaml_equivalent_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/yaml_equivalent'
4 | require 'mocha/inspect'
5 |
6 | class YamlEquivalentTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_parameter_matching_yaml_representation_of_object
10 | matcher = yaml_equivalent([1, 2, 3])
11 | assert matcher.matches?(["--- \n- 1\n- 2\n- 3\n"])
12 | end
13 |
14 | def test_should_not_match_parameter_matching_yaml_representation_of_object
15 | matcher = yaml_equivalent([1, 2, 3])
16 | assert !matcher.matches?(["--- \n- 4\n- 5\n"])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = yaml_equivalent([1, 2, 3])
21 | assert_equal 'yaml_equivalent([1, 2, 3])', matcher.mocha_inspect
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/mocha/detection/test_unit.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | module Detection
3 | module TestUnit
4 | def self.testcase
5 | if defined?(::Test::Unit::TestCase) &&
6 | !(defined?(::Minitest::Unit::TestCase) && (::Test::Unit::TestCase < ::Minitest::Unit::TestCase)) &&
7 | !(defined?(::Minitest::Spec) && (::Test::Unit::TestCase < ::Minitest::Spec))
8 | ::Test::Unit::TestCase
9 | end
10 | end
11 |
12 | def self.version
13 | version = '1.0.0'
14 | if testcase
15 | begin
16 | require 'test/unit/version'
17 | rescue LoadError # rubocop:disable Lint/HandleExceptions
18 | end
19 | if defined?(::Test::Unit::VERSION)
20 | version = ::Test::Unit::VERSION
21 | end
22 | end
23 | version
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/acceptance/bug_18914_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Bug18914Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | class AlwaysEql
15 | def my_method
16 | true
17 | end
18 |
19 | def ==(_other)
20 | true
21 | end
22 |
23 | def eql?(_other)
24 | true
25 | end
26 | end
27 |
28 | def test_should_not_allow_stubbing_of_non_mock_instance_disrupted_by_legitimate_overriding_of_eql_method
29 | always_eql1 = AlwaysEql.new
30 | always_eql1.stubs(:my_method).returns(false)
31 |
32 | always_eql2 = AlwaysEql.new
33 | always_eql2.stubs(:my_method).returns(false)
34 |
35 | assert_equal false, always_eql2.my_method
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/test/execution_point.rb:
--------------------------------------------------------------------------------
1 | class ExecutionPoint
2 | attr_reader :backtrace
3 |
4 | def self.current
5 | new(caller)
6 | end
7 |
8 | def initialize(backtrace)
9 | @backtrace = backtrace
10 | end
11 |
12 | def first_relevant_line_of_backtrace
13 | @backtrace && (@backtrace.reject { |l| %r{\Aorg/jruby/}.match(l) }.first || 'unknown:0')
14 | end
15 |
16 | def file_name
17 | /\A(.*?):\d+/.match(first_relevant_line_of_backtrace)[1]
18 | end
19 |
20 | def line_number
21 | Integer(/\A.*?:(\d+)/.match(first_relevant_line_of_backtrace)[1])
22 | end
23 |
24 | def ==(other)
25 | return false unless other.is_a?(ExecutionPoint)
26 | (file_name == other.file_name) && (line_number == other.line_number)
27 | end
28 |
29 | def to_s
30 | "file: #{file_name}; line: #{line_number}"
31 | end
32 |
33 | def inspect
34 | to_s
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/mocha/integration/minitest.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/debug'
2 | require 'mocha/detection/minitest'
3 | require 'mocha/integration/minitest/adapter'
4 |
5 | module Mocha
6 | module Integration
7 | module Minitest
8 | def self.activate
9 | target = Detection::Minitest.testcase
10 | return false unless target
11 |
12 | minitest_version = Gem::Version.new(Detection::Minitest.version)
13 | Debug.puts "Detected Minitest version: #{minitest_version}"
14 |
15 | unless Minitest::Adapter.applicable_to?(minitest_version)
16 | raise 'Versions of minitest earlier than v3.3.0 are not supported.'
17 | end
18 |
19 | unless target < Minitest::Adapter
20 | Debug.puts "Applying #{Minitest::Adapter.description}"
21 | target.send(:include, Minitest::Adapter)
22 | end
23 |
24 | true
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/mocha/integration/test_unit.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/debug'
2 | require 'mocha/detection/test_unit'
3 | require 'mocha/integration/test_unit/adapter'
4 |
5 | module Mocha
6 | module Integration
7 | module TestUnit
8 | def self.activate
9 | target = Detection::TestUnit.testcase
10 | return false unless target
11 |
12 | test_unit_version = Gem::Version.new(Detection::TestUnit.version)
13 | Debug.puts "Detected Test::Unit version: #{test_unit_version}"
14 |
15 | unless TestUnit::Adapter.applicable_to?(test_unit_version)
16 | raise 'Versions of test-unit earlier than v2.5.1 are not supported.'
17 | end
18 |
19 | unless target < TestUnit::Adapter
20 | Debug.puts "Applying #{TestUnit::Adapter.description}"
21 | target.send(:include, TestUnit::Adapter)
22 | end
23 |
24 | true
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/mocha/names.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ImpersonatingName
3 | def initialize(object)
4 | @object = object
5 | end
6 |
7 | def mocha_inspect
8 | @object.mocha_inspect
9 | end
10 | end
11 |
12 | class ImpersonatingAnyInstanceName
13 | def initialize(klass)
14 | @klass = klass
15 | end
16 |
17 | def mocha_inspect
18 | "#"
19 | end
20 | end
21 |
22 | class Name
23 | def initialize(name)
24 | @name = name.to_s
25 | end
26 |
27 | def mocha_inspect
28 | "#"
29 | end
30 | end
31 |
32 | class DefaultName
33 | def initialize(mock)
34 | @mock = mock
35 | end
36 |
37 | def mocha_inspect
38 | address = @mock.__id__ * 2
39 | address += 0x100000000 if address < 0
40 | "#x', address: address)}>"
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/acceptance/issue_524_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Issue524Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_expects_returns_last_expectation
15 | test_result = run_as_test do
16 | object = mock
17 | object.expects(method_1: 1, method_2: 2).twice
18 | object.method_1
19 | object.method_2
20 | object.method_2
21 | end
22 | assert_passed(test_result)
23 | end
24 |
25 | def test_stubs_returns_last_expectation
26 | test_result = run_as_test do
27 | object = mock
28 | object.stubs(method_1: 1, method_2: 2).twice
29 | object.method_1
30 | object.method_2
31 | object.method_2
32 | end
33 | assert_passed(test_result)
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/.rubocop_todo.yml:
--------------------------------------------------------------------------------
1 | # This configuration was generated by
2 | # `rubocop --auto-gen-config`
3 | # on 2019-11-16 18:15:36 +0000 using RuboCop version 0.58.2.
4 | # The point is for the user to remove these configuration records
5 | # one by one as the offenses are removed from the code base.
6 | # Note that changes in the inspected code, or installation of new
7 | # versions of RuboCop, may require this file to be generated again.
8 |
9 | # Offense count: 57
10 | Metrics/AbcSize:
11 | Max: 26
12 |
13 | # Offense count: 23
14 | # Configuration parameters: CountComments.
15 | Metrics/ClassLength:
16 | Max: 366
17 |
18 | # Offense count: 172
19 | # Configuration parameters: CountComments.
20 | Metrics/MethodLength:
21 | Max: 31
22 |
23 | # Offense count: 545
24 | # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
25 | # URISchemes: http, https
26 | Metrics/LineLength:
27 | Max: 180
28 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/anything.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any object.
6 | #
7 | # @return [Anything] parameter matcher.
8 | #
9 | # @see Expectation#with
10 | #
11 | # @example Any object will match.
12 | # object = mock()
13 | # object.expects(:method_1).with(anything)
14 | # object.method_1('foo')
15 | # object.method_1(789)
16 | # object.method_1(:bar)
17 | # # no error raised
18 | def anything
19 | Anything.new
20 | end
21 |
22 | # Parameter matcher which always matches a single parameter.
23 | class Anything < Base
24 | # @private
25 | def matches?(available_parameters)
26 | available_parameters.shift
27 | true
28 | end
29 |
30 | # @private
31 | def mocha_inspect
32 | 'anything'
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/unit/change_state_side_effect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/change_state_side_effect'
4 |
5 | class ChangeStateSideEffectTest < Mocha::TestCase
6 | include Mocha
7 |
8 | class FakeState
9 | attr_reader :active
10 | attr_writer :description
11 |
12 | def activate
13 | @active = true
14 | end
15 |
16 | def mocha_inspect
17 | @description
18 | end
19 | end
20 |
21 | def test_should_activate_the_given_state
22 | state = FakeState.new
23 | side_effect = ChangeStateSideEffect.new(state)
24 |
25 | side_effect.perform
26 |
27 | assert state.active
28 | end
29 |
30 | def test_should_describe_itself_in_terms_of_the_activated_state
31 | state = FakeState.new
32 | state.description = 'the-new-state'
33 | side_effect = ChangeStateSideEffect.new(state)
34 |
35 | assert_equal 'then the-new-state', side_effect.mocha_inspect
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/mocha/receivers.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ObjectReceiver
3 | def initialize(object)
4 | @object = object
5 | end
6 |
7 | def mocks
8 | object = @object
9 | mocks = []
10 | while object
11 | mocha = object.mocha(false)
12 | mocks << mocha if mocha
13 | object = object.is_a?(Class) ? object.superclass : nil
14 | end
15 | mocks
16 | end
17 | end
18 |
19 | class AnyInstanceReceiver
20 | def initialize(klass)
21 | @klass = klass
22 | end
23 |
24 | def mocks
25 | klass = @klass
26 | mocks = []
27 | while klass
28 | mocha = klass.any_instance.mocha(false)
29 | mocks << mocha if mocha
30 | klass = klass.superclass
31 | end
32 | mocks
33 | end
34 | end
35 |
36 | class DefaultReceiver
37 | def initialize(mock)
38 | @mock = mock
39 | end
40 |
41 | def mocks
42 | [@mock]
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class StubbingSameClassMethodOnParentAndChildClassTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_stubbing_same_method_on_parent_and_child_classes
15 | parent_class = Class.new do
16 | def self.foo
17 | 'Parent.foo'
18 | end
19 | end
20 | child_class = Class.new(parent_class)
21 | test_result = run_as_tests(
22 | test_1: lambda {
23 | parent_class.stubs(:foo).returns('stubbed Parent.foo')
24 | child_class.stubs(:foo).returns('stubbed Child.foo')
25 | },
26 | test_2: lambda {
27 | parent_class.foo
28 | child_class.foo
29 | }
30 | )
31 | assert_passed(test_result)
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/all_of_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/all_of'
4 | require 'mocha/inspect'
5 | require 'stub_matcher'
6 |
7 | class AllOfTest < Mocha::TestCase
8 | include Mocha::ParameterMatchers
9 |
10 | def test_should_match_if_all_matchers_match
11 | matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(true), Stub::Matcher.new(true))
12 | assert matcher.matches?(['any_old_value'])
13 | end
14 |
15 | def test_should_not_match_if_any_matcher_does_not_match
16 | matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(false), Stub::Matcher.new(true))
17 | assert !matcher.matches?(['any_old_value'])
18 | end
19 |
20 | def test_should_describe_matcher
21 | matcher = all_of(Stub::Matcher.new(true), Stub::Matcher.new(false), Stub::Matcher.new(true))
22 | assert_equal 'all_of(matcher(true), matcher(false), matcher(true))', matcher.mocha_inspect
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/any_of_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/any_of'
4 | require 'mocha/inspect'
5 | require 'stub_matcher'
6 |
7 | class AnyOfTest < Mocha::TestCase
8 | include Mocha::ParameterMatchers
9 |
10 | def test_should_match_if_any_matchers_match
11 | matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(true), Stub::Matcher.new(false))
12 | assert matcher.matches?(['any_old_value'])
13 | end
14 |
15 | def test_should_not_match_if_no_matchers_match
16 | matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(false), Stub::Matcher.new(false))
17 | assert !matcher.matches?(['any_old_value'])
18 | end
19 |
20 | def test_should_describe_matcher
21 | matcher = any_of(Stub::Matcher.new(false), Stub::Matcher.new(true), Stub::Matcher.new(false))
22 | assert_equal 'any_of(matcher(false), matcher(true), matcher(false))', matcher.mocha_inspect
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/mocha.gemspec:
--------------------------------------------------------------------------------
1 | lib = File.expand_path('../lib/', __FILE__)
2 | $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
3 | require 'mocha/version'
4 |
5 | Gem::Specification.new do |s|
6 | s.name = 'mocha'
7 | s.version = Mocha::VERSION
8 | s.licenses = ['MIT', 'BSD-2-Clause']
9 | s.required_ruby_version = '>= 2.1'
10 |
11 | s.authors = ['James Mead']
12 | s.description = 'Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes.'
13 | s.email = 'mocha-developer@googlegroups.com'
14 |
15 | s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
16 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(docs|test)/}) }
17 | end
18 | s.files.delete('.circleci/config.yml')
19 | s.files.delete('.gitignore')
20 |
21 | s.homepage = 'https://mocha.jamesmead.org'
22 | s.require_paths = ['lib']
23 | s.summary = 'Mocking and stubbing library'
24 |
25 | s.add_runtime_dependency 'ruby2_keywords', '>= 0.0.5'
26 | end
27 |
--------------------------------------------------------------------------------
/test/unit/hash_inspect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/inspect'
3 |
4 | class HashInspectTest < Mocha::TestCase
5 | def test_should_return_string_representation_of_hash
6 | hash = { a: true, b: false }
7 | assert_equal '{:a => true, :b => false}', hash.mocha_inspect
8 | end
9 |
10 | if Mocha::RUBY_V27_PLUS
11 | def test_should_return_unwrapped_keyword_style_hash_when_keyword_hash
12 | hash = Hash.ruby2_keywords_hash(a: true, b: false)
13 | assert_equal 'a: true, b: false', hash.mocha_inspect
14 | end
15 |
16 | def test_should_return_unwrapped_hash_when_keyword_hash_keys_are_not_symbols
17 | hash = Hash.ruby2_keywords_hash('a' => true, 'b' => false)
18 | assert_equal '"a" => true, "b" => false', hash.mocha_inspect
19 | end
20 | end
21 |
22 | def test_should_use_mocha_inspect_on_each_key_and_value
23 | hash = { a: 'mocha' }
24 | assert_equal %({:a => "mocha"}), hash.mocha_inspect
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/unit/hooks_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/hooks'
3 | require 'mocha/mockery'
4 |
5 | class HooksTest < Mocha::TestCase
6 | # rubocop:disable Style/ClassAndModuleChildren
7 | class Mocha::Mockery
8 | class << self
9 | attr_writer :instances
10 | end
11 | end
12 | # rubocop:enable Style/ClassAndModuleChildren
13 |
14 | class FakeMockery
15 | def verify(*args); end
16 |
17 | def teardown(_origin = nil)
18 | raise 'exception within Mockery#teardown'
19 | end
20 | end
21 |
22 | def test_ensure_mockery_instance_is_reset_even_when_an_exception_is_raised_in_mockery_teardown
23 | fake_test_case = Object.new.extend(Mocha::Hooks)
24 | mockery = FakeMockery.new
25 | Mocha::Mockery.instances = [mockery]
26 |
27 | begin
28 | fake_test_case.mocha_teardown
29 | rescue StandardError
30 | nil
31 | end
32 |
33 | assert_kind_of Mocha::Mockery::Null, Mocha::Mockery.instance
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/unit/method_matcher_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/method_matcher'
3 |
4 | class MethodMatcherTest < Mocha::TestCase
5 | include Mocha
6 |
7 | def test_should_match_if_actual_method_name_is_same_as_expected_method_name
8 | method_matcher = MethodMatcher.new(:method_name)
9 | assert method_matcher.match?(:method_name)
10 | end
11 |
12 | def test_should_match_if_actual_method_name_is_expected_method_name_as_string
13 | method_matcher = MethodMatcher.new(:method_name)
14 | assert method_matcher.match?('method_name')
15 | end
16 |
17 | def test_should_not_match_if_actual_method_name_is_not_same_as_expected_method_name
18 | method_matcher = MethodMatcher.new(:method_name)
19 | assert !method_matcher.match?(:different_method_name)
20 | end
21 |
22 | def test_should_describe_what_method_is_expected
23 | method_matcher = MethodMatcher.new(:method_name)
24 | assert_equal 'method_name', method_matcher.mocha_inspect
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/mocha/central.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class Central
3 | class Null < self
4 | def initialize(&block)
5 | super
6 | @raise_not_initialized_error = block
7 | end
8 |
9 | def stub(*)
10 | @raise_not_initialized_error.call
11 | end
12 |
13 | def unstub(*)
14 | @raise_not_initialized_error.call
15 | end
16 | end
17 |
18 | attr_accessor :stubba_methods
19 |
20 | def initialize
21 | self.stubba_methods = []
22 | end
23 |
24 | def stub(method)
25 | return if stubba_methods.detect { |m| m.matches?(method) }
26 | method.stub
27 | stubba_methods.push(method)
28 | end
29 |
30 | def unstub(method)
31 | return unless (existing = stubba_methods.detect { |m| m.matches?(method) })
32 | existing.unstub
33 | stubba_methods.delete(existing)
34 | end
35 |
36 | def unstub_all
37 | while stubba_methods.any?
38 | unstub(stubba_methods.first)
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/test/unit/backtrace_filter_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/backtrace_filter'
3 |
4 | class BacktraceFilterTest < Mocha::TestCase
5 | include Mocha
6 |
7 | def test_should_exclude_mocha_locations_from_backtrace
8 | mocha_lib = '/username/workspace/mocha_wibble/lib/'
9 | backtrace = [mocha_lib + 'exclude/me/1', mocha_lib + 'exclude/me/2', '/keep/me', mocha_lib + 'exclude/me/3']
10 | filter = BacktraceFilter.new(mocha_lib)
11 | assert_equal ['/keep/me'], filter.filtered(backtrace)
12 | end
13 |
14 | def test_should_determine_path_for_mocha_lib_directory
15 | assert_match Regexp.new('/lib/$'), BacktraceFilter::LIB_DIRECTORY
16 | end
17 |
18 | def test_should_handle_special_characters
19 | lib_directory = '/tmp/bundle/ruby/3.2.0+3/gems/mocha-2.0.2/lib/'
20 | filter = BacktraceFilter.new(lib_directory)
21 | backtrace = ['/keep/me', "#{lib_directory}mocha/deprecation.rb"]
22 | assert_equal ['/keep/me'], filter.filtered(backtrace)
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/acceptance/acceptance_test_helper.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'test_runner'
3 | require 'mocha/configuration'
4 | require 'mocha/mockery'
5 | require 'introspection'
6 |
7 | if Mocha::Detection::Minitest.testcase && (ENV['MOCHA_RUN_INTEGRATION_TESTS'] != 'test-unit')
8 | require 'mocha/minitest'
9 | else
10 | require 'mocha/test_unit'
11 | end
12 |
13 | module AcceptanceTest
14 | class FakeLogger
15 | attr_reader :warnings
16 |
17 | def initialize
18 | @warnings = []
19 | end
20 |
21 | def warn(message)
22 | @warnings << message
23 | end
24 | end
25 |
26 | attr_reader :logger
27 |
28 | include TestRunner
29 |
30 | def setup_acceptance_test
31 | Mocha::Configuration.reset_configuration
32 | @logger = FakeLogger.new
33 | mockery = Mocha::Mockery.instance
34 | mockery.logger = @logger
35 | end
36 |
37 | def teardown_acceptance_test
38 | Mocha::Configuration.reset_configuration
39 | end
40 |
41 | include Introspection::Assertions
42 | end
43 |
--------------------------------------------------------------------------------
/MIT-LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2006 James Mead
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/lib/mocha/parameters_matcher.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/inspect'
2 | require 'mocha/parameter_matchers'
3 |
4 | module Mocha
5 | class ParametersMatcher
6 | def initialize(expected_parameters = [ParameterMatchers::AnyParameters.new], expectation = nil, &matching_block)
7 | @expected_parameters = expected_parameters
8 | @expectation = expectation
9 | @matching_block = matching_block
10 | end
11 |
12 | def match?(actual_parameters = [])
13 | if @matching_block
14 | @matching_block.call(*actual_parameters)
15 | else
16 | parameters_match?(actual_parameters)
17 | end
18 | end
19 |
20 | def parameters_match?(actual_parameters)
21 | matchers.all? { |matcher| matcher.matches?(actual_parameters) } && actual_parameters.empty?
22 | end
23 |
24 | def mocha_inspect
25 | signature = matchers.mocha_inspect
26 | signature = signature.gsub(/^\[|\]$/, '')
27 | "(#{signature})"
28 | end
29 |
30 | def matchers
31 | @expected_parameters.map { |p| p.to_matcher(expectation: @expectation, top_level: true) }
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class StubMethodDefinedOnModuleAndAliasedTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_stubbing_class_method_defined_by_aliasing_module_instance_method
15 | mod = Module.new do
16 | def module_instance_method
17 | 'module-instance-method'
18 | end
19 | end
20 |
21 | klass = Class.new do
22 | extend mod
23 | class << self
24 | alias_method :aliased_module_instance_method, :module_instance_method
25 | end
26 | end
27 |
28 | assert_snapshot_unchanged(klass) do
29 | test_result = run_as_test do
30 | klass.stubs(:aliased_module_instance_method).returns('stubbed-aliased-module-instance-method')
31 | assert_equal 'stubbed-aliased-module-instance-method', klass.aliased_module_instance_method
32 | end
33 | assert_passed(test_result)
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/minitest_result.rb:
--------------------------------------------------------------------------------
1 | require 'forwardable'
2 |
3 | class MinitestResult
4 | class Failure
5 | extend Forwardable
6 | def_delegators :@failure, :message, :backtrace
7 |
8 | def initialize(failure)
9 | @failure = failure
10 | end
11 |
12 | def location
13 | Minitest.filter_backtrace(backtrace)
14 | end
15 | end
16 |
17 | def initialize(tests)
18 | @tests = tests
19 | end
20 |
21 | def failures
22 | @tests.map(&:failures).flatten.select { |r| r.instance_of?(Minitest::Assertion) }.map { |f| Failure.new(f) }
23 | end
24 |
25 | def failure_count
26 | failures.length
27 | end
28 |
29 | def failure_message_lines
30 | failures.map { |f| f.message.split("\n") }.flatten
31 | end
32 |
33 | def errors
34 | @tests.map(&:failures).flatten.select { |r| r.instance_of?(Minitest::UnexpectedError) }
35 | end
36 |
37 | def error_count
38 | errors.length
39 | end
40 |
41 | def error_messages
42 | errors.map { |e| e.message.split("\n") }.flatten
43 | end
44 |
45 | def assertion_count
46 | @tests.inject(0) { |total, test| total + test.assertions }
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/acceptance/throw_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class ThrowTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_throw_tag
15 | test_result = run_as_test do
16 | foo = stub('foo')
17 | foo.stubs(:bar).throws(:tag)
18 | assert_throws(:tag) { foo.bar }
19 | end
20 | assert_passed(test_result)
21 | end
22 |
23 | def test_should_throw_with_return_value
24 | test_result = run_as_test do
25 | foo = stub('foo')
26 | foo.stubs(:bar).throws(:tag, 'return-value')
27 | return_value = catch(:tag) { foo.bar }
28 | assert_equal 'return-value', return_value
29 | end
30 | assert_passed(test_result)
31 | end
32 |
33 | def test_should_throw_two_different_tags
34 | test_result = run_as_test do
35 | foo = stub('foo')
36 | foo.stubs(:bar).throws(:tag_one).then.throws(:tag_two)
37 | assert_throws(:tag_one) { foo.bar }
38 | assert_throws(:tag_two) { foo.bar }
39 | end
40 | assert_passed(test_result)
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/test/acceptance/raise_exception_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class RaiseExceptionTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_raise_exception
15 | exception_class = Class.new(StandardError)
16 | test_result = run_as_test do
17 | foo = stub('foo')
18 | foo.stubs(:bar).raises(exception_class, 'my-message')
19 | exception = assert_raises(exception_class) { foo.bar }
20 | assert_equal 'my-message', exception.message
21 | end
22 | assert_passed(test_result)
23 | end
24 |
25 | def test_should_raise_two_different_exceptions
26 | exception_one_class = Class.new(StandardError)
27 | exception_two_class = Class.new(StandardError)
28 | test_result = run_as_test do
29 | foo = stub('foo')
30 | foo.stubs(:bar).raises(exception_one_class).then.raises(exception_two_class)
31 | assert_raises(exception_one_class) { foo.bar }
32 | assert_raises(exception_two_class) { foo.bar }
33 | end
34 | assert_passed(test_result)
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/mocha/sequence.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | # Used to constrain the order in which expectations can occur.
3 | #
4 | # @see API#sequence
5 | # @see Expectation#in_sequence
6 | class Sequence
7 | # @private
8 | class InSequenceOrderingConstraint
9 | def initialize(sequence, index)
10 | @sequence = sequence
11 | @index = index
12 | end
13 |
14 | def allows_invocation_now?
15 | @sequence.satisfied_to_index?(@index)
16 | end
17 |
18 | def mocha_inspect
19 | "in sequence #{@sequence.mocha_inspect}"
20 | end
21 | end
22 |
23 | # @private
24 | def initialize(name)
25 | @name = name
26 | @expectations = []
27 | end
28 |
29 | # @private
30 | def constrain_as_next_in_sequence(expectation)
31 | index = @expectations.length
32 | @expectations << expectation
33 | expectation.add_ordering_constraint(InSequenceOrderingConstraint.new(self, index))
34 | end
35 |
36 | # @private
37 | def satisfied_to_index?(index)
38 | @expectations[0...index].all?(&:satisfied?)
39 | end
40 |
41 | # @private
42 | def mocha_inspect
43 | @name.mocha_inspect.to_s
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/any_parameters.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any parameters. This is used as the default for a newly built expectation.
6 | #
7 | # @return [AnyParameters] parameter matcher.
8 | #
9 | # @see Expectation#with
10 | #
11 | # @example Any parameters will match.
12 | # object = mock()
13 | # object.expects(:method_1).with(any_parameters)
14 | # object.method_1(1, 2, 3, 4)
15 | # # no error raised
16 | #
17 | # object = mock()
18 | # object.expects(:method_1).with(any_parameters)
19 | # object.method_1(5, 6, 7, 8, 9, 0)
20 | # # no error raised
21 | def any_parameters
22 | AnyParameters.new
23 | end
24 |
25 | # Parameter matcher which always matches whatever the parameters.
26 | class AnyParameters < Base
27 | # @private
28 | def matches?(available_parameters)
29 | until available_parameters.empty?
30 | available_parameters.shift
31 | end
32 | true
33 | end
34 |
35 | # @private
36 | def mocha_inspect
37 | 'any_parameters'
38 | end
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/test/unit/in_state_ordering_constraint_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 |
3 | require 'mocha/in_state_ordering_constraint'
4 |
5 | class InStateOrderingConstraintTest < Mocha::TestCase
6 | include Mocha
7 |
8 | class FakeStatePredicate
9 | attr_writer :active, :description
10 |
11 | def active?
12 | @active
13 | end
14 |
15 | def mocha_inspect
16 | @description
17 | end
18 | end
19 |
20 | def test_should_allow_invocation_when_state_is_active
21 | state_predicate = FakeStatePredicate.new
22 | ordering_constraint = InStateOrderingConstraint.new(state_predicate)
23 |
24 | state_predicate.active = true
25 | assert ordering_constraint.allows_invocation_now?
26 |
27 | state_predicate.active = false
28 | assert !ordering_constraint.allows_invocation_now?
29 | end
30 |
31 | def test_should_describe_itself_in_terms_of_the_state_predicates_description
32 | state_predicate = FakeStatePredicate.new
33 | ordering_constraint = InStateOrderingConstraint.new(state_predicate)
34 |
35 | state_predicate.description = 'the-state-predicate'
36 |
37 | assert_equal 'when the-state-predicate', ordering_constraint.mocha_inspect
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | # Used as parameters for {Expectation#with} to restrict the parameter values which will match the expectation. Can be nested.
3 | module ParameterMatchers; end
4 | end
5 |
6 | require 'mocha/parameter_matchers/instance_methods'
7 |
8 | require 'mocha/parameter_matchers/all_of'
9 | require 'mocha/parameter_matchers/any_of'
10 | require 'mocha/parameter_matchers/any_parameters'
11 | require 'mocha/parameter_matchers/anything'
12 | require 'mocha/parameter_matchers/equals'
13 | require 'mocha/parameter_matchers/has_entry'
14 | require 'mocha/parameter_matchers/has_entries'
15 | require 'mocha/parameter_matchers/has_key'
16 | require 'mocha/parameter_matchers/has_keys'
17 | require 'mocha/parameter_matchers/has_value'
18 | require 'mocha/parameter_matchers/includes'
19 | require 'mocha/parameter_matchers/instance_of'
20 | require 'mocha/parameter_matchers/is_a'
21 | require 'mocha/parameter_matchers/kind_of'
22 | require 'mocha/parameter_matchers/not'
23 | require 'mocha/parameter_matchers/optionally'
24 | require 'mocha/parameter_matchers/regexp_matches'
25 | require 'mocha/parameter_matchers/responds_with'
26 | require 'mocha/parameter_matchers/yaml_equivalent'
27 | require 'mocha/parameter_matchers/equivalent_uri'
28 |
--------------------------------------------------------------------------------
/test/acceptance/partial_mocks_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class PartialMockTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_pass_if_all_expectations_are_satisfied
15 | test_result = run_as_test do
16 | partial_mock_one = 'partial_mock_one'
17 | partial_mock_two = 'partial_mock_two'
18 |
19 | partial_mock_one.expects(:first)
20 | partial_mock_one.expects(:second)
21 | partial_mock_two.expects(:third)
22 |
23 | partial_mock_one.first
24 | partial_mock_one.second
25 | partial_mock_two.third
26 | end
27 | assert_passed(test_result)
28 | end
29 |
30 | def test_should_fail_if_all_expectations_are_not_satisfied
31 | test_result = run_as_test do
32 | partial_mock_one = 'partial_mock_one'
33 | partial_mock_two = 'partial_mock_two'
34 |
35 | partial_mock_one.expects(:first)
36 | partial_mock_one.expects(:second)
37 | partial_mock_two.expects(:third)
38 |
39 | partial_mock_one.first
40 | partial_mock_two.third
41 | end
42 | assert_failed(test_result)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/test/acceptance/issue_272_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Issue272Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | module Mod
15 | private
16 |
17 | def foo
18 | 'original-foo'
19 | end
20 |
21 | def bar
22 | 'original-bar'
23 | end
24 | end
25 |
26 | class Klass
27 | extend Mod
28 |
29 | class << self
30 | public :foo
31 | public :bar
32 | end
33 | end
34 |
35 | def test_private_methods_in_module_used_to_extend_class_and_made_public
36 | test_result = run_as_test do
37 | Klass.stubs(:foo).returns('stubbed-foo')
38 | # hangs in next line executing:
39 | # `@original_method = stubbee._method(method)`
40 | # in Mocha::StubbedMethod#hide_original_method
41 | # but only in Ruby v2.3, not v2.2
42 | Klass.stubs(:bar).returns('stubbed-bar')
43 | assert_equal 'stubbed-foo', Klass.foo
44 | assert_equal 'stubbed-bar', Klass.bar
45 | end
46 | assert_passed(test_result)
47 | assert_equal 'original-foo', Klass.foo
48 | assert_equal 'original-bar', Klass.bar
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/test/acceptance/stub_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class StubTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_build_stub_and_explicitly_add_an_expectation
15 | test_result = run_as_test do
16 | foo = stub
17 | foo.stubs(:bar)
18 | foo.bar
19 | end
20 | assert_passed(test_result)
21 | end
22 |
23 | def test_should_build_named_stub_and_explicitly_add_an_expectation
24 | test_result = run_as_test do
25 | foo = stub('foo')
26 | foo.stubs(:bar)
27 | foo.bar
28 | end
29 | assert_passed(test_result)
30 | end
31 |
32 | def test_should_build_stub_incorporating_two_expectations
33 | test_result = run_as_test do
34 | foo = stub(bar: 'bar', baz: 'baz')
35 | foo.bar
36 | foo.baz
37 | end
38 | assert_passed(test_result)
39 | end
40 |
41 | def test_should_build_named_stub_incorporating_two_expectations
42 | test_result = run_as_test do
43 | foo = stub('foo', bar: 'bar', baz: 'baz')
44 | foo.bar
45 | foo.baz
46 | end
47 | assert_passed(test_result)
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/test/acceptance/exception_rescue_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class ExceptionRescueTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_unexpected_invocation_exception_is_not_caught_by_standard_rescue
15 | test_result = run_as_test do
16 | mock = mock('mock')
17 | begin
18 | mock.some_method
19 | rescue StandardError => e
20 | flunk "should not rescue #{e.class}"
21 | end
22 | end
23 | assert_failed(test_result)
24 | assert_equal 'unexpected invocation: #.some_method()', test_result.failure_message_lines[0]
25 | end
26 |
27 | def test_invocation_never_expected_exception_is_not_caught_by_standard_rescue
28 | test_result = run_as_test do
29 | mock = mock('mock')
30 | mock.expects(:some_method).never
31 | begin
32 | mock.some_method
33 | rescue StandardError => e
34 | flunk "should not rescue #{e.class}"
35 | end
36 | end
37 | assert_failed(test_result)
38 | assert_equal 'unexpected invocation: #.some_method()', test_result.failure_message_lines[0]
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/equals.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any +Object+ equalling +value+.
6 | #
7 | # @param [Object] value expected value.
8 | # @return [Equals] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | # @see Object#==
12 | #
13 | # @example Actual parameter equals expected parameter.
14 | # object = mock()
15 | # object.expects(:method_1).with(equals(2))
16 | # object.method_1(2)
17 | # # no error raised
18 | #
19 | # @example Actual parameter does not equal expected parameter.
20 | # object = mock()
21 | # object.expects(:method_1).with(equals(2))
22 | # object.method_1(3)
23 | # # error raised, because method_1 was not called with an +Object+ that equals 2
24 | def equals(value)
25 | Equals.new(value)
26 | end
27 |
28 | # Parameter matcher which matches when actual parameter equals expected value.
29 | class Equals < Base
30 | # @private
31 | def initialize(value)
32 | @value = value
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | parameter == @value
39 | end
40 |
41 | # @private
42 | def mocha_inspect
43 | @value.mocha_inspect
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/is_a.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any object that is a +klass+.
6 | #
7 | # @param [Class] klass expected class.
8 | # @return [IsA] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | # @see Kernel#is_a?
12 | #
13 | # @example Actual parameter is a +Integer+.
14 | # object = mock()
15 | # object.expects(:method_1).with(is_a(Integer))
16 | # object.method_1(99)
17 | # # no error raised
18 | #
19 | # @example Actual parameter is not a +Integer+.
20 | # object = mock()
21 | # object.expects(:method_1).with(is_a(Integer))
22 | # object.method_1('string')
23 | # # error raised, because method_1 was not called with an Integer
24 | #
25 | def is_a(klass) # rubocop:disable Naming/PredicateName
26 | IsA.new(klass)
27 | end
28 |
29 | # Parameter matcher which matches when actual parameter is a specific class.
30 | class IsA < Base
31 | # @private
32 | def initialize(klass)
33 | @klass = klass
34 | end
35 |
36 | # @private
37 | def matches?(available_parameters)
38 | parameter = available_parameters.shift
39 | parameter.is_a?(@klass)
40 | end
41 |
42 | # @private
43 | def mocha_inspect
44 | "is_a(#{@klass.mocha_inspect})"
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/acceptance/stub_everything_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class StubEverythingTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_build_stub_and_explicitly_add_an_expectation
15 | test_result = run_as_test do
16 | foo = stub_everything
17 | foo.stubs(:bar)
18 | foo.bar
19 | foo.unexpected_invocation
20 | end
21 | assert_passed(test_result)
22 | end
23 |
24 | def test_should_build_named_stub_and_explicitly_add_an_expectation
25 | test_result = run_as_test do
26 | foo = stub_everything('foo')
27 | foo.stubs(:bar)
28 | foo.bar
29 | foo.unexpected_invocation
30 | end
31 | assert_passed(test_result)
32 | end
33 |
34 | def test_should_build_stub_incorporating_two_expectations
35 | test_result = run_as_test do
36 | foo = stub_everything(bar: 'bar', baz: 'baz')
37 | foo.bar
38 | foo.baz
39 | foo.unexpected_invocation
40 | end
41 | assert_passed(test_result)
42 | end
43 |
44 | def test_should_build_named_stub_incorporating_two_expectations
45 | test_result = run_as_test do
46 | foo = stub_everything('foo', bar: 'bar', baz: 'baz')
47 | foo.bar
48 | foo.baz
49 | foo.unexpected_invocation
50 | end
51 | assert_passed(test_result)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/test/acceptance/return_value_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class ReturnValueTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_build_mock_and_explicitly_add_an_expectation_with_a_return_value
15 | test_result = run_as_test do
16 | foo = mock('foo')
17 | foo.expects(:bar).returns('bar')
18 | assert_equal 'bar', foo.bar
19 | end
20 | assert_passed(test_result)
21 | end
22 |
23 | def test_should_build_mock_incorporating_two_expectations_with_return_values
24 | test_result = run_as_test do
25 | foo = mock('foo', bar: 'bar', baz: 'baz')
26 | assert_equal 'bar', foo.bar
27 | assert_equal 'baz', foo.baz
28 | end
29 | assert_passed(test_result)
30 | end
31 |
32 | def test_should_build_stub_and_explicitly_add_an_expectation_with_a_return_value
33 | test_result = run_as_test do
34 | foo = stub('foo')
35 | foo.stubs(:bar).returns('bar')
36 | assert_equal 'bar', foo.bar
37 | end
38 | assert_passed(test_result)
39 | end
40 |
41 | def test_should_build_stub_incorporating_two_expectations_with_return_values
42 | test_result = run_as_test do
43 | foo = stub('foo', bar: 'bar', baz: 'baz')
44 | assert_equal 'bar', foo.bar
45 | assert_equal 'baz', foo.baz
46 | end
47 | assert_passed(test_result)
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/not.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches if +matcher+ does *not* match.
6 | #
7 | # @param [Base] matcher matcher whose logic to invert.
8 | # @return [Not] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example Actual parameter does not include the value +1+.
13 | # object = mock()
14 | # object.expects(:method_1).with(Not(includes(1)))
15 | # object.method_1([0, 2, 3])
16 | # # no error raised
17 | #
18 | # @example Actual parameter does include the value +1+.
19 | # object = mock()
20 | # object.expects(:method_1).with(Not(includes(1)))
21 | # object.method_1([0, 1, 2, 3])
22 | # # error raised, because method_1 was not called with object not including 1
23 | #
24 | def Not(matcher) # rubocop:disable Naming/MethodName
25 | Not.new(matcher)
26 | end
27 |
28 | # Parameter matcher which inverts the logic of the specified matcher using a logical NOT operation.
29 | class Not < Base
30 | # @private
31 | def initialize(matcher)
32 | @matcher = matcher
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | !@matcher.matches?([parameter])
39 | end
40 |
41 | # @private
42 | def mocha_inspect
43 | "Not(#{@matcher.mocha_inspect})"
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/instance_of.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any object that is an instance of +klass+
6 | #
7 | # @param [Class] klass expected class.
8 | # @return [InstanceOf] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | # @see Kernel#instance_of?
12 | #
13 | # @example Actual parameter is an instance of +String+.
14 | # object = mock()
15 | # object.expects(:method_1).with(instance_of(String))
16 | # object.method_1('string')
17 | # # no error raised
18 | #
19 | # @example Actual parameter is not an instance of +String+.
20 | # object = mock()
21 | # object.expects(:method_1).with(instance_of(String))
22 | # object.method_1(99)
23 | # # error raised, because method_1 was not called with an instance of String
24 | def instance_of(klass)
25 | InstanceOf.new(klass)
26 | end
27 |
28 | # Parameter matcher which matches when actual parameter is an instance of the specified class.
29 | class InstanceOf < Base
30 | # @private
31 | def initialize(klass)
32 | @klass = klass
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | parameter.instance_of?(@klass)
39 | end
40 |
41 | # @private
42 | def mocha_inspect
43 | "instance_of(#{@klass.mocha_inspect})"
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/all_of.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches if all +matchers+ match.
6 | #
7 | # @param [*Array] matchers parameter matchers.
8 | # @return [AllOf] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example All parameter matchers match.
13 | # object = mock()
14 | # object.expects(:method_1).with(all_of(includes(1), includes(3)))
15 | # object.method_1([1, 3])
16 | # # no error raised
17 | #
18 | # @example One of the parameter matchers does not match.
19 | # object = mock()
20 | # object.expects(:method_1).with(all_of(includes(1), includes(3)))
21 | # object.method_1([1, 2])
22 | # # error raised, because method_1 was not called with object including 1 and 3
23 | def all_of(*matchers)
24 | AllOf.new(*matchers)
25 | end
26 |
27 | # Parameter matcher which combines a number of other matchers using a logical AND.
28 | class AllOf < Base
29 | # @private
30 | def initialize(*matchers)
31 | @matchers = matchers
32 | end
33 |
34 | # @private
35 | def matches?(available_parameters)
36 | parameter = available_parameters.shift
37 | @matchers.all? { |matcher| matcher.to_matcher.matches?([parameter]) }
38 | end
39 |
40 | # @private
41 | def mocha_inspect
42 | "all_of(#{@matchers.map(&:mocha_inspect).join(', ')})"
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/kind_of.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any +Object+ that is a kind of +klass+.
6 | #
7 | # @param [Class] klass expected class.
8 | # @return [KindOf] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | # @see Kernel#kind_of?
12 | #
13 | # @example Actual parameter is a kind of +Integer+.
14 | # object = mock()
15 | # object.expects(:method_1).with(kind_of(Integer))
16 | # object.method_1(99)
17 | # # no error raised
18 | #
19 | # @example Actual parameter is not a kind of +Integer+.
20 | # object = mock()
21 | # object.expects(:method_1).with(kind_of(Integer))
22 | # object.method_1('string')
23 | # # error raised, because method_1 was not called with a kind of Integer
24 | def kind_of(klass)
25 | KindOf.new(klass)
26 | end
27 |
28 | # Parameter matcher which matches when actual parameter is a kind of specified class.
29 | class KindOf < Base
30 | # @private
31 | def initialize(klass)
32 | @klass = klass
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | # rubocop:disable Style/ClassCheck
39 | parameter.kind_of?(@klass)
40 | # rubocop:enable Style/ClassCheck
41 | end
42 |
43 | # @private
44 | def mocha_inspect
45 | "kind_of(#{@klass.mocha_inspect})"
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/test/acceptance/issue_70_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Issue70Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_stub_expectations_instance_method
15 | instance = Class.new do
16 | def expectations
17 | :original_return_value
18 | end
19 | end.new
20 | test_result = run_as_test do
21 | instance.stubs(:expectations).returns(:stubbed_return_value)
22 | assert_equal :stubbed_return_value, instance.expectations
23 | end
24 | assert_passed(test_result)
25 | end
26 |
27 | def test_should_stub_expectations_class_method
28 | klass = Class.new do
29 | def self.expectations
30 | :original_return_value
31 | end
32 | end
33 | test_result = run_as_test do
34 | klass.stubs(:expectations).returns(:stubbed_return_value)
35 | assert_equal :stubbed_return_value, klass.expectations
36 | end
37 | assert_passed(test_result)
38 | end
39 |
40 | def test_should_stub_expectations_any_instance_method
41 | klass = Class.new do
42 | def expectations
43 | :original_return_value
44 | end
45 | end
46 | instance = klass.new
47 | test_result = run_as_test do
48 | klass.any_instance.stubs(:expectations).returns(:stubbed_return_value)
49 | assert_equal :stubbed_return_value, instance.expectations
50 | end
51 | assert_passed(test_result)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/mocha/expectation_error_factory.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/backtrace_filter'
2 | require 'mocha/expectation_error'
3 |
4 | module Mocha
5 | # This factory determines what class of exception should be raised when Mocha detects a test failure.
6 | #
7 | # This class should only be used by authors of test libraries and not by typical "users" of Mocha.
8 | #
9 | # For example, it is used by +Mocha::Integration::Minitest::Adapter+ in order to have Mocha raise a +Minitest::Assertion+ which can then be sensibly handled by +Minitest::Unit::TestCase+.
10 | #
11 | # @see Mocha::Integration::Minitest::Adapter
12 | class ExpectationErrorFactory
13 | class << self
14 | # @!attribute exception_class
15 | # Determines what class of exception should be raised when Mocha detects a test failure.
16 | #
17 | # This attribute may be set by authors of test libraries in order to have Mocha raise exceptions of a specific class when there is an unexpected invocation or an unsatisfied expectation.
18 | #
19 | # By default a +Mocha::ExpectationError+ will be raised.
20 | #
21 | # @return [Exception] class of exception to be raised when an expectation error occurs
22 | # @see Mocha::ExpectationError
23 | attr_accessor :exception_class
24 |
25 | # @private
26 | def build(message = nil, backtrace = [])
27 | exception = exception_class.new(message)
28 | filter = BacktraceFilter.new
29 | exception.set_backtrace(filter.filtered(backtrace))
30 | exception
31 | end
32 | end
33 | self.exception_class = ExpectationError
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/has_key.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches +Hash+ containing +key+.
6 | #
7 | # @param [Object] key expected key.
8 | # @return [HasKey] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example Actual parameter contains entry with expected key.
13 | # object = mock()
14 | # object.expects(:method_1).with(has_key('key_1'))
15 | # object.method_1('key_1' => 1, 'key_2' => 2)
16 | # # no error raised
17 | #
18 | # @example Actual parameter does not contain entry with expected key.
19 | # object = mock()
20 | # object.expects(:method_1).with(has_key('key_1'))
21 | # object.method_1('key_2' => 2)
22 | # # error raised, because method_1 was not called with Hash containing key: 'key_1'
23 | #
24 | def has_key(key) # rubocop:disable Naming/PredicateName
25 | HasKey.new(key)
26 | end
27 |
28 | # Parameter matcher which matches when actual parameter contains +Hash+ entry with expected key.
29 | class HasKey < Base
30 | # @private
31 | def initialize(key)
32 | @key = key
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | return false unless parameter.respond_to?(:keys)
39 | parameter.keys.any? { |key| @key.to_matcher.matches?([key]) }
40 | end
41 |
42 | # @private
43 | def mocha_inspect
44 | "has_key(#{@key.mocha_inspect})"
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/regexp_matches.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches any object that matches +regexp+.
6 | #
7 | # @param [Regexp] regexp regular expression to match.
8 | # @return [RegexpMatches] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example Actual parameter is matched by specified regular expression.
13 | # object = mock()
14 | # object.expects(:method_1).with(regexp_matches(/e/))
15 | # object.method_1('hello')
16 | # # no error raised
17 | #
18 | # @example Actual parameter is not matched by specified regular expression.
19 | # object = mock()
20 | # object.expects(:method_1).with(regexp_matches(/a/))
21 | # object.method_1('hello')
22 | # # error raised, because method_1 was not called with a parameter that matched the
23 | # # regular expression
24 | def regexp_matches(regexp)
25 | RegexpMatches.new(regexp)
26 | end
27 |
28 | # Parameter matcher which matches if specified regular expression matches actual paramter.
29 | class RegexpMatches < Base
30 | # @private
31 | def initialize(regexp)
32 | @regexp = regexp
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | return false unless parameter.respond_to?(:=~)
39 | parameter =~ @regexp
40 | end
41 |
42 | # @private
43 | def mocha_inspect
44 | "regexp_matches(#{@regexp.mocha_inspect})"
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/has_value.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches +Hash+ containing +value+.
6 | #
7 | # @param [Object] value expected value.
8 | # @return [HasValue] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example Actual parameter contains entry with expected value.
13 | # object = mock()
14 | # object.expects(:method_1).with(has_value(1))
15 | # object.method_1('key_1' => 1, 'key_2' => 2)
16 | # # no error raised
17 | #
18 | # @example Actual parameter does not contain entry with expected value.
19 | # object = mock()
20 | # object.expects(:method_1).with(has_value(1))
21 | # object.method_1('key_2' => 2)
22 | # # error raised, because method_1 was not called with Hash containing value: 1
23 | #
24 | def has_value(value) # rubocop:disable Naming/PredicateName
25 | HasValue.new(value)
26 | end
27 |
28 | # Parameter matcher which matches when actual parameter contains +Hash+ entry with expected value.
29 | class HasValue < Base
30 | # @private
31 | def initialize(value)
32 | @value = value
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | return false unless parameter.respond_to?(:values)
39 | parameter.values.any? { |value| @value.to_matcher.matches?([value]) }
40 | end
41 |
42 | # @private
43 | def mocha_inspect
44 | "has_value(#{@value.mocha_inspect})"
45 | end
46 | end
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/acceptance/issue_65_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class Issue65Test < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_expectations_on_class_methods_on_same_class_should_be_verified_in_consecutive_tests
15 | klass = Class.new do
16 | def self.foo; end
17 |
18 | def self.bar; end
19 | end
20 | test1 = run_as_test do
21 | klass.expects(:foo)
22 | klass.foo
23 | end
24 | assert_passed(test1)
25 | test2 = run_as_test do
26 | klass.expects(:bar)
27 | end
28 | assert_failed(test2)
29 | end
30 |
31 | def test_expectations_on_any_instance_methods_on_same_class_should_be_verified_in_consecutive_tests
32 | klass = Class.new do
33 | def foo; end
34 |
35 | def bar; end
36 | end
37 | test1 = run_as_test do
38 | klass.any_instance.expects(:foo)
39 | klass.new.foo
40 | end
41 | assert_passed(test1)
42 | test2 = run_as_test do
43 | klass.any_instance.expects(:bar)
44 | end
45 | assert_failed(test2)
46 | end
47 |
48 | def test_expectations_on_instance_methods_on_same_object_should_be_verified_in_consecutive_tests
49 | instance = Class.new do
50 | def foo; end
51 |
52 | def bar; end
53 | end.new
54 | test1 = run_as_test do
55 | instance.expects(:foo)
56 | instance.foo
57 | end
58 | assert_passed(test1)
59 | test2 = run_as_test do
60 | instance.expects(:bar)
61 | end
62 | assert_failed(test2)
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/regexp_matches_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/regexp_matches'
4 | require 'mocha/inspect'
5 |
6 | class RegexpMatchesTest < Mocha::TestCase
7 | include Mocha::ParameterMatchers
8 |
9 | def test_should_match_parameter_matching_regular_expression
10 | matcher = regexp_matches(/oo/)
11 | assert matcher.matches?(['foo'])
12 | end
13 |
14 | def test_should_not_match_parameter_not_matching_regular_expression
15 | matcher = regexp_matches(/oo/)
16 | assert !matcher.matches?(['bar'])
17 | end
18 |
19 | def test_should_describe_matcher
20 | matcher = regexp_matches(/oo/)
21 | assert_equal 'regexp_matches(/oo/)', matcher.mocha_inspect
22 | end
23 |
24 | def test_should_not_raise_error_on_empty_arguments
25 | matcher = regexp_matches(/oo/)
26 | assert_nothing_raised { matcher.matches?([]) }
27 | end
28 |
29 | def test_should_not_match_on_empty_arguments
30 | matcher = regexp_matches(/oo/)
31 | assert !matcher.matches?([])
32 | end
33 |
34 | def test_should_not_raise_error_on_argument_that_does_not_respond_to_equals_tilde
35 | matcher = regexp_matches(/oo/)
36 | assert_nothing_raised { matcher.matches?([object_not_responding_to_equals_tilde]) }
37 | end
38 |
39 | def test_should_not_match_on_argument_that_does_not_respond_to_equals_tilde
40 | matcher = regexp_matches(/oo/)
41 | assert !matcher.matches?([object_not_responding_to_equals_tilde])
42 | end
43 |
44 | private
45 |
46 | def object_not_responding_to_equals_tilde
47 | Class.new { undef =~ if respond_to?(:=~) }.new
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/mocha/integration/test_unit/adapter.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/api'
2 | require 'mocha/integration/assertion_counter'
3 | require 'mocha/expectation_error'
4 |
5 | module Mocha
6 | module Integration
7 | module TestUnit
8 | # Integrates Mocha into recent versions of Test::Unit.
9 | #
10 | # See the source code for an example of how to integrate Mocha into a test library.
11 | module Adapter
12 | include Mocha::API
13 |
14 | # @private
15 | def self.applicable_to?(test_unit_version)
16 | Gem::Requirement.new('>= 2.5.1').satisfied_by?(test_unit_version)
17 | end
18 |
19 | # @private
20 | def self.description
21 | 'adapter for Test::Unit gem >= v2.5.1'
22 | end
23 |
24 | # @private
25 | def self.included(mod)
26 | mod.setup :mocha_setup, before: :prepend
27 |
28 | mod.exception_handler(:handle_mocha_expectation_error)
29 |
30 | mod.cleanup after: :append do
31 | assertion_counter = Integration::AssertionCounter.new(self)
32 | mocha_verify(assertion_counter)
33 | end
34 |
35 | mod.teardown :mocha_teardown, after: :append
36 | end
37 |
38 | private
39 |
40 | # @private
41 | def mocha_test_name
42 | name
43 | end
44 |
45 | # @private
46 | def handle_mocha_expectation_error(exception)
47 | return false unless exception.is_a?(Mocha::ExpectationError)
48 | problem_occurred
49 | add_failure(exception.message, exception.backtrace)
50 | true
51 | end
52 | end
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/any_of.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches if any +matchers+ match.
6 | #
7 | # @param [*Array] matchers parameter matchers.
8 | # @return [AnyOf] parameter matcher.
9 | #
10 | # @see Expectation#with
11 | #
12 | # @example One parameter matcher matches.
13 | # object = mock()
14 | # object.expects(:method_1).with(any_of(1, 3))
15 | # object.method_1(1)
16 | # # no error raised
17 | #
18 | # @example The other parameter matcher matches.
19 | # object = mock()
20 | # object.expects(:method_1).with(any_of(1, 3))
21 | # object.method_1(3)
22 | # # no error raised
23 | #
24 | # @example Neither parameter matcher matches.
25 | # object = mock()
26 | # object.expects(:method_1).with(any_of(1, 3))
27 | # object.method_1(2)
28 | # # error raised, because method_1 was not called with 1 or 3
29 | def any_of(*matchers)
30 | AnyOf.new(*matchers)
31 | end
32 |
33 | # Parameter matcher which combines a number of other matchers using a logical OR.
34 | class AnyOf < Base
35 | # @private
36 | def initialize(*matchers)
37 | @matchers = matchers
38 | end
39 |
40 | # @private
41 | def matches?(available_parameters)
42 | parameter = available_parameters.shift
43 | @matchers.any? { |matcher| matcher.to_matcher.matches?([parameter]) }
44 | end
45 |
46 | # @private
47 | def mocha_inspect
48 | "any_of(#{@matchers.map(&:mocha_inspect).join(', ')})"
49 | end
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/test/acceptance/stubbing_method_accepting_block_parameter_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class StubbingMethodAcceptingBlockParameterTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_stubbing_class_method_accepting_block_parameter_should_restore_original_method
15 | klass = Class.new do
16 | def self.my_class_method(&block)
17 | block.call
18 | end
19 | end
20 | test_result = run_as_test do
21 | klass.stubs(:my_class_method)
22 | end
23 | assert_passed(test_result)
24 | assert_equal :return_value, (klass.my_class_method { :return_value })
25 | end
26 |
27 | def test_stubbing_instance_method_accepting_block_parameter_should_restore_original_method
28 | instance = Class.new do
29 | def my_instance_method
30 | yield
31 | end
32 | end.new
33 | test_result = run_as_test do
34 | instance.stubs(:my_instance_method)
35 | end
36 | assert_passed(test_result)
37 | assert_equal :return_value, (instance.my_instance_method { :return_value })
38 | end
39 |
40 | def test_stubbing_any_instance_method_accepting_block_parameter_should_restore_original_method
41 | klass = Class.new do
42 | def my_instance_method
43 | yield
44 | end
45 | end
46 | test_result = run_as_test do
47 | klass.any_instance.stubs(:my_instance_method)
48 | end
49 | assert_passed(test_result)
50 | assert_equal :return_value, (klass.new.my_instance_method { :return_value })
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/equivalent_uri_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 | require 'mocha/parameter_matchers/equivalent_uri'
3 |
4 | class EquivalentUriMatchesTest < Mocha::TestCase
5 | include Mocha::ParameterMatchers
6 |
7 | def test_should_match_identical_uri
8 | matcher = equivalent_uri('http://example.com/foo?a=1&b=2')
9 | assert matcher.matches?(['http://example.com/foo?a=1&b=2'])
10 | end
11 |
12 | def test_should_match_uri_with_rearranged_query_string
13 | matcher = equivalent_uri('http://example.com/foo?b=2&a=1')
14 | assert matcher.matches?(['http://example.com/foo?a=1&b=2'])
15 | end
16 |
17 | def test_should_not_match_uri_with_different_query_string
18 | matcher = equivalent_uri('http://example.com/foo?a=1')
19 | assert !matcher.matches?(['http://example.com/foo?a=1&b=2'])
20 | end
21 |
22 | def test_should_not_match_uri_when_no_query_string_expected
23 | matcher = equivalent_uri('http://example.com/foo')
24 | assert !matcher.matches?(['http://example.com/foo?a=1&b=2'])
25 | end
26 |
27 | def test_should_not_match_uri_with_different_domain
28 | matcher = equivalent_uri('http://a.example.com/foo?a=1&b=2')
29 | assert !matcher.matches?(['http://b.example.com/foo?a=1&b=2'])
30 | end
31 |
32 | def test_should_match_uri_without_scheme_and_domain
33 | matcher = equivalent_uri('/foo?a=1&b=2')
34 | assert matcher.matches?(['/foo?a=1&b=2'])
35 | end
36 |
37 | def test_should_match_uri_with_query_string_containing_blank_value
38 | matcher = equivalent_uri('http://example.com/foo?a=&b=2')
39 | assert matcher.matches?(['http://example.com/foo?a=&b=2'])
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/mocha/expectation_list.rb:
--------------------------------------------------------------------------------
1 | module Mocha
2 | class ExpectationList
3 | def initialize(expectations = [])
4 | @expectations = expectations
5 | end
6 |
7 | def add(expectation)
8 | @expectations.unshift(expectation)
9 | expectation
10 | end
11 |
12 | def remove_all_matching_method(method_name)
13 | @expectations.reject! { |expectation| expectation.matches_method?(method_name) }
14 | end
15 |
16 | def matches_method?(method_name)
17 | @expectations.any? { |expectation| expectation.matches_method?(method_name) }
18 | end
19 |
20 | def match(invocation, ignoring_order: false)
21 | matching_expectations(invocation, ignoring_order: ignoring_order).first
22 | end
23 |
24 | def match_but_out_of_order(invocation)
25 | matching_expectations(invocation).first
26 | end
27 |
28 | def match_allowing_invocation(invocation)
29 | matching_expectations(invocation).detect(&:invocations_allowed?)
30 | end
31 |
32 | def verified?(assertion_counter = nil)
33 | @expectations.all? { |expectation| expectation.verified?(assertion_counter) }
34 | end
35 |
36 | def to_a
37 | @expectations
38 | end
39 |
40 | def to_set
41 | @expectations.to_set
42 | end
43 |
44 | def length
45 | @expectations.length
46 | end
47 |
48 | def any?
49 | @expectations.any?
50 | end
51 |
52 | def +(other)
53 | self.class.new(to_a + other.to_a)
54 | end
55 |
56 | private
57 |
58 | def matching_expectations(invocation, ignoring_order: false)
59 | @expectations.select { |e| e.match?(invocation, ignoring_order: ignoring_order) }
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/test/acceptance/expectations_on_multiple_methods_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class ExpectationsOnMultipleMethodsTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_should_expect_calls_to_multiple_methods
15 | instance = Class.new do
16 | def my_instance_method_1
17 | :original_return_value_1
18 | end
19 |
20 | def my_instance_method_2
21 | :original_return_value_2
22 | end
23 | end.new
24 | test_result = run_as_test do
25 | instance.expects(
26 | my_instance_method_1: :new_return_value_1,
27 | my_instance_method_2: :new_return_value_2
28 | )
29 | assert_equal :new_return_value_1, instance.my_instance_method_1
30 | assert_equal :new_return_value_2, instance.my_instance_method_2
31 | end
32 | assert_passed(test_result)
33 | end
34 |
35 | def test_should_stub_calls_to_multiple_methods
36 | instance = Class.new do
37 | def my_instance_method_1
38 | :original_return_value_1
39 | end
40 |
41 | def my_instance_method_2
42 | :original_return_value_2
43 | end
44 | end.new
45 | test_result = run_as_test do
46 | instance.stubs(
47 | my_instance_method_1: :new_return_value_1,
48 | my_instance_method_2: :new_return_value_2
49 | )
50 | assert_equal :new_return_value_1, instance.my_instance_method_1
51 | assert_equal :new_return_value_2, instance.my_instance_method_2
52 | end
53 | assert_passed(test_result)
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/responds_with_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/responds_with'
4 | require 'mocha/parameter_matchers/instance_methods'
5 | require 'mocha/inspect'
6 |
7 | class RespondsWithTest < Mocha::TestCase
8 | include Mocha::ParameterMatchers
9 |
10 | def test_should_match_parameter_responding_with_expected_value
11 | matcher = responds_with(:upcase, 'FOO')
12 | assert matcher.matches?(['foo'])
13 | end
14 |
15 | def test_should_not_match_parameter_responding_with_unexpected_value
16 | matcher = responds_with(:upcase, 'FOO')
17 | assert !matcher.matches?(['bar'])
18 | end
19 |
20 | def test_should_match_parameter_responding_with_nested_responds_with_matcher
21 | matcher = responds_with(:foo, responds_with(:bar, 'baz'))
22 | object = Class.new do
23 | def foo
24 | Class.new do
25 | def bar
26 | 'baz'
27 | end
28 | end.new
29 | end
30 | end.new
31 | assert matcher.matches?([object])
32 | end
33 |
34 | def test_should_describe_matcher
35 | matcher = responds_with(:foo, :bar)
36 | assert_equal 'responds_with(:foo, :bar)', matcher.mocha_inspect
37 | end
38 |
39 | def test_should_match_parameter_responding_with_expected_values_for_given_messages
40 | matcher = responds_with(upcase: 'FOO', reverse: 'oof')
41 | assert matcher.matches?(['foo'])
42 | end
43 |
44 | def test_should_describe_matcher_with_multiple_messages_vs_results
45 | matcher = responds_with(foo: :bar, baz: 123)
46 | assert_equal 'all_of(responds_with(:foo, :bar), responds_with(:baz, 123))', matcher.mocha_inspect
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/unit/object_inspect_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../test_helper', __FILE__)
2 | require 'mocha/inspect'
3 | require 'method_definer'
4 |
5 | class ObjectInspectTest < Mocha::TestCase
6 | include MethodDefiner
7 |
8 | def test_should_return_default_string_representation_of_object_not_including_instance_variables
9 | object = Object.new
10 | class << object
11 | attr_accessor :attribute
12 | end
13 | object.attribute = 'instance_variable'
14 | assert_match Regexp.new('^#$'), object.mocha_inspect
15 | assert_no_match(/instance_variable/, object.mocha_inspect)
16 | end
17 |
18 | def test_should_return_customized_string_representation_of_object
19 | object = Object.new
20 | class << object
21 | define_method(:inspect) { 'custom_inspect' }
22 | end
23 | assert_equal 'custom_inspect', object.mocha_inspect
24 | end
25 |
26 | def test_should_use_underscored_id_instead_of_object_id_or_id_so_that_they_can_be_stubbed
27 | calls = []
28 | object = Object.new
29 | replace_instance_method(object, :object_id) do
30 | calls << :object_id
31 | return 1
32 | end
33 | replace_instance_method(object, :__id__) do
34 | calls << :__id__
35 | return 1
36 | end
37 | replace_instance_method(object, :inspect) { 'object-description' }
38 |
39 | object.mocha_inspect
40 |
41 | assert_equal [:__id__], calls.uniq
42 | end
43 |
44 | def test_should_not_call_object_instance_format_method
45 | object = Object.new
46 | class << object
47 | def format(*)
48 | 'internal_format'
49 | end
50 | end
51 | assert_no_match(/internal_format/, object.mocha_inspect)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/yaml_equivalent.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 | require 'yaml'
3 |
4 | module Mocha
5 | module ParameterMatchers
6 | # Matches any YAML that represents the specified +object+
7 | #
8 | # @param [Object] object object whose YAML to compare.
9 | # @return [YamlEquivalent] parameter matcher.
10 | #
11 | # @see Expectation#with
12 | #
13 | # @example Actual parameter is YAML equivalent of specified +object+.
14 | # object = mock()
15 | # object.expects(:method_1).with(yaml_equivalent(1, 2, 3))
16 | # object.method_1("--- \n- 1\n- 2\n- 3\n")
17 | # # no error raised
18 | #
19 | # @example Actual parameter is not YAML equivalent of specified +object+.
20 | # object = mock()
21 | # object.expects(:method_1).with(yaml_equivalent(1, 2, 3))
22 | # object.method_1("--- \n- 1\n- 2\n")
23 | # # error raised, because method_1 was not called with YAML representing the specified Array
24 | def yaml_equivalent(object)
25 | YamlEquivalent.new(object)
26 | end
27 |
28 | # Parameter matcher which matches if actual parameter is YAML equivalent of specified object.
29 | class YamlEquivalent < Base
30 | # @private
31 | def initialize(object)
32 | @object = object
33 | end
34 |
35 | # @private
36 | def matches?(available_parameters)
37 | parameter = available_parameters.shift
38 | # rubocop:disable Security/YAMLLoad
39 | @object == YAML.load(parameter)
40 | # rubocop:enable Security/YAMLLoad
41 | end
42 |
43 | # @private
44 | def mocha_inspect
45 | "yaml_equivalent(#{@object.mocha_inspect})"
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/mocha/inspect.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | module Mocha
4 | module Inspect
5 | module ObjectMethods
6 | def mocha_inspect
7 | address = __id__ * 2
8 | address += 0x100000000 if address < 0
9 | inspect =~ /# ? "#<#{self.class}:0x#{Kernel.format('%x', address: address)}>" : inspect
10 | end
11 | end
12 |
13 | module ArrayMethods
14 | def mocha_inspect(wrapped = true)
15 | unwrapped = collect(&:mocha_inspect).join(', ')
16 | wrapped ? "[#{unwrapped}]" : unwrapped
17 | end
18 | end
19 |
20 | module HashMethods
21 | def mocha_inspect
22 | if Hash.ruby2_keywords_hash?(self)
23 | collect do |key, value|
24 | case key
25 | when Symbol
26 | "#{key}: #{value.mocha_inspect}"
27 | else
28 | "#{key.mocha_inspect} => #{value.mocha_inspect}"
29 | end
30 | end.join(', ')
31 | else
32 | unwrapped = collect { |key, value| "#{key.mocha_inspect} => #{value.mocha_inspect}" }.join(', ')
33 | "{#{unwrapped}}"
34 | end
35 | end
36 | end
37 |
38 | module TimeMethods
39 | def mocha_inspect
40 | "#{inspect} (#{to_f} secs)"
41 | end
42 | end
43 |
44 | module DateMethods
45 | def mocha_inspect
46 | to_s
47 | end
48 | end
49 | end
50 | end
51 |
52 | class Object
53 | include Mocha::Inspect::ObjectMethods
54 | end
55 |
56 | class Array
57 | include Mocha::Inspect::ArrayMethods
58 | end
59 |
60 | class Hash
61 | include Mocha::Inspect::HashMethods
62 | end
63 |
64 | class Time
65 | include Mocha::Inspect::TimeMethods
66 | end
67 |
68 | class Date
69 | include Mocha::Inspect::DateMethods
70 | end
71 |
--------------------------------------------------------------------------------
/test/acceptance/multiple_yielding_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../acceptance_test_helper', __FILE__)
2 |
3 | class MultipleYieldingTest < Mocha::TestCase
4 | include AcceptanceTest
5 |
6 | def setup
7 | setup_acceptance_test
8 | end
9 |
10 | def teardown
11 | teardown_acceptance_test
12 | end
13 |
14 | def test_yields_values_multiple_times_when_stubbed_method_is_invoked
15 | test_result = run_as_test do
16 | m = mock('m')
17 | m.stubs(:foo).multiple_yields([1], [2, 3])
18 | yielded = []
19 | m.foo { |*args| yielded << args }
20 | assert_equal [[1], [2, 3]], yielded
21 | end
22 | assert_passed(test_result)
23 | end
24 |
25 | def test_yields_values_multiple_times_when_multiple_yields_arguments_are_not_arrays
26 | test_result = run_as_test do
27 | m = mock('m')
28 | m.stubs(:foo).multiple_yields(1, { b: 2 }, '3')
29 | yielded = []
30 | m.foo { |*args| yielded << args }
31 | assert_equal [[1], [{ b: 2 }], ['3']], yielded
32 | end
33 | assert_passed(test_result)
34 | end
35 |
36 | def test_raises_local_jump_error_if_instructed_to_multiple_yield_but_no_block_given
37 | test_result = run_as_test do
38 | m = mock('m')
39 | m.stubs(:foo).multiple_yields([])
40 | assert_raises(LocalJumpError) { m.foo }
41 | end
42 | assert_passed(test_result)
43 | end
44 |
45 | def test_yields_different_values_on_consecutive_invocations
46 | test_result = run_as_test do
47 | m = mock('m')
48 | m.stubs(:foo).multiple_yields([0], [1, 2]).then.multiple_yields([3], [4, 5])
49 | yielded = []
50 | m.foo { |*args| yielded << args }
51 | m.foo { |*args| yielded << args }
52 | assert_equal [[0], [1, 2], [3], [4, 5]], yielded
53 | end
54 | assert_passed(test_result)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/unit/parameter_matchers/has_key_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../../../test_helper', __FILE__)
2 |
3 | require 'mocha/parameter_matchers/has_key'
4 | require 'mocha/parameter_matchers/instance_methods'
5 | require 'mocha/inspect'
6 |
7 | class HasKeyTest < Mocha::TestCase
8 | include Mocha::ParameterMatchers
9 |
10 | def test_should_match_hash_including_specified_key
11 | matcher = has_key(:key_1)
12 | assert matcher.matches?([{ key_1: 1, key_2: 2 }])
13 | end
14 |
15 | def test_should_not_match_hash_not_including_specified_key
16 | matcher = has_key(:key_1)
17 | assert !matcher.matches?([{ key_2: 2 }])
18 | end
19 |
20 | def test_should_describe_matcher
21 | matcher = has_key(:key)
22 | assert_equal 'has_key(:key)', matcher.mocha_inspect
23 | end
24 |
25 | def test_should_match_hash_including_specified_key_with_nested_key_matcher
26 | matcher = has_key(equals(:key_1))
27 | assert matcher.matches?([{ key_1: 1, key_2: 2 }])
28 | end
29 |
30 | def test_should_not_match_hash_not_including_specified_key_with_nested_key_matcher
31 | matcher = has_key(equals(:key_1))
32 | assert !matcher.matches?([{ key_2: 2 }])
33 | end
34 |
35 | def test_should_not_raise_error_on_empty_arguments
36 | matcher = has_key(:key)
37 | assert_nothing_raised { matcher.matches?([]) }
38 | end
39 |
40 | def test_should_not_match_on_empty_arguments
41 | matcher = has_key(:key)
42 | assert !matcher.matches?([])
43 | end
44 |
45 | def test_should_not_raise_error_on_argument_that_does_not_respond_to_keys
46 | matcher = has_key(:key)
47 | assert_nothing_raised { matcher.matches?([:key]) }
48 | end
49 |
50 | def test_should_not_match_on_argument_that_does_not_respond_to_keys
51 | matcher = has_key(:key)
52 | assert !matcher.matches?([:key])
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/lib/mocha/parameter_matchers/has_keys.rb:
--------------------------------------------------------------------------------
1 | require 'mocha/parameter_matchers/base'
2 |
3 | module Mocha
4 | module ParameterMatchers
5 | # Matches +Hash+ containing +keys+.
6 | #
7 | # @param [*Array