# This cannot take advantage of our relative requires, since this file is a# dependency of `rspec/mocks/argument_list_matcher.rb`. See comment there for# details.require'rspec/support/matcher_definition'moduleRSpecmoduleMocks# ArgumentMatchers are placeholders that you can include in message# expectations to match arguments against a broader check than simple# equality.## With the exception of `any_args` and `no_args`, they all match against# the arg in same position in the argument list.## @see ArgumentListMatchermoduleArgumentMatchers# Acts like an arg splat, matching any number of args at any point in an arg list.## @example# expect(object).to receive(:message).with(1, 2, any_args)## # matches any of these:# object.message(1, 2)# object.message(1, 2, 3)# object.message(1, 2, 3, 4)defany_argsAnyArgsMatcher::INSTANCEend# Matches any argument at all.## @example# expect(object).to receive(:message).with(anything)defanythingAnyArgMatcher::INSTANCEend# Matches no arguments.## @example# expect(object).to receive(:message).with(no_args)defno_argsNoArgsMatcher::INSTANCEend# Matches if the actual argument responds to the specified messages.## @example# expect(object).to receive(:message).with(duck_type(:hello))# expect(object).to receive(:message).with(duck_type(:hello, :goodbye))defduck_type(*args)DuckTypeMatcher.new(*args)end# Matches a boolean value.## @example# expect(object).to receive(:message).with(boolean())defbooleanBooleanMatcher::INSTANCEend# Matches a hash that includes the specified key(s) or key/value pairs.# Ignores any additional keys.## @example# expect(object).to receive(:message).with(hash_including(:key => val))# expect(object).to receive(:message).with(hash_including(:key))# expect(object).to receive(:message).with(hash_including(:key, :key2 => val2))defhash_including(*args)HashIncludingMatcher.new(ArgumentMatchers.anythingize_lonely_keys(*args))end# Matches a hash that doesn't include the specified key(s) or key/value.## @example# expect(object).to receive(:message).with(hash_excluding(:key => val))# expect(object).to receive(:message).with(hash_excluding(:key))# expect(object).to receive(:message).with(hash_excluding(:key, :key2 => :val2))defhash_excluding(*args)HashExcludingMatcher.new(ArgumentMatchers.anythingize_lonely_keys(*args))end# Matches an array that includes the specified items at least once.# Ignores duplicates and additional values## @example# expect(object).to receive(:message).with(array_including(1,2,3))# expect(object).to receive(:message).with(array_including([1,2,3]))defarray_including(*args)actually_an_array=Array===args.first&&args.count==1?args.first:argsArrayIncludingMatcher.new(actually_an_array)end# Matches an array that excludes the specified items.## @example# expect(object).to receive(:message).with(array_excluding(1,2,3))# expect(object).to receive(:message).with(array_excluding([1,2,3]))defarray_excluding(*args)actually_an_array=Array===args.first&&args.count==1?args.first:argsArrayExcludingMatcher.new(actually_an_array)endalias_method:hash_not_including,:hash_excluding# Matches if `arg.instance_of?(klass)`## @example# expect(object).to receive(:message).with(instance_of(Thing))definstance_of(klass)InstanceOf.new(klass)endalias_method:an_instance_of,:instance_of# Matches if `arg.kind_of?(klass)`## @example# expect(object).to receive(:message).with(kind_of(Thing))defkind_of(klass)KindOf.new(klass)endalias_method:a_kind_of,:kind_of# @privatedefself.anythingize_lonely_keys(*args)hash=Hash===args.last?args.delete_at(-1):{}args.each{|arg|hash[arg]=AnyArgMatcher::INSTANCE}hashend# Intended to be subclassed by stateless, immutable argument matchers.# Provides a `<klass name>::INSTANCE` constant for accessing a global# singleton instance of the matcher. There is no need to construct# multiple instance since there is no state. It also facilities the# special case logic we need for some of these matchers, by making it# easy to do comparisons like: `[klass::INSTANCE] == args` rather than# `args.count == 1 && klass === args.first`.## @privateclassSingletonMatcherprivate_class_method:newdefself.inherited(subklass)subklass.const_set(:INSTANCE,subklass.send(:new))endend# @privateclassAnyArgsMatcher<SingletonMatcherdefdescription"*(any args)"endend# @privateclassAnyArgMatcher<SingletonMatcherdef===(_other)trueenddefdescription"anything"endend# @privateclassNoArgsMatcher<SingletonMatcherdefdescription"no args"endend# @privateclassBooleanMatcher<SingletonMatcherdef===(value)true==value||false==valueenddefdescription"boolean"endend# @privateclassBaseHashMatcherdefinitialize(expected)@expected=expectedenddef===(predicate,actual)@expected.__send__(predicate)do|k,v|actual.key?(k)&&Support::FuzzyMatcher.values_match?(v,actual[k])endrescueNoMethodErrorfalseenddefdescription(name)"#{name}(#{formatted_expected_hash.inspect.sub(/^\{/,"").sub(/\}$/,"")})"endprivatedefformatted_expected_hashHash[@expected.mapdo|k,v|k=RSpec::Support.rspec_description_for_object(k)v=RSpec::Support.rspec_description_for_object(v)[k,v]end]endend# @privateclassHashIncludingMatcher<BaseHashMatcherdef===(actual)super(:all?,actual)enddefdescriptionsuper("hash_including")endend# @privateclassHashExcludingMatcher<BaseHashMatcherdef===(actual)super(:none?,actual)enddefdescriptionsuper("hash_not_including")endend# @privateclassArrayIncludingMatcherdefinitialize(expected)@expected=expectedenddef===(actual)actual=actual.uniqreturntrueif(actual&@expected).count>=@expected.count@expected.uniq.all?do|expected_element|actual.any?do|actual_element|RSpec::Support::FuzzyMatcher.values_match?(expected_element,actual_element)endendrescueNoMethodErrorfalseenddefdescription"array_including(#{formatted_expected_values})"endprivatedefformatted_expected_values@expected.mapdo|x|RSpec::Support.rspec_description_for_object(x)end.join(", ")endend# @privateclassArrayExcludingMatcherdefinitialize(unexpected)@unexpected=unexpected.uniqenddef===(actual)actual=actual.uniqreturnfalseunless(actual&@unexpected).empty?actual.none?do|actual_element|@unexpected.any?do|unexpected_element|RSpec::Support::FuzzyMatcher.values_match?(unexpected_element,actual_element)endendrescueNoMethodErrorfalseenddefdescription"array_excluding(#{formatted_unexpected_values})"endprivatedefformatted_unexpected_values@unexpected.mapdo|x|RSpec::Support.rspec_description_for_object(x)end.join(", ")endend# @privateclassDuckTypeMatcherdefinitialize(*methods_to_respond_to)@methods_to_respond_to=methods_to_respond_toenddef===(value)@methods_to_respond_to.all?{|message|value.respond_to?(message)}enddefdescription"duck_type(#{@methods_to_respond_to.map(&:inspect).join(', ')})"endend# @privateclassInstanceOfdefinitialize(klass)@klass=klassenddef===(actual)actual.instance_of?(@klass)enddefdescription"an_instance_of(#{@klass.name})"endend# @privateclassKindOfdefinitialize(klass)@klass=klassenddef===(actual)actual.kind_of?(@klass)enddefdescription"kind of #{@klass.name}"endendmatcher_namespace=name+'::'::RSpec::Support.register_matcher_definitiondo|object|# This is the best we have for now. We should tag all of our matchers# with a module or something so we can test for it directly.## (Note Module#parent in ActiveSupport is defined in a similar way.)beginobject.class.name.include?(matcher_namespace)rescueNoMethodError# Some objects, like BasicObject, don't implement standard# reflection methods.falseendendendendend