pax_global_header00006660000000000000000000000064145577000010014511gustar00rootroot0000000000000052 comment=c3e599857fcfbd04a42b2fdbea9e2810ebd52fb2 rspec-expectations-3.13.0/000077500000000000000000000000001455770000100154155ustar00rootroot00000000000000rspec-expectations-3.13.0/.document000066400000000000000000000000601455770000100172300ustar00rootroot00000000000000lib/**/*.rb - README.md LICENSE.md Changelog.md rspec-expectations-3.13.0/.github/000077500000000000000000000000001455770000100167555ustar00rootroot00000000000000rspec-expectations-3.13.0/.github/FUNDING.yml000066400000000000000000000003351455770000100205730ustar00rootroot00000000000000# This file was generated on 2023-04-16T20:53:22+01:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. github: [JonRowe, benoittgt] open_collective: rspec rspec-expectations-3.13.0/.github/dependabot.yml000066400000000000000000000004371455770000100216110ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" rspec-expectations-3.13.0/.github/workflows/000077500000000000000000000000001455770000100210125ustar00rootroot00000000000000rspec-expectations-3.13.0/.github/workflows/ci.yml000066400000000000000000000114301455770000100221270ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. name: RSpec CI on: push: branches: - 'main' - '*-maintenance' - '*-dev' pull_request: branches: - '*' permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true env: RSPEC_CI: true # This tells rspec-rails what branch to run in ci RSPEC_VERSION: '~> 3.13.0' jobs: rubocop: name: Rubocop runs-on: 'ubuntu-20.04' steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: '3.0' - run: script/update_rubygems_and_install_bundler - run: script/clone_all_rspec_repos - run: bundle install --standalone - run: bundle binstubs --all - run: script/run_rubocop test: name: Ruby ${{ matrix.ruby }} ${{ matrix.name_extra || '' }} runs-on: ${{ matrix.os || 'ubuntu-20.04' }} strategy: matrix: ruby: - '3.3' - '3.2' - '3.1' - '3.0' - 2.7 - 2.6 - 2.5 - 2.4 - 2.3 - 2.2 env: - DIFF_LCS_VERSION: "> 1.4.3" include: - ruby: ruby-head env: RUBY_HEAD: true - ruby: jruby-9.2.13.0 env: JRUBY_OPTS: "--dev" - ruby: 2.7 name_extra: "with diff-lcs 1.3" env: DIFF_LCS_VERSION: "~> 1.3.0" - ruby: 2.7 name_extra: "with diff-lcs 1.4.3" env: DIFF_LCS_VERSION: "1.4.3" fail-fast: false continue-on-error: ${{ matrix.allow_failure || endsWith(matrix.ruby, 'head') }} env: ${{ matrix.env }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: bundler: ${{ matrix.bundler || '2.2.22' }} ruby-version: ${{ matrix.ruby }} - run: script/update_rubygems_and_install_bundler - run: script/clone_all_rspec_repos - run: bundle install --standalone - run: bundle binstubs --all - run: script/run_build legacy: name: Legacy Ruby Builds (${{ matrix.container.version }}) runs-on: ubuntu-20.04 container: image: ${{ matrix.container.tag }} options: ${{ matrix.container.options || '--add-host github-complains-if-this-is-empty.com:127.0.0.1' }} strategy: fail-fast: false matrix: container: - version: "2.1.9" tag: ghcr.io/rspec/docker-ci:2.1.9 post: git config --global --add safe.directory `pwd` - version: "2.0" tag: ghcr.io/rspec/docker-ci:2.0.0 - version: "1.9.3" tag: ghcr.io/rspec/docker-ci:1.9.3 - version: "1.9.2" tag: ghcr.io/rspec/docker-ci:1.9.2 options: "--add-host rubygems.org:151.101.129.227 --add-host api.rubygems.org:151.101.129.227" - version: "1.8.7" tag: ghcr.io/rspec/docker-ci:1.8.7 options: "--add-host rubygems.org:151.101.129.227 --add-host api.rubygems.org:151.101.129.227" - version: "REE" tag: ghcr.io/rspec/docker-ci:ree options: "--add-host rubygems.org:151.101.129.227 --add-host api.rubygems.org:151.101.129.227" - version: "JRuby 1.7" tag: ghcr.io/rspec/docker-ci:jruby-1.7 - version: "JRuby 1.7 1.8 mode" tag: ghcr.io/rspec/docker-ci:jruby-1.7 jruby_opts: '--dev --1.8' pre: gem uninstall jruby-openssl options: "--add-host rubygems.org:151.101.129.227 --add-host api.rubygems.org:151.101.129.227" - version: "JRuby 9.1.17.0" tag: ghcr.io/rspec/docker-ci:jruby-9.1.17.0 options: "--add-host rubygems.org:151.101.129.227 --add-host api.rubygems.org:151.101.129.227" env: LEGACY_CI: true JRUBY_OPTS: ${{ matrix.container.jruby_opts || '--dev' }} steps: - uses: actions/checkout@v3 - run: ${{ matrix.container.pre }} - run: script/legacy_setup.sh - run: ${{ matrix.container.post }} - run: bundle exec bin/rspec - run: bundle exec script/cucumber.sh windows: name: Ruby ${{ matrix.ruby }} (Windows) runs-on: windows-latest strategy: matrix: ruby: - 2.7 - 2.6 - 2.5 - 2.4 - 2.3 - 2.2 fail-fast: false steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: bundler: '2.2.22' ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: choco install ansicon - run: bundle exec rspec --backtrace rspec-expectations-3.13.0/.gitignore000066400000000000000000000002401455770000100174010ustar00rootroot00000000000000*.sw? .DS_Store coverage* rdoc pkg doc tmp rerun.txt Gemfile.lock .bundle *.rbc .yardoc bin .rbx Gemfile-custom bundle .rspec-local spec/examples.txt specs.out rspec-expectations-3.13.0/.rspec000066400000000000000000000000411455770000100165250ustar00rootroot00000000000000--warnings --require spec_helper rspec-expectations-3.13.0/.rubocop.yml000066400000000000000000000043501455770000100176710ustar00rootroot00000000000000inherit_from: - .rubocop_todo.yml - .rubocop_rspec_base.yml AllCops: TargetRubyVersion: 2.4 DisplayCopNames: true Exclude: - bin/* - tmp/**/* # Over time we'd like to get this down, but this is what we're at now. Layout/LineLength: Max: 186 # Offense count: 1 Style/BlockComments: Enabled: false Style/ClassAndModuleChildren: Exclude: - spec/**/* Style/EvalWithLocation: Exclude: - spec/rspec/matchers/built_in/respond_to_spec.rb Style/MultilineBlockChain: Exclude: - spec/**/* Style/RescueModifier: Exclude: - spec/**/* - benchmarks/**/* Style/Semicolon: Enabled: false Style/SingleLineMethods: Exclude: - spec/**/* - benchmarks/**/* # We have some situations where we need to use `raise ExceptionClass.new(argument)`. Style/RaiseArgs: Enabled: false Style/FrozenStringLiteralComment: EnforcedStyle: never Exclude: - REPORT_TEMPLATE.md Style/PercentLiteralDelimiters: PreferredDelimiters: default: [] '%r': '||' Style/WordArray: Enabled: false Security/Eval: Exclude: - Gemfile Metrics/AbcSize: Max: 27 # Offense count: 2 # Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: Max: 96 Exclude: - spec/**/* # Offense count: 1 # Configuration parameters: CountComments. Metrics/ModuleLength: Max: 239 Exclude: - spec/**/* # Offense count: 4 Metrics/PerceivedComplexity: Max: 14 Layout/AccessModifierIndentation: Exclude: - 'lib/rspec/expectations/syntax.rb' # Too much diff to fix # Offense count: 7 Layout/ParameterAlignment: Enabled: false Layout/SpaceInsideArrayLiteralBrackets: Exclude: - spec/rspec/matchers/built_in/contain_exactly_spec.rb Layout/SpaceInsideParens: Exclude: - spec/rspec/matchers/built_in/* Lint/AmbiguousBlockAssociation: Exclude: - spec/**/* Lint/AmbiguousRegexpLiteral: Exclude: - 'features/step_definitions/*' Lint/SuppressedException: Exclude: - benchmarks/**/* # Offense count: 3 Lint/IneffectiveAccessModifier: Exclude: - 'lib/rspec/matchers.rb' - 'lib/rspec/matchers/built_in/compound.rb' Lint/InheritException: Exclude: - 'lib/rspec/expectations.rb' Bundler/DuplicatedGem: Enabled: false Bundler/OrderedGems: Enabled: false rspec-expectations-3.13.0/.rubocop_rspec_base.yml000066400000000000000000000150051455770000100220560ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # This file contains defaults for RSpec projects. Individual projects # can customize by inheriting this file and overriding particular settings. Layout/AccessModifierIndentation: Enabled: false # "Use alias_method instead of alias" # We're fine with `alias`. Style/Alias: Enabled: false # "Avoid the use of the case equality operator ===" # We prefer using `Class#===` over `Object#is_a?` because `Class#===` # is less likely to be monkey patched than `is_a?` on a user object. Style/CaseEquality: Enabled: false # Warns when the class is excessively long. Metrics/ClassLength: Max: 100 Style/CollectionMethods: PreferredMethods: reduce: 'inject' # Over time we'd like to get this down, but this is what we're at now. Metrics/CyclomaticComplexity: Max: 10 # We use YARD to enforce documentation. It works better than rubocop's # enforcement...rubocop complains about the places we re-open # `RSpec::Expectations` and `RSpec::Matchers` w/o having doc commments. Style/Documentation: Enabled: false # We still support 1.8.7 which requires trailing dots Layout/DotPosition: EnforcedStyle: trailing Style/DoubleNegation: Enabled: false # each_with_object is unavailable on 1.8.7 so we have to disable this one. Style/EachWithObject: Enabled: false Style/FormatString: EnforcedStyle: percent # As long as we support ruby 1.8.7 we have to use hash rockets. Style/HashSyntax: EnforcedStyle: hash_rockets # We can't use the new lambda syntax, since we still support 1.8.7. Style/Lambda: Enabled: false # Over time we'd like to get this down, but this is what we're at now. Layout/LineLength: Max: 100 # Over time we'd like to get this down, but this is what we're at now. Metrics/MethodLength: Max: 15 # Who cares what we call the argument for binary operator methods? Naming/BinaryOperatorParameterName: Enabled: false Style/PercentLiteralDelimiters: PreferredDelimiters: '%': () # double-quoted string '%i': '[]' # array of symbols '%q': () # single-quoted string '%Q': () # double-quoted string '%r': '{}' # regular expression pattern '%s': () # a symbol '%w': '[]' # array of single-quoted strings '%W': '[]' # array of double-quoted strings '%x': () # a shell command as a string # We have too many special cases where we allow generator methods or prefer a # prefixed predicate due to it's improved readability. Naming/PredicateName: Enabled: false # On 1.8 `proc` is `lambda`, so we use `Proc.new` to ensure we get real procs on all supported versions. # http://batsov.com/articles/2014/02/04/the-elements-of-style-in-ruby-number-12-proc-vs-proc-dot-new/ Style/Proc: Enabled: false # Exceptions should be rescued with `Support::AllExceptionsExceptOnesWeMustNotRescue` Lint/RescueException: Enabled: true # We haven't adopted the `fail` to signal exceptions vs `raise` for re-raises convention. Style/SignalException: Enabled: false # We've tended to use no space, so it's less of a change to stick with that. Layout/SpaceAroundEqualsInParameterDefault: EnforcedStyle: no_space # We don't care about single vs double qoutes. Style/StringLiterals: Enabled: false # This rule favors constant names from the English standard library which we don't load. Style/SpecialGlobalVars: Enabled: false Style/TrailingCommaInArrayLiteral: Enabled: false Style/TrailingCommaInHashLiteral: Enabled: false Style/TrailingCommaInArguments: Enabled: false Style/TrivialAccessors: AllowDSLWriters: true AllowPredicates: true ExactNameMatch: true Style/ParallelAssignment: Enabled: false Layout/EmptyLineBetweenDefs: Enabled: false Layout/FirstParameterIndentation: Enabled: false Layout/ParameterAlignment: EnforcedStyle: with_first_parameter Layout/SpaceInsideBlockBraces: Enabled: false Layout/SpaceInsideParens: Enabled: false Naming/ConstantName: Enabled: false Style/ClassCheck: Enabled: false Style/ConditionalAssignment: Enabled: false Style/EmptyMethod: Enabled: false Style/FormatStringToken: Enabled: false Style/GuardClause: Enabled: false Style/IdenticalConditionalBranches: Enabled: false Style/IfUnlessModifier: Enabled: false Style/IfUnlessModifierOfIfUnless: Enabled: false Lint/MissingSuper: Enabled: false Style/MissingRespondToMissing: Enabled: false Style/MixinUsage: Enabled: false Style/MultipleComparison: Enabled: false Style/MutableConstant: Enabled: false Style/NestedModifier: Enabled: false Style/NestedParenthesizedCalls: Enabled: false Style/NumericPredicate: Enabled: false Style/RedundantParentheses: Enabled: false Style/StringLiteralsInInterpolation: Enabled: false Style/SymbolArray: Enabled: false Style/SymbolProc: Enabled: false Style/YodaCondition: Enabled: false Style/ZeroLengthPredicate: Enabled: false Layout/ClosingParenthesisIndentation: Enabled: false Layout/ExtraSpacing: Enabled: false Layout/MultilineMethodCallBraceLayout: Enabled: false Layout/MultilineMethodCallIndentation: Enabled: false Layout/MultilineOperationIndentation: Enabled: false Layout/SpaceAroundBlockParameters: Enabled: false Layout/SpaceAroundOperators: Enabled: false Layout/SpaceBeforeComma: Enabled: false Style/BlockDelimiters: Enabled: false Style/EmptyCaseCondition: Enabled: false Style/MultilineIfModifier: Enabled: false Style/RescueStandardError: Enabled: false Style/StderrPuts: Enabled: false Style/TernaryParentheses: Enabled: false Naming/HeredocDelimiterNaming: Enabled: false Layout/AssignmentIndentation: Enabled: false Layout/EmptyLineAfterMagicComment: Enabled: false Layout/FirstArrayElementIndentation: Enabled: false Layout/HeredocIndentation: Enabled: false Layout/SpaceInsidePercentLiteralDelimiters: Enabled: false Style/EmptyElse: Enabled: false Style/IfInsideElse: Enabled: false Style/RedundantReturn: Enabled: false Style/StructInheritance: Enabled: false Naming/VariableNumber: Enabled: false Layout/SpaceInsideStringInterpolation: Enabled: false Style/DateTime: Enabled: false Style/ParenthesesAroundCondition: Enabled: false Layout/EmptyLinesAroundBlockBody: Enabled: false Lint/ImplicitStringConcatenation: Enabled: false Lint/NestedMethodDefinition: Enabled: false Style/RegexpLiteral: Enabled: false Style/TrailingUnderscoreVariable: Enabled: false Layout/EmptyLinesAroundAccessModifier: Enabled: false rspec-expectations-3.13.0/.rubocop_todo.yml000066400000000000000000000251571455770000100207260ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config` # on 2022-01-09 00:30:11 UTC using RuboCop version 1.11.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 4 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: with_first_argument, with_fixed_indentation Layout/ArgumentAlignment: Exclude: - 'spec/rspec/expectations/handler_spec.rb' - 'spec/rspec/expectations_spec.rb' - 'spec/rspec/matchers/built_in/yield_spec.rb' # Offense count: 15 # Cop supports --auto-correct. Layout/ClosingHeredocIndentation: Exclude: - 'lib/rspec/matchers/built_in/equal.rb' - 'lib/rspec/matchers/generated_descriptions.rb' - 'spec/rspec/matchers/built_in/all_spec.rb' - 'spec/rspec/matchers/built_in/contain_exactly_spec.rb' - 'spec/rspec/matchers/built_in/equal_spec.rb' # Offense count: 68 # Cop supports --auto-correct. Layout/EmptyLineAfterGuardClause: Enabled: false # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: AllowAliasSyntax, AllowedMethods. # AllowedMethods: alias_method, public, protected, private Layout/EmptyLinesAroundAttributeAccessor: Exclude: - 'lib/rspec/expectations/configuration.rb' - 'spec/rspec/matchers/built_in/be_between_spec.rb' # Offense count: 17 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses Layout/FirstArgumentIndentation: Exclude: - 'spec/rspec/expectations/failure_aggregator_spec.rb' - 'spec/rspec/matchers/aliases_spec.rb' - 'spec/rspec/matchers/built_in/compound_spec.rb' - 'spec/rspec/matchers/composable_spec.rb' - 'spec/rspec/matchers/expecteds_for_multiple_diffs_spec.rb' - 'spec/rspec/matchers_spec.rb' # Offense count: 12 # Cop supports --auto-correct. # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. # SupportedHashRocketStyles: key, separator, table # SupportedColonStyles: key, separator, table # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit Layout/HashAlignment: Exclude: - 'lib/rspec/expectations/configuration.rb' - 'rspec-expectations.gemspec' - 'spec/rspec/expectations/handler_spec.rb' - 'spec/rspec/matchers/composable_spec.rb' - 'spec/rspec/matchers/description_generation_spec.rb' # Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: Width, IgnoredPatterns. Layout/IndentationWidth: Exclude: - 'lib/rspec/matchers/built_in/be.rb' - 'lib/rspec/matchers/built_in/be_kind_of.rb' - 'lib/rspec/matchers/built_in/start_or_end_with.rb' - 'lib/rspec/matchers/dsl.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. # SupportedStyles: space, no_space, compact # SupportedStylesForEmptyBraces: space, no_space Layout/SpaceInsideHashLiteralBraces: Exclude: - 'spec/rspec/matchers/built_in/be_spec.rb' # Offense count: 10 # Configuration parameters: AllowedMethods. # AllowedMethods: enums Lint/ConstantDefinitionInBlock: Exclude: - 'spec/rspec/matchers/built_in/be_between_spec.rb' - 'spec/rspec/matchers/built_in/be_spec.rb' - 'spec/rspec/matchers/built_in/have_attributes_spec.rb' - 'spec/rspec/matchers/built_in/include_spec.rb' - 'spec/rspec/matchers/built_in/raise_error_spec.rb' - 'spec/rspec/matchers/description_generation_spec.rb' - 'spec/rspec/matchers/expecteds_for_multiple_diffs_spec.rb' # Offense count: 2 Lint/FloatComparison: Exclude: - 'spec/rspec/matchers/built_in/operators_spec.rb' - 'spec/spec_helper.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowedImplicitNamespaces. # AllowedImplicitNamespaces: Gem Lint/RaiseException: Exclude: - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 2 # Cop supports --auto-correct. Lint/RedundantCopDisableDirective: Exclude: - 'spec/rspec/matchers/built_in/change_spec.rb' - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Lint/RedundantRequireStatement: Exclude: - 'spec/rspec/matchers/built_in/eq_spec.rb' # Offense count: 2 Lint/StructNewOverride: Exclude: - 'spec/rspec/expectations/syntax_spec.rb' # Offense count: 1 # Configuration parameters: AllowComments. Lint/SuppressedException: Exclude: - 'benchmarks/**/*' - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 3 # Configuration parameters: IgnoredPatterns. # IgnoredPatterns: (?-mix:(exactly|at_least|at_most)\(\d+\)\.times) Lint/UnreachableLoop: Exclude: - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. Lint/UnusedBlockArgument: Exclude: - 'spec/rspec/matchers/built_in/be_spec.rb' # Offense count: 5 # Cop supports --auto-correct. # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. Lint/UnusedMethodArgument: Exclude: - 'spec/rspec/expectations/failure_aggregator_spec.rb' - 'spec/rspec/matchers/built_in/be_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowComments. Lint/UselessMethodDefinition: Exclude: - 'lib/rspec/matchers.rb' # Offense count: 3 # Cop supports --auto-correct. Lint/UselessTimes: Exclude: - 'spec/rspec/matchers/built_in/yield_spec.rb' # Offense count: 1 # Configuration parameters: IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: Max: 27 # Offense count: 69 # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. # AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to Naming/MethodParameterName: Exclude: - 'benchmarks/caller_vs_raise_for_backtrace.rb' - 'benchmarks/method_to_proc.rb' - 'lib/rspec/expectations/minitest_integration.rb' - 'lib/rspec/matchers/built_in/count_expectation.rb' - 'lib/rspec/matchers/built_in/equal.rb' - 'lib/rspec/matchers/built_in/operators.rb' - 'lib/rspec/matchers/built_in/respond_to.rb' - 'spec/rspec/matchers/aliased_matcher_spec.rb' - 'spec/rspec/matchers/built_in/equal_spec.rb' - 'spec/rspec/matchers/built_in/respond_to_spec.rb' - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 5 # Cop supports --auto-correct. # Configuration parameters: PreferredName. Naming/RescuedExceptionsVariableName: Exclude: - 'lib/rspec/matchers/built_in/base_matcher.rb' - 'lib/rspec/matchers/built_in/raise_error.rb' - 'lib/rspec/matchers/built_in/throw_symbol.rb' - 'lib/rspec/matchers/dsl.rb' # Offense count: 1 # Configuration parameters: EnforcedStyle, AllowModifiersOnSymbols. # SupportedStyles: inline, group Style/AccessModifierDeclarations: Exclude: - 'lib/rspec/matchers/built_in/base_matcher.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Exclude: - 'spec/rspec/matchers/built_in/has_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Style/CaseLikeIf: Exclude: - 'lib/rspec/matchers/built_in/has.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: ==, equal?, eql? Style/ClassEqualityComparison: Exclude: - 'spec/rspec/matchers/aliases_spec.rb' - 'spec/support/matchers.rb' # Offense count: 11 # Cop supports --auto-correct. # Configuration parameters: Keywords. # Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW, NOTE Style/CommentAnnotation: Exclude: - 'lib/rspec/expectations/handler.rb' - 'spec/rspec/matchers/built_in/respond_to_spec.rb' - 'spec/rspec/matchers/dsl_spec.rb' - 'spec/support/shared_examples/block_matcher.rb' - 'spec/support/shared_examples/matcher.rb' # Offense count: 1 # Cop supports --auto-correct. Style/EmptyLiteral: Exclude: - 'spec/rspec/matchers/built_in/include_spec.rb' # Offense count: 2 # Cop supports --auto-correct. Style/ExpandPathArguments: Exclude: - 'Gemfile' - 'rspec-expectations.gemspec' # Offense count: 2 # Cop supports --auto-correct. Style/ExplicitBlockArgument: Exclude: - 'spec/rspec/matchers/built_in/all_spec.rb' - 'spec/rspec/matchers/built_in/contain_exactly_spec.rb' # Offense count: 5 # Cop supports --auto-correct. Style/GlobalStdStream: Exclude: - 'spec/rspec/matchers/built_in/change_spec.rb' - 'spec/rspec/matchers/composable_spec.rb' # Offense count: 7 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - 'lib/rspec/matchers/built_in/contain_exactly.rb' - 'lib/rspec/matchers/built_in/has.rb' - 'lib/rspec/matchers/built_in/raise_error.rb' - 'lib/rspec/matchers/dsl.rb' - 'lib/rspec/matchers/matcher_delegator.rb' - 'spec/rspec/matchers/built_in/compound_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Exclude: - 'spec/spec_helper.rb' # Offense count: 24 # Cop supports --auto-correct. Style/RedundantRegexpEscape: Exclude: - 'lib/rspec/matchers/built_in/throw_symbol.rb' - 'spec/rspec/matchers/built_in/raise_error_spec.rb' - 'spec/rspec/matchers/composable_spec.rb' - 'spec/rspec/matchers/dsl_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Style/RedundantSelf: Exclude: - 'spec/rspec/matchers/built_in/be_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods. # AllowedMethods: present?, blank?, presence, try, try! Style/SafeNavigation: Exclude: - 'lib/rspec/matchers/built_in/operators.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowModifier. Style/SoleNestedConditional: Exclude: - 'spec/rspec/expectations/failure_aggregator_spec.rb' # Offense count: 7 # Cop supports --auto-correct. Style/StringConcatenation: Exclude: - 'lib/rspec/matchers/built_in/all.rb' - 'lib/rspec/matchers/built_in/be.rb' - 'lib/rspec/matchers/built_in/compound.rb' - 'lib/rspec/matchers/built_in/contain_exactly.rb' - 'lib/rspec/matchers/built_in/yield.rb' - 'spec/rspec/matchers/aliased_matcher_spec.rb' rspec-expectations-3.13.0/.yardopts000066400000000000000000000001141455770000100172570ustar00rootroot00000000000000--exclude features --no-private --markup markdown - Changelog.md LICENSE.md rspec-expectations-3.13.0/BUILD_DETAIL.md000066400000000000000000000124501455770000100176220ustar00rootroot00000000000000 # The CI build, in detail The [Travis CI build](https://travis-ci.org/rspec/rspec-expectations) runs many verification steps to prevent regressions and ensure high-quality code. To run the Travis build locally, run: ``` $ script/run_build ``` It can be useful to run the build steps individually to repro a failing part of a Travis build. Let's break the build down into the individual steps. ## Specs RSpec dogfoods itself. Its primary defense against regressions is its spec suite. Run with: ``` $ bundle exec rspec # or, if you installed your bundle with `--standalone --binstubs`: $ bin/rspec ``` The spec suite performs a couple extra checks that are worth noting: * *That all the code is warning-free.* Any individual example that produces output to `stderr` will fail. We also have a spec that loads all the `lib` and `spec` files in a newly spawned process to detect load-time warnings and fail if there are any. RSpec must be warning-free so that users who enable Ruby warnings will not get warnings from our code. * *That only a minimal set of stdlibs are loaded.* Since Ruby makes loaded libraries available for use in any context, we want to minimize how many bits of the standard library we load and use. Otherwise, RSpec's use of part of the standard library could mask a problem where a gem author forgets to load a part of the standard library they rely on. The spec suite contains a spec that defines a list of allowed loaded stdlibs. In addition, we use [SimpleCov](https://github.com/colszowka/simplecov) to measure and enforce test coverage. If the coverage falls below a project-specific threshold, the build will fail. ## Cukes RSpec uses [cucumber](https://cucumber.io/) for both acceptance testing and [documentation](https://rspec.info/documentation). Since we publish our cukes as documentation, please limit new cucumber scenarios to user-facing examples that help demonstrate usage. Any tests that exist purely to prevent regressions should be written as specs, even if they are written in an acceptance style. Duplication between our YARD API docs and the cucumber documentation is fine. Run with: ``` $ bundle exec cucumber # or, if you installed your bundle with `--standalone --binstubs`: $ bin/cucumber ``` ## YARD documentation RSpec uses [YARD](https://yardoc.org/) for API documentation on the [rspec.info site](https://rspec.info/). Our commitment to [SemVer](https://semver.org) requires that we explicitly declare our public API, and our build uses YARD to ensure that every class, module and method has either been labeled `@private` or has at least some level of documentation. For new APIs, this forces us to make an intentional decision about whether or not it should be part of RSpec's public API or not. To run the YARD documentation coverage check, run: ``` $ bundle exec yard stats --list-undoc # or, if you installed your bundle with `--standalone --binstubs`: $ bin/yard stats --list-undoc ``` We also want to prevent YARD errors or warnings when actually generating the docs. To check for those, run: ``` $ bundle exec yard doc --no-cache # or, if you installed your bundle with `--standalone --binstubs`: $ bin/yard doc --no-cache ``` ## RuboCop We use [RuboCop](https://github.com/rubocop-hq/rubocop) to enforce style conventions on the project so that the code has stylistic consistency throughout. Run with: ``` $ bundle exec rubocop lib # or, if you installed your bundle with `--standalone --binstubs`: $ bin/rubocop lib ``` Our RuboCop configuration is a work-in-progress, so if you get a failure due to a RuboCop default, feel free to ask about changing the configuration. Otherwise, you'll need to address the RuboCop failure, or, as a measure of last resort, by wrapping the offending code in comments like `# rubocop:disable SomeCheck` and `# rubocop:enable SomeCheck`. ## Run spec files one-by-one A fast TDD cycle depends upon being able to run a single spec file, without the rest of the test suite. While rare, it's fairly easy to create a situation where a spec passes when the entire suite runs but fails when its individual file is run. To guard against this, our CI build runs each spec file individually, using a bit of bash like: ``` for file in `find spec -iname '*_spec.rb'`; do echo "Running $file" bin/rspec $file -b --format progress done ``` Since this step boots RSpec so many times, it runs much, much faster when we can avoid the overhead of bundler. This is a main reason our CI build installs the bundle with `--standalone --binstubs` and runs RSpec via `bin/rspec` rather than `bundle exec rspec`. ## Running the spec suite for each of the other repos While each of the RSpec repos is an independent gem (generally designed to be usable on its own), there are interdependencies between the gems, and the specs for each tend to use features from the other gems. We don't want to merge a pull request for one repo that might break the build for another repo, so our CI build includes a spec that runs the spec suite of each of the _other_ project repos. Note that we only run the spec suite, not the full build, of the other projects, as the spec suite runs very quickly compared to the full build. rspec-expectations-3.13.0/CODE_OF_CONDUCT.md000066400000000000000000000054441455770000100202230ustar00rootroot00000000000000 # Contributor Code of Conduct For the purpose of building a welcoming, harassment-free community that values contributions from anyone, the RSpec project has adopted the following code of conduct. All contributors and participants (including maintainers!) are expected to abide by its terms. As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting one of the project maintainers listed at https://rspec.info/about/. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/3/0/ rspec-expectations-3.13.0/CONTRIBUTING.md000066400000000000000000000103671455770000100176550ustar00rootroot00000000000000 # Contributing RSpec is a community-driven project that has benefited from improvements from over *500* contributors. We welcome contributions from *everyone*. While contributing, please follow the project [code of conduct](CODE_OF_CONDUCT.md), so that everyone can be included. If you'd like to help make RSpec better, here are some ways you can contribute: - by running RSpec HEAD to help us catch bugs before new releases - by [reporting bugs you encounter](https://github.com/rspec/rspec-expectations/issues/new) with [report template](#report-template) - by [suggesting new features](https://github.com/rspec/rspec-expectations/issues/new) - by improving RSpec's Feature or API [documentation](https://rspec.info/documentation/) - by improving [RSpec's website](https://rspec.info/) ([source](https://github.com/rspec/rspec.github.io)) - by taking part in [feature and issue discussions](https://github.com/rspec/rspec-expectations/issues) - by adding a failing test for reproducible [reported bugs](https://github.com/rspec/rspec-expectations/issues) - by reviewing [pull requests](https://github.com/rspec/rspec-expectations/pulls) and suggesting improvements - by [writing code](DEVELOPMENT.md) (no patch is too small! fix typos or bad whitespace) If you need help getting started, check out the [DEVELOPMENT](DEVELOPMENT.md) file for steps that will get you up and running. Thanks for helping us make RSpec better! ## `Small` issues These issue are ones that we be believe are best suited for new contributors to get started with. They represent a meaningful contribution to the project that should not be too hard to pull off. ## Report template Having a way to reproduce your issue will be very helpful for others to help confirm, investigate and ultimately fix your issue. You can do this by providing an executable test case. To make this process easier, we have prepared one basic [bug report templates](REPORT_TEMPLATE.md) for you to use as a starting point. ## Maintenance branches Maintenance branches are how we manage the different supported point releases of RSpec. As such, while they might look like good candidates to merge into main, please do not open pull requests to merge them. ## Working on multiple RSpec gems at the same time RSpec is composed of multiple gems (`rspec-core`, `rspec-mocks`, etc). Sometimes you have to work on a combination of them at the same time. When submitting your code for review, we ask that you get a passing build (green CI). If you are working across the repositories, please add a commit that temporarily pins your PR to the right branch of the other repository you depend on. For example, if we wanted a change in `rspec-expectations` that relied on a change for on `rspec-mocks`. We add a commit with the title: >[WIP] Use rspec-mocks with "custom-failure-message" branch And content: ```diff diff --git a/Gemfile b/Gemfile -%w[rspec rspec-core rspec-mocks rspec-support].each do |lib| +%w[rspec rspec-core rspec-support].each do |lib| library_path = File.expand_path("../../#{lib}", __FILE__) if File.exist?(library_path) && !ENV['USE_GIT_REPOS'] gem lib, :path => library_path @@ -11,6 +11,7 @@ branch = File.read(File.expand_path("../maintenance-branch", __FILE__)).chomp gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => branch end end +gem 'rspec-mocks', :git => "https://github.com/rspec/rspec-mocks.git", :branch => "custom-failure-message" ``` In general the process is: 1. Create PRs explaining what you are trying to achieve. 2. Pin the repositories to each other. 3. Check they pass (go green). 4. Await review if appropriate. 5. Remove the commit from step 2. We will merge ignoring the failure. 6. Remove the commit from the other, check it passes with the other commit now on `main`. 7. Merge the other. 8. We will trigger builds for the `main` branch of affected repositories to check if everything is in order. Steps 5-8 should happen continuously (e.g. one after another but within a short timespan) so that we don't leave a broken main around. It is important to triage that build process and revert if necessary. rspec-expectations-3.13.0/Changelog.md000066400000000000000000001510021455770000100176250ustar00rootroot00000000000000### Development [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.3...main) ### 3.13.0 / 2024-02-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.4...v3.13.0) Enhancements: * Update `eq` and `eql` matchers to better highlight difference in string encoding. (Alan Foster, #1425) ### 3.12.4 / 2024-02-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.3...v3.12.4) Bug Fixes: * Fix the diff for redefined `actual` and reassigned `@actual` in compound expectations failure messages. (Phil Pirozhkov, #1440) ### 3.12.3 / 2023-04-20 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.2...v3.12.3) Bug Fixes: * Fix `include` matcher when fuzzy matching on keys with a hash-like actual which has a non standard `key?` method which may raise. (Jon Rowe, #1416) ### 3.12.2 / 2023-01-07 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.1...v3.12.2) Bug Fixes: * Prevent deprecation warning when using the `exist` matcher with `Dir`. (Steve Dierker, #1398) ### 3.12.1 / 2022-12-16 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.0...v3.12.1) Bug Fixes: * Pass keyword arguments through to aliased (and thus negated) matchers. (Jon Rowe, #1394) * When handling failures in an aggregated_failures block (or example) prevent the failure list leaking out. (Maciek Rząsa, #1392) ### 3.12.0 / 2022-10-26 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.1...v3.12.0) Enhancements: * Add `an_array_matching` alias for `match_array` to improve readability as an argument matcher. (Mark Schneider, #1361) ### 3.11.1 / 2022-09-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.0...v3.11.1) Bug Fixes: * Allow the `contain_exactly` matcher to be reused by resetting its internals on `matches?` (@bclayman-sq, #1326) * Using the exist matcher on `FileTest` no longer produces a deprecation warning. (Ryo Nakamura, #1383) ### 3.11.0 / 2022-02-09 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.2...v3.11.0) Enhancements: * Return `true` from `aggregate_failures` when no exception occurs. (Jon Rowe, #1225) Deprecations: * Print a deprecation message when using the implicit block expectation syntax. (Phil Pirozhkov, #1139) ### 3.10.2 / 2022-01-14 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.1...v3.10.2) Bug Fixes: * Fix support for dynamic matchers for expectation target checks (Phil Pirozhkov, #1294) * Fix `expect(array).to include(hash).times`, previously this would fail due to matching the entire array as a single hash, rather than a member of the hash. (Slava Kardakov, #1322) * Ensure `raise_error` matches works with the `error_highlight` option from Ruby 3.1. (Peter Goldstein, #1339) ### 3.10.1 / 2020-12-27 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.0...v3.10.1) Bug Fixes: * Allow JRuby 9.2.x.x to generate backtraces normally rather than via our backfill workaround. (#1230, Jon Rowe) ### 3.10.0 / 2020-10-30 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.3...v3.10.0) Enhancements: * Allow `include` matcher to be chained with `once`, `at_least`, etc. for simple cases. (Marc-André Lafortune, #1168) * Add an explicit warning when `nil` is passed to `raise_error`. (Phil Pirozhkov, #1143) * Improve `include` matcher's composability. (Phil Pirozhkov, #1155) * Mocks expectations can now set a custom failure message. (Benoit Tigeot and Nicolas Zermati, #1156) * `aggregate_failures` now shows the backtrace line for each failure. (Fabricio Bedin, #1163) * Support multiple combinations of `yield_control` modifiers like `at_least`, `at_most`. (Jon Rowe, #1169) * Dynamic `have_` matchers now have output consistent with other dynamic matchers. (Marc-André Lafortune, #1195) * New config option `strict_predicate_matchers` allows predicate matcher to be strict (i.e. match for `true` or `false`) instead of the default (match truthy vs `false` or `nil`). (Marc-André Lafortune, #1196) ### 3.9.4 / 2020-10-29 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.3...v3.9.4) Bug Fixes: * Fix regression with `be_` and `have_` matchers and arguments implementing `to_hash` were they would act like keywords and be cast to a hash. (Jon Rowe, #1222) ### 3.9.3 / 2020-10-23 Bug Fixes: * Swap the comparison of the delta vs the expected for the `be_within` matcher allowing more complicated oobjects to be compared providing they provide `abs` and other comparison methods. (Kelly Stannard, #1182) * Properly format expected in the description of the `be_within` matcher. (Jon Rowe, #1185) * Remove warning when using keyword arguments with `be_` and `have_` matchers on 2.7.x (Jon Rowe, #1187) * Prevent formatting a single hash as a list of key value pairs in default failure messages for custom matches (fixes formatting in `EnglishPhrasing#list`). (Robert Eshleman, #1193) * Prevent errors from causing false positives when using `be ` comparison, e.g. `expect(1).not_to be < 'a'` will now correctly fail rather than pass. (Jon Rowe, #1208) ### 3.9.2 / 2020-05-08 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.1...v3.9.2) Bug Fixes: * Issue a proper `ArgumentError` when invalid arguments are given to `yield_control` modifiers such as `at_least` et al. (Marc-André Lafortune, #1167) * Prevent Ruby 2.7 keyword arguments warning from being issued by custom matcher definitions. (Jon Rowe, #1176) ### 3.9.1 / 2020-03-13 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.9.0...v3.9.1) Bug Fixes: * Issue an improved warning when using `respond_to(...).with(n).arguments` and ignore the warning when using with `have_attributes(...)`. (Jon Rowe, #1164) ### 3.9.0 / 2019-10-08 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.6...v3.9.0) Enhancements: * The `respond_to` matcher now uses the signature from `initialize` to validate checks for `new` (unless `new` is non standard). (Jon Rowe, #1072) * Generated descriptions for matchers now use `is expected to` rather than `should` in line with our preferred DSL. (Pete Johns, #1080, rspec/rspec-core#2572) * Add the ability to re-raise expectation errors when matching with `match_when_negated` blocks. (Jon Rowe, #1130) * Add a warning when an empty diff is produce due to identical inspect output. (Benoit Tigeot, #1126) ### 3.8.6 / 2019-10-07 Bug Fixes: * Revert #1125 due to the change being incompatible with our semantic versioning policy. ### 3.8.5 / 2019-10-02 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.4...v3.8.5) Bug Fixes: * Prevent unsupported implicit block expectation syntax from being used. (Phil Pirozhkov, #1125) ### 3.8.4 / 2019-06-10 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.3...v3.8.4) Bug Fixes: * Prevent false negatives when checking objects for the methods required to run the the `be_an_instance_of` and `be_kind_of` matchers. (Nazar Matus, #1112) ### 3.8.3 / 2019-04-20 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.2...v3.8.3) Bug Fixes: * Prevent composed `all` matchers from leaking into their siblings leading to duplicate failures. (Jamie English, #1086) * Prevent objects which change their hash on comparison from failing change checks. (Phil Pirozhkov, #1100) * Issue an `ArgumentError` rather than a `NoMethodError` when `be_an_instance_of` and `be_kind_of` matchers encounter objects not supporting those methods. (Taichi Ishitani, #1107) ### 3.8.2 / 2018-10-09 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.1...v3.8.2) Bug Fixes: * Change `include` matcher to rely on a `respond_to?(:include?)` check rather than a direct Hash comparison before calling `to_hash` to convert to a hash. (Jordan Owens, #1073) * Prevent unexpected call stack jumps from causing an obscure error (`IndexError`), and replace that error with a proper informative message. (Jon Rowe, #1076) ### 3.8.1 / 2018-08-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.8.0...v3.8.1) Bug Fixes: * Fix regression in `include` matcher so stopped `expect(hash.with_indifferent_access).to include(:symbol_key)` from working. (Eito Katagiri, #1069) ### 3.8.0 / 2018-08-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.7.0...v3.8.0) Enhancements: * Improve failure message of `change(receiver, :message)` by including the receiver as `SomeClass#some_message`. (Tomohiro Hashidate, #1005) * Improve `change` matcher so that it can correctly detect changes in deeply nested mutable objects (such as arrays-of-hashes-of-arrays). The improved logic uses the before/after `hash` value to see if the object has been mutated, rather than shallow duping the object. (Myron Marston, #1034) * Improve `include` matcher so that pseudo-hash objects (e.g. objects that decorate a hash using a `SimpleDelegator` or similar) are treated as a hash, as long as they implement `to_hash`. (Pablo Brasero, #1012) * Add `max_formatted_output_length=` to configuration, allowing changing the length at which we truncate large output strings. (Sam Phippen #951, Benoit Tigeot #1056) * Improve error message when passing a matcher that doesn't support block expectations to a block based `expect`. (@nicktime, #1066) ### 3.7.0 / 2017-10-17 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.6.0...v3.7.0) Enhancements: * Improve compatibility with `--enable-frozen-string-literal` option on Ruby 2.3+. (Pat Allan, #997) ### 3.6.0 / 2017-05-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.6.0.beta2...v3.6.0) Enhancements: * Treat NoMethodError as a failure for comparison matchers. (Jon Rowe, #972) * Allow for scoped aliased and negated matchers--just call `alias_matcher` or `define_negated_matcher` from within an example group. (Markus Reiter, #974) * Improve failure message of `change` matcher with block and `satisfy` matcher by including the block snippet instead of just describing it as `result` or `block` when Ripper is available. (Yuji Nakayama, #987) Bug Fixes: * Fix `yield_with_args` and `yield_successive_args` matchers so that they compare expected to actual args at the time the args are yielded instead of at the end, in case the method that is yielding mutates the arguments after yielding. (Alyssa Ross, #965) ### 3.6.0.beta2 / 2016-12-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.6.0.beta1...v3.6.0.beta2) Bug Fixes: * Using the exist matcher on `File` no longer produces a deprecation warning. (Jon Rowe, #954) ### 3.6.0.beta1 / 2016-10-09 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.5.0...v3.6.0.beta1) Bug Fixes: * Fix `contain_exactly` to work correctly with ranges. (Myron Marston, #940) * Fix `change` to work correctly with sets. (Marcin Gajewski, #939) ### 3.5.0 / 2016-07-01 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.5.0.beta4...v3.5.0) Enhancements: * Add support for keyword arguments to the `respond_to` matcher. (Rob Smith, #915). ### 3.5.0.beta4 / 2016-06-05 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.5.0.beta3...v3.5.0.beta4) Bug Fixes: * Fix `include` matcher so that it provides a valid diff for hashes. (Yuji Nakayama, #916) ### 3.5.0.beta3 / 2016-04-02 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.5.0.beta2...v3.5.0.beta3) Enhancements: * Make `rspec/expectations/minitest_integration` work on Minitest::Spec 5.6+. (Myron Marston, #904) * Add an alias `having_attributes` for `have_attributes` matcher. (Yuji Nakayama, #905) * Improve `change` matcher error message when block is mis-used. (Alex Altair, #908) ### 3.5.0.beta2 / 2016-03-10 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.5.0.beta1...v3.5.0.beta2) Enhancements: * Add the ability to raise an error on encountering false positives via `RSpec::Configuration#on_potential_false_positives = :raise`. (Jon Rowe, #900) * When using the custom matcher DSL, support new `notify_expectation_failures: true` option for the `match` method to allow expectation failures to be raised as normal instead of being converted into a `false` return value for `matches?`. (Jon Rowe, #892) Bug Fixes: * Allow `should` deprecation check to work on `BasicObject`s. (James Coleman, #898) ### 3.5.0.beta1 / 2016-02-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.4.0...v3.5.0.beta1) Enhancements: * Make `match_when_negated` in custom matcher DSL support use of expectations within the match logic. (Chris Arcand, #789) Bug Fixes: * Return `true` as expected from passing negated expectations (such as `expect("foo").not_to eq "bar"`), so they work properly when used within a `match` or `match_when_negated` block. (Chris Arcand, #789) ### 3.4.0 / 2015-11-11 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.1...v3.4.0) Enhancements: * Warn when `RSpec::Matchers` is included in a superclass after it has already been included in a subclass on MRI 1.9, since that situation can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816) * Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845) * Add `#with_captures` to the match matcher which allows a user to specify expected captures when matching a regex against a string. (Sam Phippen, #848) * Always print compound failure messages in the multi-line form. Trying to print it all on a single line didn't read very well. (Myron Marston, #859) Bug Fixes: * Fix failure message from dynamic predicate matchers when the object does not respond to the predicate so that it is inspected rather than relying upon its `to_s` -- that way for `nil`, `"nil"` is printed rather than an empty string. (Myron Marston, #841) * Fix SystemStackError raised when diffing an Enumerable object whose `#each` includes the object itself. (Yuji Nakayama, #857) ### 3.3.1 / 2015-07-15 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.0...v3.3.1) Bug Fixes: * Fix `be >`, `be <`, etc so that it fails rather than allowing an argument error to be raised when compared against an object of the wrong type. This allows it to be used in composed matcher expressions against heterogeneous objects. (Dennis Günnewig, #809) * Fix `respond_to` to work properly on target objects that redefine the `method` method. (unmanbearpig, #821) ### 3.3.0 / 2015-06-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.2.1...v3.3.0) Enhancements: * Expose `RSpec::Matchers::EnglishPhrasing` to make it easier to write nice failure messages in custom matchers. (Jared Beck, #736) * Add `RSpec::Matchers::FailMatchers`, a mixin which provides `fail`, `fail_with` and `fail_including` matchers for use in specifying that an expectation fails for use by extension/plugin authors. (Charlie Rudolph, #729) * Avoid loading `tempfile` (and its dependencies) unless it is absolutely needed. (Myron Marston, #735) * Improve failure output when attempting to use `be_true` or `be_false`. (Tim Wade, #744) * Define `RSpec::Matchers#respond_to_missing?` so that `RSpec::Matchers#respond_to?` and `RSpec::Matchers#method` handle dynamic predicate matchers. (Andrei Botalov, #751) * Use custom Time/DateTime/BigDecimal formatting for all matchers so they are consistently represented in failure messages. (Gavin Miller, #740) * Add configuration to turn off warnings about matcher combinations that may cause false positives. (Jon Rowe, #768) * Warn when using a bare `raise_error` matcher that you may be subject to false positives. (Jon Rowe, #768) * Warn rather than raise when using the`raise_error` matcher in negative expectations that may be subject to false positives. (Jon Rowe, #775) * Improve failure message for `include(a, b, c)` so that if `a` and `b` are included the failure message only mentions `c`. (Chris Arcand, #780) * Allow `satisfy` matcher to take an optional description argument that will be used in the `description`, `failure_message` and `failure_message_when_negated` in place of the undescriptive "sastify block". (Chris Arcand, #783) * Add new `aggregate_failures` API that allows multiple independent expectations to all fail and be listed in the failure output, rather than the example aborting on the first failure. (Myron Marston, #776) * Improve `raise_error` matcher so that it can accept a matcher as a single argument that matches the message. (Time Wade, #782) Bug Fixes: * Make `contain_exactly` / `match_array` work with strict test doubles that have not defined `<=>`. (Myron Marston, #758) * Fix `include` matcher so that it omits the diff when it would confusingly highlight items that are actually included but are not an exact match in a line-by-line diff. (Tim Wade, #763) * Fix `match` matcher so that it does not blow up when matching a string or regex against another matcher (rather than a string or regex). (Myron Marston, #772) * Silence whitespace-only diffs. (Myron Marston, #801) ### 3.2.1 / 2015-04-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.2.0...v3.2.1) Bug Fixes: * Prevent `Range`s from being enumerated when generating matcher descriptions. (Jon Rowe, #755) * Ensure exception messages are compared as strings in the `raise_error` matcher. (Jon Rowe, #755) ### 3.2.0 / 2015-02-03 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.1.2...v3.2.0) Enhancements: * Add `block_arg` method to custom matcher API, which allows you to access the block passed to a custom matcher, if there is one. (Mike Dalton, #645) * Provide more detail in failure message of `yield_control` matcher. (Jon Rowe, #650) * Add a shorthand syntax for `chain` in the matcher DSL which assigns values for use elsewhere, for example `chain :and_smaller_than, :small_value` creates an `attr_reader` for `small_value` (Tom Stuart, #644) * Provide a more helpful deprecation message when using the `should` syntax. (Elia Schito, #663) * Provide more detail in the `have_attributes` matcher failure message. (Jon Rowe, #668) * Make the `have_attributes` matcher diffable. (Jon Rowe, Alexey Fedorov, #668) * Add `output(...).to_std(out|err)_from_any_process` as alternatives to `output(...).to_std(out|err)`. The latter doesn't work when a sub process writes to the named stream but is much faster. (Alex Genco, #700) * Improve compound matchers (created by `and` and `or`) so that diffs are included in failures when one or more of their matchers are diffable. (Alexey Fedorov, #713) Bug Fixes: * Avoid calling `private_methods` from the `be` predicate matcher on the target object if the object publicly responds to the predicate method. This avoids a possible error that can occur if the object raises errors from `private_methods` (which can happen with celluloid objects). (@chapmajs, #670) * Make `yield_control` (with no modifier) default to `at_least(:once)` rather than raising a confusing error when multiple yields are encountered. (Myron Marston, #675) * Fix "instance variable @color not initialized" warning when using rspec-expectations outside of an rspec-core context. (Myron Marston, #689) * Fix `start_with` and `end_with` to work properly when checking a string against an array of strings. (Myron Marston, #690) * Don't use internally delegated matchers when generating descriptions for examples without doc strings. (Myron Marston, #692) ### 3.1.2 / 2014-09-26 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.1.1...v3.1.2) Bug Fixes: * Fix `define_negated_matcher` so that matchers that support fluent interfaces continue to be negated after you use the chained method. (Myron Marston, #656) * Fix `define_negated_matcher` so that the matchers fail with an appropriate failure message. (Myron Marston, #659) ### 3.1.1 / 2014-09-15 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.1.0...v3.1.1) Bug Fixes: * Fix regression in `all` matcher in 3.1.0 that prevented it from working on objects that are not `Enumerable` but do implement `each_with_index` (such as an ActiveRecord proxy). (Jori Hardman, #647) ### 3.1.0 / 2014-09-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.4...v3.1.0) Enhancements: * Add `have_attributes` matcher, that passes if actual's attribute values match the expected attributes hash: `Person = Struct.new(:name, :age)` `person = Person.new("Bob", 32)` `expect(person).to have_attributes(:name => "Bob", :age => 32)`. (Adam Farhi, #571) * Extended compound matcher support to block matchers, for cases like: `expect { ... }.to change { x }.to(3).and change { y }.to(4)`. (Myron Marston, #567) * Include chained methods in custom matcher description and failure message when new `include_chain_clauses_in_custom_matcher_descriptions` config option is enabled. (Dan Oved, #600) * Add `thrice` modifier to `yield_control` matcher as a synonym for `exactly(3).times`. (Dennis Taylor, #615) * Add `RSpec::Matchers.define_negated_matcher`, which defines a negated version of the named matcher. (Adam Farhi, Myron Marston, #618) * Document and support negation of `contain_exactly`/`match_array`. (Jon Rowe, #626). Bug Fixes: * Rename private `LegacyMacherAdapter` constant to `LegacyMatcherAdapter` to fix typo. (Abdelkader Boudih, #563) * Fix `all` matcher so that it fails properly (rather than raising a `NoMethodError`) when matched against a non-enumerable. (Hao Su, #622) ### 3.0.4 / 2014-08-14 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.3...v3.0.4) Bug Fixes: * Fix `start_with` and `end_with` so that they work properly with structs. (Myron Marston, #620) * Fix failure message generation so that structs are printed properly in failures. Previously failure messages would represent them as an array. (Myron Marston, #620) * Fix composable matcher support so that it does not wrongly treat structs as arrays. (Myron Marston, #620) ### 3.0.3 / 2014-07-21 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.2...v3.0.3) Bug Fixes: * Fix issue with detection of generic operator matchers so they work correctly when undefined. (Myron Marston, #597) * Don't inadvertently define `BasicObject` in 1.8.7. (Chris Griego, #603) * Fix `include` matcher so that it fails gracefully when matched against an object that does not respond to `include?`. (Myron Marston, #607) ### 3.0.2 / 2014-06-19 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.1...v3.0.2) Bug Fixes: * Fix regression in `contain_exactly` (AKA `match_array`) that caused it to wrongly pass when the expected array was empty. (Myron Marston, #581) * Provide a better error message when you use the `change(obj, :msg)` form of the change matcher but forget the message argument. (Alex Sunderland, #585) * Make the `contain_exactly` matcher work with arrays that contain hashes in arbitrary ordering. (Sam Phippen, #578) ### 3.0.1 / 2014-06-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.0...v3.0.1) Bug Fixes: * Add a missing `require` that would cause the `respond_to` matcher to fail when used in a project where the rest of RSpec (e.g. core and expecatations) weren't being used. (Myron Marston, #566) * Structs are no longer treated as arrays when diffed. (Jon Rowe, #576) ### 3.0.0 / 2014-06-01 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.0.rc1...v3.0.0) No code changes. Just taking it out of pre-release. ### 3.0.0.rc1 / 2014-05-18 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.0.beta2...v3.0.0.rc1) Breaking Changes for 3.0.0: * Remove `matcher_execution_context` attribute from DSL-defined custom matchers. (Myron Marston) * Remove `RSpec::Matchers::Pretty#_pretty_print`. (Myron Marston) * Remove `RSpec::Matchers::Pretty#expected_to_sentence`. (Myron Marston) * Rename `RSpec::Matchers::Configuration` constant to `RSpec::Expectations::Configuration`. (Myron Marston) * Prevent `have_xyz` predicate matchers using private methods. (Adrian Gonzalez) * Block matchers must now implement `supports_block_expectations?`. (Myron Marston) * Stop supporting `require 'rspec-expectations'`. Use `require 'rspec/expectations'` instead. (Myron Marston) Bug Fixes: * Fix `NoMethodError` triggered by beta2 when `YARD` was loaded in the test environment. (Myron Marston) * Fix `be_xyz` matcher to accept a `do...end` block. (Myron Marston) * Fix composable matcher failure message generation logic so that it does not blow up when given `$stdout` or `$stderr`. (Myron Marston) * Fix `change` matcher to work properly with `IO` objects. (Myron Marston) * Fix `exist` matcher so that it can be used in composed matcher expressions involving objects that do not implement `exist?` or `exists?`. (Daniel Fone) * Fix composable matcher match logic so that it clones matchers before using them in order to work properly with matchers that use internal memoization based on a given `actual` value. (Myron Marston) * Fix `be_xyz` and `has_xyz` predicate matchers so that they can be used in composed matcher expressions involving objects that do not implement the predicate method. (Daniel Fone) Enhancements: * Document the remaining public APIs. rspec-expectations now has 100% of the public API documented and will remain that way (as new undocumented methods will fail the build). (Myron Marston) * Improve the formatting of BigDecimal objects in `eq` matcher failure messages. (Daniel Fone) * Improve the failure message for `be_xyz` predicate matchers so that it includes the `inspect` output of the receiver. (Erik Michaels-Ober, Sam Phippen) * Add `all` matcher, to allow you to specify that a given matcher matches all elements in a collection: `expect([1, 3, 5]).to all( be_odd )`. (Adam Farhi) * Add boolean aliases (`&`/`|`) for compound operators (`and`/`or`). (Adam Farhi) * Give users a clear error when they wrongly use a value matcher in a block expectation expression (e.g. `expect { 3 }.to eq(3)`) or vice versa. (Myron Marston) ### 3.0.0.beta2 / 2014-02-17 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.0.0.beta1...v3.0.0.beta2) Breaking Changes for 3.0.0: * Remove deprecated support for accessing the `RSpec` constant using `Rspec` or `Spec`. (Myron Marston) * Remove deprecated `RSpec::Expectations.differ=`. (Myron Marston) * Remove support for deprecated `expect(...).should`. (Myron Marston) * Explicitly disallow `expect { }.not_to change { }` with `by`, `by_at_least`, `by_at_most` or `to`. These have never been supported but did not raise explicit errors. (Myron Marston) * Provide `===` rather than `==` as an alias of `matches?` for all matchers. The semantics of `===` are closer to an RSpec matcher than `==`. (Myron Marston) * Remove deprecated `RSpec::Matchers::OperatorMatcher` constant. (Myron Marston) * Make `RSpec::Expectations::ExpectationNotMetError` subclass `Exception` rather than `StandardError` so they can bypass a bare `rescue` in end-user code (e.g. when an expectation is set from within a rspec-mocks stub implementation). (Myron Marston) * Remove Test::Unit and Minitest 4.x integration. (Myron Marston) Enhancements: * Simplify the failure message of the `be` matcher when matching against: `true`, `false` and `nil`. (Sam Phippen) * Update matcher protocol and custom matcher DSL to better align with the newer `expect` syntax. If you want your matchers to maintain compatibility with multiple versions of RSpec, you can alias the new names to the old. (Myron Marston) * `failure_message_for_should` => `failure_message` * `failure_message_for_should_not` => `failure_message_when_negated` * `match_for_should` => `match` * `match_for_should_not` => `match_when_negated` * Improve generated descriptions from `change` matcher. (Myron Marston) * Add support for compound matcher expressions using `and` and `or`. Simply chain them off of any existing matcher to create an expression like `expect(alphabet).to start_with("a").and end_with("z")`. (Eloy Espinaco) * Add `contain_exactly` as a less ambiguous version of `match_array`. Note that it expects the expected array to be splatted as individual args: `expect(array).to contain_exactly(1, 2)` is the same as `expect(array).to match_array([1, 2])`. (Myron Marston) * Update `contain_exactly`/`match_array` so that it can match against other non-array collections (such as a `Set`). (Myron Marston) * Update built-in matchers so that they can accept matchers as arguments to allow you to compose matchers in arbitrary ways. (Myron Marston) * Add `RSpec::Matchers::Composable` mixin that can be used to make a custom matcher composable as well. Note that custom matchers defined via `RSpec::Matchers.define` already have this. (Myron Marston) * Define noun-phrase aliases for built-in matchers, which can be used when creating composed matcher expressions that read better and provide better failure messages. (Myron Marston) * Add `RSpec::Matchers.alias_matcher` so users can define their own matcher aliases. The `description` of the matcher will reflect the alternate matcher name. (Myron Marston) * Add explicit `be_between` matcher. `be_between` has worked for a long time as a dynamic predicate matcher, but the failure message was suboptimal. The new matcher provides a much better failure message. (Erik Michaels-Ober) * Enhance the `be_between` matcher to allow for `inclusive` or `exclusive` comparison (e.g. inclusive of min/max or exclusive of min/max). (Pedro Gimenez) * Make failure message for `not_to be #{operator}` less confusing by only saying it's confusing when comparison operators are used. (Prathamesh Sonpatki) * Improve failure message of `eq` matcher when `Time` or `DateTime` objects are used so that the full sub-second precision is included. (Thomas Holmes, Jeff Wallace) * Add `output` matcher for expecting that a block outputs `to_stdout` or `to_stderr`. (Luca Pette, Matthias Günther) * Forward a provided block on to the `has_xyz?` method call when the `have_xyz` matcher is used. (Damian Galarza) * Provide integration with Minitest 5.x. Require `rspec/expectations/minitest_integration` after loading minitest to use rspec-expectations with minitest. (Myron Marston) Bug Fixes: * Fix wrong matcher descriptions with falsey expected value (yujinakayama) * Fix `expect { }.not_to change { }.from(x)` so that the matcher only passes if the starting value is `x`. (Tyler Rick, Myron Marston) * Fix hash diffing, so that it colorizes properly and doesn't consider trailing commas when performing the diff. (Jared Norman) * Fix built-in matchers to fail normally rather than raising `ArgumentError` when given an object of the wrong type to match against, so that they work well in composite matcher expressions like `expect([1.51, "foo"]).to include(a_string_matching(/foo/), a_value_within(0.1).of(1.5))`. (Myron Marston) Deprecations: * Retain support for RSpec 2 matcher protocol (e.g. for matchers in 3rd party extension gems like `shoulda`), but it will print a deprecation warning. (Myron Marston) ### 3.0.0.beta1 / 2013-11-07 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.2...v3.0.0.beta1) Breaking Changes for 3.0.0: * Remove explicit support for 1.8.6. (Jon Rowe) * Remove the deprecated `be_close` matcher, preferring `be_within` instead. (Sam Phippen) * Remove the deprecated `have`, `have_at_least` and `have_at_most` matchers. You can continue using those matchers through https://github.com/rspec/rspec-collection_matchers, or you can rewrite your expectations with something like `expect(your_object.size).to eq(num)`. (Hugo Baraúna) * Rename `be_true` and `be_false` to `be_truthy` and `be_falsey`. (Sam Phippen) * Make `expect { }.to_not raise_error(SomeSpecificClass, message)`, `expect { }.to_not raise_error(SomeSpecificClass)` and `expect { }.to_not raise_error(message)` invalid, since they are prone to hiding failures. Instead, use `expect { }.to_not raise_error` (with no args). (Sam Phippen) * Within `RSpec::Matchers.define` blocks, helper methods made available either via `def self.helper` or `extend HelperModule` are no longer available to the `match` block (or any of the others). Instead `include` your helper module and define the helper method as an instance method. (Myron Marston) * Force upgrading Diff::LCS for encoding compatability with diffs. (Jon Rowe) Enhancements: * Support `do..end` style block with `raise_error` matcher. (Yuji Nakayama) * Rewrote custom matcher DSL to simplify its implementation and solve a few issues. (Myron Marston) * Allow early `return` from within custom matcher DSL blocks. (Myron Marston) * The custom matcher DSL's `chain` can now accept a block. (Myron Marston) * Support setting an expectation on a `raise_error` matcher via a chained `with_message` method call. (Sam Phippen) Bug Fixes: * Allow `include` and `match` matchers to be used from within a DSL-defined custom matcher's `match` block. (Myron Marston) * Correct encoding error message on diff failure (Jon Rowe) Deprecations: * Using the old `:should` syntax without explicitly configuring it is deprecated. It will continue to work but will emit a deprecation warning in RSpec 3 if you do not explicitly enable it. (Sam Phippen) ### 2.99.2 / 2014-07-21 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.1...v2.99.2) Bug Fixes: * Fix regression in `Expectations#method_handle_for` where proxy objects with method delegated would wrongly not return a method handle. (Jon Rowe, #594) * Fix issue with detection of generic operator matchers so they work correctly when undefined. (Myron Marston, #597) ### 2.99.1 / 2014-06-19 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.0...v2.99.1) Bug Fixes: * Fix typo in custom matcher `expected` deprecation warning -- it's `expected_as_array`, not `expected_array`. (Frederick Cheung, #562) ### 2.99.0 / 2014-06-01 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.0.rc1...v2.99.0) Enhancements: * Special case deprecation message for `errors_on` with `rspec-rails` to be more useful. (Aaron Kromer) ### 2.99.0.rc1 / 2014-05-18 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.0.beta2...2.99.0.rc1) Deprecations: * Deprecate `matcher_execution_context` attribute on DSL-defined custom matchers. (Myron Marston) * Deprecate `RSpec::Matchers::Pretty#_pretty_print`. (Myron Marston) * Deprecate `RSpec::Matchers::Pretty#expected_to_sentence`. (Myron Marston) * Deprecate `RSpec::Matchers::Configuration` in favor of `RSpec::Expectations::Configuration`. (Myron Marston) * Deprecate `be_xyz` predicate matcher on an object that doesn't respond to `xyz?` or `xyzs?`. (Daniel Fone) * Deprecate `have_xyz` matcher on an object that doesn't respond to `has_xyz?`. (Daniel Fone) * Deprecate `have_xyz` matcher on an object that has a private method `has_xyz?`. (Jon Rowe) * Issue a deprecation warning when a block expectation expression is used with a matcher that doesn't explicitly support block expectations via `supports_block_expectations?`. (Myron Marston) * Deprecate `require 'rspec-expectations'`. Use `require 'rspec/expectations'` instead. (Myron Marston) ### 2.99.0.beta2 / 2014-02-17 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.99.0.beta1...v2.99.0.beta2) Deprecations: * Deprecate chaining `by`, `by_at_least`, `by_at_most` or `to` off of `expect { }.not_to change { }`. The docs have always said these are not supported for the negative form but now they explicitly raise errors in RSpec 3. (Myron Marston) * Change the semantics of `expect { }.not_to change { x }.from(y)`. In RSpec 2.x, this expectation would only fail if `x` started with the value of `y` and changed. If it started with a different value and changed, it would pass. In RSpec 3, it will pass only if the value starts at `y` and it does not change. (Myron Marston) * Deprecate `matcher == value` as an alias for `matcher.matches?(value)`, in favor of `matcher === value`. (Myron Marston) * Deprecate `RSpec::Matchers::OperatorMatcher` in favor of `RSpec::Matchers::BuiltIn::OperatorMatcher`. (Myron Marston) * Deprecate auto-integration with Test::Unit and minitest. Instead, include `RSpec::Matchers` in the appropriate test case base class yourself. (Myron Marston) * Deprecate treating `#expected` on a DSL-generated custom matcher as an array when only 1 argument is passed to the matcher method. In RSpec 3 it will be the single value in order to make diffs work properly. (Jon Rowe) ### 2.99.0.beta1 / 2013-11-07 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.4...v2.99.0.beta1) Deprecations * Deprecate `have`, `have_at_least` and `have_at_most`. You can continue using those matchers through https://github.com/rspec/rspec-collection_matchers, or you can rewrite your expectations with something like `expect(your_object.size).to eq(num)`. (Hugo Baraúna) * Deprecate `be_xyz` predicate matcher when `xyz?` is a private method. (Jon Rowe) * Deprecate `be_true`/`be_false` in favour of `be_truthy`/`be_falsey` (for Ruby's conditional semantics) or `be true`/`be false` (for exact equality). (Sam Phippen) * Deprecate calling helper methods from a custom matcher with the wrong scope. (Myron Marston) * `def self.foo` / `extend Helper` can be used to add macro methods (e.g. methods that call the custom matcher DSL methods), but should not be used to define helper methods called from within the DSL blocks. * `def foo` / `include Helper` is the opposite: it's for helper methods callable from within a DSL block, but not for defining macros. * RSpec 2.x allowed helper methods defined either way to be used for either purpose, but RSpec 3.0 will not. ### 2.14.5 / 2014-02-01 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.4...v2.14.5) Bug fixes * Fix wrong matcher descriptions with falsey expected value (yujinakayama) ### 2.14.4 / 2013-11-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.3...v2.14.4) Bug fixes * Make the `match` matcher produce a diff output. (Jon Rowe, Ben Moss) * Choose encoding for diff's more intelligently, and when all else fails fall back to default internal encoding with replacing characters. (Jon Rowe) ### 2.14.3 / 2013-09-22 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.2...v2.14.3) Bug fixes * Fix operator matchers (`should` syntax) when `method` is redefined on target. (Brandon Turner) * Fix diffing of hashes with object based keys. (Jon Rowe) * Fix operator matchers (`should` syntax) when operator is defined via `method_missing` (Jon Rowe) ### 2.14.2 / 2013-08-14 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.1...v2.14.2) Bug fixes * Fix `be_` matcher to not support operator chaining like the `be` matcher does (e.g. `be == 5`). This led to some odd behaviors since `be_ == anything` returned a `BeComparedTo` matcher and was thus always truthy. This was a consequence of the implementation (e.g. subclassing the basic `Be` matcher) and was not intended behavior. (Myron Marston). * Fix `change` matcher to compare using `==` in addition to `===`. This is important for an expression like: `expect {}.to change { a.class }.from(ClassA).to(ClassB)` because `SomeClass === SomeClass` returns false. (Myron Marston) ### 2.14.1 / 2013-08-08 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.0...2.14.1) Bug fixes * Ensure diff output uses the same encoding as the encoding of the string being diff'd to prevent `Encoding::UndefinedConversionError` errors (Jon Rowe). ### 2.14.0 / 2013-07-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.14.0.rc1...v2.14.0) Bug fixes * Values that are not matchers use `#inspect`, rather than `#description` for documentation output (Andy Lindeman, Sam Phippen). * Make `expect(a).to be_within(x).percent_of(y)` work with negative y (Katsuhiko Nishimra). * Make the `be_predicate` matcher work as expected used with `expect{...}.to change...` (Sam Phippen). ### 2.14.0.rc1 / 2013-05-27 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.13.0...v2.14.0.rc1) Enhancements * Enhance `yield_control` so that you can specify an exact or relative number of times: `expect { }.to yield_control.exactly(3).times`, `expect { }.to yield_control.at_least(2).times`, etc (Bartek Borkowski). * Make the differ that is used when an expectation fails better handle arrays by splitting each element of the array onto its own line. (Sam Phippen) * Accept duck-typed strings that respond to `:to_str` as expectation messages. (Toby Ovod-Everett) Bug fixes * Fix differ to not raise errors when dealing with differently-encoded strings (Jon Rowe). * Fix `expect(something).to be_within(x).percent_of(y)` where x and y are both integers (Sam Phippen). * Fix `have` matcher to handle the fact that on ruby 2.0, `Enumerator#size` may return nil (Kenta Murata). * Fix `expect { raise s }.to raise_error(s)` where s is an error instance on ruby 2.0 (Sam Phippen). * Fix `expect(object).to raise_error` passing. This now warns the user and fails the spec (tomykaira). Deprecations * Deprecate `expect { }.not_to raise_error(SpecificErrorClass)` or `expect { }.not_to raise_error("some specific message")`. Using these was prone to hiding failures as they would allow _any other error_ to pass. (Sam Phippen and David Chelimsky) ### 2.13.0 / 2013-02-23 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.12.1...v2.13.0) Enhancements * Add support for percent deltas to `be_within` matcher: `expect(value).to be_within(10).percent_of(expected)` (Myron Marston). * Add support to `include` matcher to allow it to be given a list of matchers as the expecteds to match against (Luke Redpath). Bug fixes * Fix `change` matcher so that it dups strings in order to handle mutated strings (Myron Marston). * Fix `should be =~ /some regex/` / `expect(...).to be =~ /some regex/`. Previously, these either failed with a confusing `undefined method matches?' for false:FalseClass` error or were no-ops that didn't actually verify anything (Myron Marston). * Add compatibility for diff-lcs 1.2 and relax the version constraint (Peter Goldstein). * Fix DSL-generated matchers to allow multiple instances of the same matcher in the same example to have different description and failure messages based on the expected value (Myron Marston). * Prevent `undefined method #split for Array` error when dumping the diff of an array of multiline strings (Myron Marston). * Don't blow up when comparing strings that are in an encoding that is not ASCII compatible (Myron Marston). * Remove confusing "Check the implementation of #==" message printed for empty diffs (Myron Marston). ### 2.12.1 / 2012-12-15 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.12.0...v2.12.1) Bug fixes * Improve the failure message for an expression like `{}.should =~ {}`. (Myron Marston and Andy Lindeman) * Provide a `match_regex` alias so that custom matchers built using the matcher DSL can use it (since `match` is a different method in that context). (Steven Harman) ### 2.12.0 / 2012-11-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.11.3...v2.12.0) Enhancements * Colorize diffs if the `--color` option is configured. (Alex Coplan) * Include backtraces in unexpected errors handled by `raise_error` matcher (Myron Marston) * Print a warning when users accidentally pass a non-string argument as an expectation message (Sam Phippen) * `=~` and `match_array` matchers output a more useful error message when the actual value is not an array (or an object that responds to `#to_ary`) (Sam Phippen) Bug fixes * Fix `include` matcher so that `expect({}).to include(:a => nil)` fails as it should (Sam Phippen). * Fix `be_an_instance_of` matcher so that `Class#to_s` is used in the description rather than `Class#inspect`, since some classes (like `ActiveRecord::Base`) define a long, verbose `#inspect`. (Tom Stuart) ### 2.11.3 / 2012-09-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.11.2...v2.11.3) Bug fixes * Fix (and deprecate) `expect { }.should` syntax so that it works even though it was never a documented or intended syntax. It worked as a consequence of the implementation of `expect` in RSpec 2.10 and earlier. (Myron Marston) * Ensure #== is defined on built in matchers so that they can be composed. For example: expect { user.emailed! }.to change { user.last_emailed_at }.to be_within(1.second).of(Time.zone.now) ### 2.11.2 / 2012-07-25 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.11.1...v2.11.2) Bug fixes * Define `should` and `should_not` on `Object` rather than `BasicObject` on MacRuby. On MacRuby, `BasicObject` is defined but is not the root of the object hierarchy. (Gabriel Gilder) ### 2.11.1 / 2012-07-08 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.11.0...v2.11.1) Bug fixes * Constrain `actual` in `be_within` matcher to values that respond to `-` instead of requiring a specific type. * `Time`, for example, is a legit alternative. ### 2.11.0 / 2012-07-07 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.10.0...v2.11.0) Enhancements * Expand `expect` syntax so that it supports expections on bare values in addition to blocks (Myron Marston). * Add configuration options to control available expectation syntaxes (Myron Marston): * `RSpec.configuration.expect_with(:rspec) { |c| c.syntax = :expect }` * `RSpec.configuration.expect_with(:rspec) { |c| c.syntax = :should }` * `RSpec.configuration.expect_with(:rspec) { |c| c.syntax = [:should, :expect] }` * `RSpec.configuration.add_should_and_should_not_to Delegator` Bug fixes * Allow only `Numeric` values to be the "actual" in the `be_within` matcher. This prevents confusing error messages. (Su Zhang @zhangsu) * Define `should` and `should_not` on `BasicObject` rather than `Kernel` on 1.9. This makes `should` and `should_not` work properly with `BasicObject`-subclassed proxy objects like `Delegator`. (Myron Marston) ### 2.10.0 / 2012-05-03 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.9.1...v2.10.0) Enhancements * Add new `start_with` and `end_with` matchers (Jeremy Wadsack) * Add new matchers for specifying yields (Myron Marston): * `expect {...}.to yield_control` * `expect {...}.to yield_with_args(1, 2, 3)` * `expect {...}.to yield_with_no_args` * `expect {...}.to yield_successive_args(1, 2, 3)` * `match_unless_raises` takes multiple exception args Bug fixes * Fix `be_within` matcher to be inclusive of delta. * Fix message-specific specs to pass on Rubinius (John Firebaugh) ### 2.9.1 / 2012-04-03 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.9.0...v2.9.1) Bug fixes * Provide a helpful message if the diff between two objects is empty. * Fix bug diffing single strings with multiline strings. * Fix for error with using custom matchers inside other custom matchers (mirasrael) * Fix using execution context methods in nested DSL matchers (mirasrael) ### 2.9.0 / 2012-03-17 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.8.0...v2.9.0) Enhancements * Move built-in matcher classes to RSpec::Matchers::BuiltIn to reduce pollution of RSpec::Matchers (which is included in every example). * Autoload files with matcher classes to improve load time. Bug fixes * Align `respond_to?` and `method_missing` in DSL-defined matchers. * Clear out user-defined instance variables between invocations of DSL-defined matchers. * Dup the instance of a DSL generated matcher so its state is not changed by subsequent invocations. * Treat expected args consistently across positive and negative expectations (thanks to Ralf Kistner for the heads up) ### 2.8.0 / 2012-01-04 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.8.0.rc2...v2.8.0) Enhancements * Better diff output for Hash (Philippe Creux) * Eliminate Ruby warnings (Olek Janiszewski) ### 2.8.0.rc2 / 2011-12-19 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.8.0.rc1...v2.8.0.rc2) No changes for this release. Just releasing with the other rspec gems. ### 2.8.0.rc1 / 2011-11-06 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.7.0...v2.8.0.rc1) Enhancements * Use classes for the built-in matchers (they're faster). * Eliminate Ruby warnings (Matijs van Zuijlen) ### 2.7.0 / 2011-10-16 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.6.0...v2.7.0) Enhancements * `HaveMatcher` converts argument using `to_i` (Alex Bepple & Pat Maddox) * Improved failure message for the `have_xxx` matcher (Myron Marston) * `HaveMatcher` supports `count` (Matthew Bellantoni) * Change matcher dups `Enumerable` before the action, supporting custom `Enumerable` types like `CollectionProxy` in Rails (David Chelimsky) Bug fixes * Fix typo in `have(n).xyz` documentation (Jean Boussier) * fix `safe_sort` for ruby 1.9.2 (`Kernel` now defines `<=>` for Object) (Peter van Hardenberg) ### 2.6.0 / 2011-05-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.5.0...v2.6.0) Enhancements * `change` matcher accepts regexps (Robert Davis) * better descriptions for `have_xxx` matchers (Magnus Bergmark) * `range.should cover(*values)` (Anders Furseth) Bug fixes * Removed non-ascii characters that were choking rcov (Geoffrey Byers) * change matcher dups arrays and hashes so their before/after states can be compared correctly. * Fix the order of inclusion of RSpec::Matchers in Test::Unit::TestCase and MiniTest::Unit::TestCase to prevent a SystemStackError (Myron Marston) ### 2.5.0 / 2011-02-05 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.4.0...v2.5.0) Enhancements * `should exist` works with `exist?` or `exists?` (Myron Marston) * `expect { ... }.not_to do_something` (in addition to `to_not`) Documentation * improved docs for raise_error matcher (James Almond) ### 2.4.0 / 2011-01-02 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.3.0...v2.4.0) No functional changes in this release, which was made to align with the rspec-core-2.4.0 release. Enhancements * improved RDoc for change matcher (Jo Liss) ### 2.3.0 / 2010-12-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.2.1...v2.3.0) Enhancements * diff strings when include matcher fails (Mike Sassak) ### 2.2.0 / 2010-11-28 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.1.0...v2.2.0) ### 2.1.0 / 2010-11-07 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.0.1...v2.1.0) Enhancements * `be_within(delta).of(expected)` matcher (Myron Marston) * Lots of new Cucumber features (Myron Marston) * Raise error if you try `should != expected` on Ruby-1.9 (Myron Marston) * Improved failure messages from `throw_symbol` (Myron Marston) Bug fixes * Eliminate hard dependency on `RSpec::Core` (Myron Marston) * `have_matcher` - use pluralize only when ActiveSupport inflections are indeed defined (Josep M Bach) * throw_symbol matcher no longer swallows exceptions (Myron Marston) * fix matcher chaining to avoid name collisions (Myron Marston) ### 2.0.0 / 2010-10-10 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.0.0.rc...v2.0.0) Enhancements * Add match_for_should_not method to matcher DSL (Myron Marston) Bug fixes * `respond_to` matcher works correctly with `should_not` with multiple methods (Myron Marston) * `include` matcher works correctly with `should_not` with multiple values (Myron Marston) ### 2.0.0.rc / 2010-10-05 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.0.0.beta.22...v2.0.0.rc) Enhancements * `require 'rspec/expectations'` in a T::U or MiniUnit suite (Josep M. Bach) Bug fixes * change by 0 passes/fails correctly (Len Smith) * Add description to satisfy matcher ### 2.0.0.beta.22 / 2010-09-12 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v2.0.0.beta.20...v2.0.0.beta.22) Enhancements * diffing improvements * diff multiline strings * don't diff single line strings * don't diff numbers (silly) * diff regexp + multiline string Bug fixes * `should[_not]` change now handles boolean values correctly rspec-expectations-3.13.0/DEV-README.md000066400000000000000000000012741455770000100173140ustar00rootroot00000000000000## Set up the dev environment git clone https://github.com/rspec/rspec-expectations.git cd rspec-expectations gem install bundler bundle install Now you should be able to run any of: rake rake spec rake cucumber Or, if you prefer to use the rspec and cucumber commands directly, you can either: bundle exec rspec Or ... bundle install --binstubs bin/rspec ## Customize the dev environment The Gemfile includes the gems you'll need to be able to run specs. If you want to customize your dev environment with additional tools like guard or ruby-debug, add any additional gem declarations to Gemfile-custom (see Gemfile-custom.sample for some examples). rspec-expectations-3.13.0/DEVELOPMENT.md000066400000000000000000000115611455770000100175250ustar00rootroot00000000000000 # Development Setup Generally speaking, you only need to clone the project and install the dependencies with [Bundler](https://bundler.io/). You can either get a full RSpec development environment using [rspec-dev](https://github.com/rspec/rspec-dev#README) or you can set this project up individually. ## Setting up rspec-expectations individually For most contributors, setting up the project individually will be simpler. Unless you have a specific reason to use rspec-dev, we recommend using this approach. Clone the repo: ``` $ git clone git@github.com:rspec/rspec-expectations.git ``` Install the dependencies using [Bundler](https://bundler.io/): ``` $ cd rspec-expectations $ bundle install ``` To minimize boot time and to ensure we don't depend upon any extra dependencies loaded by Bundler, our CI builds avoid loading Bundler at runtime by using Bundler's [`--standalone option`](https://myronmars.to/n/dev-blog/2012/03/faster-test-boot-times-with-bundler-standalone). While not strictly necessary (many/most of our contributors do not do this!), if you want to exactly reproduce our CI builds you'll want to do the same: ``` $ bundle install --standalone --binstubs ``` The `--binstubs` option creates the `bin/rspec` file that, like `bundle exec rspec`, will load all the versions specified in `Gemfile.lock` without loading bundler at runtime! ## Using rspec-dev See the [rspec-dev README](https://github.com/rspec/rspec-dev#README) for setup instructions. The rspec-dev project contains many rake tasks for helping manage an RSpec development environment, making it easy to do things like: * Change branches across all repos * Update all repos with the latest code from `main` * Cut a new release across all repos * Push out updated build scripts to all repos These sorts of tasks are essential for the RSpec maintainers but will probably be unnecessary complexity if you're just contributing to one repository. If you are getting setup to make your first contribution, we recommend you take the simpler route of setting up rspec-expectations individually. ## Gotcha: Version mismatch from sibling repos The [Gemfile](Gemfile) is designed to be flexible and support using the other RSpec repositories either from a local sibling directory (e.g. `../rspec-`) or, if there is no such directory, directly from git. This generally does the "right thing", but can be a gotcha in some situations. For example, if you are setting up `rspec-core`, and you happen to have an old clone of `rspec-expectations` in a sibling directory, it'll be used even though it might be months or years out of date, which can cause confusing failures. To avoid this problem, you can either `export USE_GIT_REPOS=1` to force the use of `:git` dependencies instead of local dependencies, or update the code in the sibling directory. rspec-dev contains rake tasks to help you keep all repos in sync. ## Extra Gems If you need additional gems for any tasks---such as `benchmark-ips` for benchmarking or `byebug` for debugging---you can create a `Gemfile-custom` file containing those gem declarations. The `Gemfile` evaluates that file if it exists, and it is git-ignored. # Running the build The [Travis CI build](https://travis-ci.org/rspec/rspec-expectations) runs many verification steps to prevent regressions and ensure high-quality code. To run the Travis build locally, run: ``` $ script/run_build ``` See [build detail](BUILD_DETAIL.md) for more detail. # What to Expect To ensure high, uniform code quality, all code changes (including changes from the maintainers!) are subject to a pull request code review. We'll often ask for clarification or suggest alternate ways to do things. Our code reviews are intended to be a two-way conversation. Here's a short, non-exhaustive checklist of things we typically ask contributors to do before PRs are ready to merge. It can help get your PR merged faster if you do these in advance! - [ ] New behavior is covered by tests and all tests are passing. - [ ] No Ruby warnings are issued by your changes. - [ ] Documentation reflects changes and renders as intended. - [ ] RuboCop passes (e.g. `bundle exec rubocop lib`). - [ ] Commits are squashed into a reasonable number of logical changesets that tell an easy-to-follow story. - [ ] No changelog entry is necessary (we'll add it as part of the merge process!) # Adding Docs RSpec uses [YARD](https://yardoc.org/) for its API documentation. To ensure the docs render well, we recommend running a YARD server and viewing your edits in a browser. To run a YARD server: ``` $ bundle exec yard server --reload # or, if you installed your bundle with `--standalone --binstubs`: $ bin/yard server --reload ``` Then navigate to `localhost:8808` to view the rendered docs. rspec-expectations-3.13.0/Gemfile000066400000000000000000000055321455770000100167150ustar00rootroot00000000000000source "https://rubygems.org" gemspec branch = File.read(File.expand_path("../maintenance-branch", __FILE__)).chomp %w[rspec rspec-core rspec-mocks rspec-support].each do |lib| library_path = File.expand_path("../../#{lib}", __FILE__) if File.exist?(library_path) && !ENV['USE_GIT_REPOS'] gem lib, :path => library_path else gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => branch end end if RUBY_VERSION < '1.9.3' gem 'rake', '< 11.0.0' # rake 11 requires Ruby 1.9.3 or later elsif RUBY_VERSION < '2.0.0' gem 'rake', '< 12.0.0' # rake 12 requires Ruby 2.0.0 or later elsif RUBY_VERSION < '2.2.0' gem 'rake', '12.3.2' else gem 'rake', '>= 12.3.3' end if ENV['DIFF_LCS_VERSION'] gem 'diff-lcs', ENV['DIFF_LCS_VERSION'] else gem 'diff-lcs', '~> 1.4', '>= 1.4.3' end gem 'coderay' # for syntax highlighting gem 'yard', '~> 0.9.24', :require => false ### deps for rdoc.info group :documentation do gem 'redcarpet', :platform => :mri gem 'github-markup', :platform => :mri end group :coverage do gem 'simplecov' end if RUBY_VERSION < '2.0.0' || RUBY_ENGINE == 'java' gem 'json', '< 2.0.0' # is a dependency of simplecov else gem 'json', '> 2.3.0' end # allow gems to be installed on older rubies and/or windows if RUBY_VERSION < '2.2.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/) gem 'ffi', '< 1.10' elsif RUBY_VERSION < '2.4.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/) gem 'ffi', '< 1.15' elsif RUBY_VERSION < '1.9' gem 'ffi', '< 1.9.19' # ffi dropped Ruby 1.8 support in 1.9.19 elsif RUBY_VERSION < '2.0' gem 'ffi', '< 1.11.0' # ffi dropped Ruby 1.9 support in 1.11.0 else gem 'ffi', '> 1.9.24' # prevent Github security vulnerability warning end if RUBY_VERSION <= '2.3.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/) gem "childprocess", "< 1.0.0" elsif RUBY_VERSION < '2.0.0' gem "childprocess", "< 1.0.0" else gem "childprocess", "> 1.0.0" end if RUBY_VERSION < '2.0.0' gem 'thor', '< 1.0.0' else gem 'thor', '> 1.0.0' end if RUBY_VERSION < '1.9.2' gem 'contracts', '~> 0.15.0' # is a dependency of aruba end # Version 5.12 of minitest requires Ruby 2.4 if RUBY_VERSION < '2.4.0' gem 'minitest', '< 5.12.0' end platforms :jruby do if RUBY_VERSION < '1.9.0' # Pin jruby-openssl on older J Ruby gem "jruby-openssl", "< 0.10.0" else gem "jruby-openssl" end end if RUBY_VERSION >= '2.4' && RUBY_ENGINE == 'ruby' gem 'rubocop', "~> 1.0", "< 1.12" end if RUBY_VERSION < '2.0.0' gem 'cucumber', "<= 1.3.22" elsif !ENV['DIFF_LCS_VERSION'].to_s.empty? && ENV['DIFF_LCS_VERSION'].scan(/\d\.\d/).first.to_f < 1.5 # Older version of diff-lcs cause a downstream error with cucumber and modern rails gem "activesupport", "< 7" end eval File.read('Gemfile-custom') if File.exist?('Gemfile-custom') rspec-expectations-3.13.0/Gemfile-custom.sample000066400000000000000000000005111455770000100214750ustar00rootroot00000000000000group :development do gem 'interactive_rspec' gem 'guard-rspec', '~> 1.2.1' gem 'growl', '1.0.3' gem 'spork', '0.9.0' platform :mri do gem 'rb-fsevent', '~> 0.9.0' gem 'ruby-prof', '~> 0.10.0' case RUBY_VERSION when /^1.8/ gem 'ruby-debug' when /^1.9/ gem 'debugger' end end end rspec-expectations-3.13.0/Guardfile000066400000000000000000000003501455770000100172400ustar00rootroot00000000000000guard 'rspec', :version => 2 do watch(/^spec\/(.*)_spec.rb/) watch(/^lib\/(.*)\.rb/) { |m| "spec/#{m[1]}_spec.rb" } watch(/^spec\/spec_helper.rb/) { "spec" } watch(/^lib\/rspec\/matchers\/built_in/) { "spec" } end rspec-expectations-3.13.0/ISSUE_TEMPLATE.md000066400000000000000000000010361455770000100201220ustar00rootroot00000000000000 ### Subject of the issue ### Your environment * Ruby version: * rspec-expectations version: ### Steps to reproduce ### Expected behavior ### Actual behavior rspec-expectations-3.13.0/LICENSE.md000066400000000000000000000023011455770000100170150ustar00rootroot00000000000000The MIT License (MIT) ===================== * Copyright © 2012 David Chelimsky, Myron Marston * Copyright © 2006 David Chelimsky, The RSpec Development Team * Copyright © 2005 Steven Baker 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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. rspec-expectations-3.13.0/README.md000066400000000000000000000221261455770000100166770ustar00rootroot00000000000000# RSpec Expectations [![Build Status](https://github.com/rspec/rspec-expectations/workflows/RSpec%20CI/badge.svg)](https://github.com/rspec/rspec-expectations/actions) [![Code Climate](https://codeclimate.com/github/rspec/rspec-expectations.svg)](https://codeclimate.com/github/rspec/rspec-expectations) RSpec::Expectations lets you express expected outcomes on an object in an example. ```ruby expect(account.balance).to eq(Money.new(37.42, :USD)) ``` ## Install If you want to use rspec-expectations with rspec, just install the rspec gem and RubyGems will also install rspec-expectations for you (along with rspec-core and rspec-mocks): gem install rspec Want to run against the `main` branch? You'll need to include the dependent RSpec repos as well. Add the following to your `Gemfile`: ```ruby %w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib| gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main' end ``` If you want to use rspec-expectations with another tool, like Test::Unit, Minitest, or Cucumber, you can install it directly: gem install rspec-expectations ## Contributing Once you've set up the environment, you'll need to cd into the working directory of whichever repo you want to work in. From there you can run the specs and cucumber features, and make patches. NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You can treat each RSpec repo as an independent project. - [Build details](BUILD_DETAIL.md) - [Code of Conduct](CODE_OF_CONDUCT.md) - [Detailed contributing guide](CONTRIBUTING.md) - [Development setup guide](DEVELOPMENT.md) ## Basic usage Here's an example using rspec-core: ```ruby RSpec.describe Order do it "sums the prices of the items in its line items" do order = Order.new order.add_entry(LineItem.new(:item => Item.new( :price => Money.new(1.11, :USD) ))) order.add_entry(LineItem.new(:item => Item.new( :price => Money.new(2.22, :USD), :quantity => 2 ))) expect(order.total).to eq(Money.new(5.55, :USD)) end end ``` The `describe` and `it` methods come from rspec-core. The `Order`, `LineItem`, `Item` and `Money` classes would be from _your_ code. The last line of the example expresses an expected outcome. If `order.total == Money.new(5.55, :USD)`, then the example passes. If not, it fails with a message like: expected: # got: # ## Built-in matchers ### Equivalence ```ruby expect(actual).to eq(expected) # passes if actual == expected expect(actual).to eql(expected) # passes if actual.eql?(expected) expect(actual).not_to eql(not_expected) # passes if not(actual.eql?(expected)) ``` Note: The new `expect` syntax no longer supports the `==` matcher. ### Identity ```ruby expect(actual).to be(expected) # passes if actual.equal?(expected) expect(actual).to equal(expected) # passes if actual.equal?(expected) ``` ### Comparisons ```ruby expect(actual).to be > expected expect(actual).to be >= expected expect(actual).to be <= expected expect(actual).to be < expected expect(actual).to be_within(delta).of(expected) ``` ### Regular expressions ```ruby expect(actual).to match(/expression/) ``` Note: The new `expect` syntax no longer supports the `=~` matcher. ### Types/classes ```ruby expect(actual).to be_an_instance_of(expected) # passes if actual.class == expected expect(actual).to be_a(expected) # passes if actual.kind_of?(expected) expect(actual).to be_an(expected) # an alias for be_a expect(actual).to be_a_kind_of(expected) # another alias ``` ### Truthiness ```ruby expect(actual).to be_truthy # passes if actual is truthy (not nil or false) expect(actual).to be true # passes if actual == true expect(actual).to be_falsy # passes if actual is falsy (nil or false) expect(actual).to be false # passes if actual == false expect(actual).to be_nil # passes if actual is nil expect(actual).to_not be_nil # passes if actual is not nil ``` ### Expecting errors ```ruby expect { ... }.to raise_error expect { ... }.to raise_error(ErrorClass) expect { ... }.to raise_error("message") expect { ... }.to raise_error(ErrorClass, "message") ``` ### Expecting throws ```ruby expect { ... }.to throw_symbol expect { ... }.to throw_symbol(:symbol) expect { ... }.to throw_symbol(:symbol, 'value') ``` ### Yielding ```ruby expect { |b| 5.tap(&b) }.to yield_control # passes regardless of yielded args expect { |b| yield_if_true(true, &b) }.to yield_with_no_args # passes only if no args are yielded expect { |b| 5.tap(&b) }.to yield_with_args(5) expect { |b| 5.tap(&b) }.to yield_with_args(Integer) expect { |b| "a string".tap(&b) }.to yield_with_args(/str/) expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) ``` ### Predicate matchers ```ruby expect(actual).to be_xxx # passes if actual.xxx? expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg) ``` ### Ranges (Ruby >= 1.9 only) ```ruby expect(1..10).to cover(3) ``` ### Collection membership ```ruby # exact order, entire collection expect(actual).to eq(expected) # exact order, partial collection (based on an exact position) expect(actual).to start_with(expected) expect(actual).to end_with(expected) # any order, entire collection expect(actual).to match_array(expected) # You can also express this by passing the expected elements # as individual arguments expect(actual).to contain_exactly(expected_element1, expected_element2) # any order, partial collection expect(actual).to include(expected) ``` #### Examples ```ruby expect([1, 2, 3]).to eq([1, 2, 3]) # Order dependent equality check expect([1, 2, 3]).to include(1) # Exact ordering, partial collection matches expect([1, 2, 3]).to include(2, 3) # expect([1, 2, 3]).to start_with(1) # As above, but from the start of the collection expect([1, 2, 3]).to start_with(1, 2) # expect([1, 2, 3]).to end_with(3) # As above but from the end of the collection expect([1, 2, 3]).to end_with(2, 3) # expect({:a => 'b'}).to include(:a => 'b') # Matching within hashes expect("this string").to include("is str") # Matching within strings expect("this string").to start_with("this") # expect("this string").to end_with("ring") # expect([1, 2, 3]).to contain_exactly(2, 3, 1) # Order independent matches expect([1, 2, 3]).to match_array([3, 2, 1]) # # Order dependent compound matchers expect( [{:a => 'hash'},{:a => 'another'}] ).to match([a_hash_including(:a => 'hash'), a_hash_including(:a => 'another')]) ``` ## `should` syntax In addition to the `expect` syntax, rspec-expectations continues to support the `should` syntax: ```ruby actual.should eq expected actual.should be > 3 [1, 2, 3].should_not include 4 ``` See [detailed information on the `should` syntax and its usage.](https://github.com/rspec/rspec-expectations/blob/main/Should.md) ## Compound Matcher Expressions You can also create compound matcher expressions using `and` or `or`: ``` ruby expect(alphabet).to start_with("a").and end_with("z") expect(stoplight.color).to eq("red").or eq("green").or eq("yellow") ``` ## Composing Matchers Many of the built-in matchers are designed to take matchers as arguments, to allow you to flexibly specify only the essential aspects of an object or data structure. In addition, all of the built-in matchers have one or more aliases that provide better phrasing for when they are used as arguments to another matcher. ### Examples ```ruby expect { k += 1.05 }.to change { k }.by( a_value_within(0.1).of(1.0) ) expect { s = "barn" }.to change { s } .from( a_string_matching(/foo/) ) .to( a_string_matching(/bar/) ) expect(["barn", 2.45]).to contain_exactly( a_value_within(0.1).of(2.5), a_string_starting_with("bar") ) expect(["barn", "food", 2.45]).to end_with( a_string_matching("foo"), a_value > 2 ) expect(["barn", 2.45]).to include( a_string_starting_with("bar") ) expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/)) hash = { :a => { :b => ["foo", 5], :c => { :d => 2.05 } } } expect(hash).to match( :a => { :b => a_collection_containing_exactly( a_string_starting_with("f"), an_instance_of(Integer) ), :c => { :d => (a_value < 3) } } ) expect { |probe| [1, 2, 3].each(&probe) }.to yield_successive_args( a_value < 2, 2, a_value > 2 ) ``` ## Usage outside rspec-core You always need to load `rspec/expectations` even if you only want to use one part of the library: ```ruby require 'rspec/expectations' ``` Then simply include `RSpec::Matchers` in any class: ```ruby class MyClass include RSpec::Matchers def do_something(arg) expect(arg).to be > 0 # do other stuff end end ``` ## Also see * [https://github.com/rspec/rspec](https://github.com/rspec/rspec) * [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core) * [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks) * [https://github.com/rspec/rspec-rails](https://github.com/rspec/rspec-rails) rspec-expectations-3.13.0/REPORT_TEMPLATE.md000066400000000000000000000021171455770000100202460ustar00rootroot00000000000000 # Report template ```ruby # frozen_string_literal: true begin require "bundler/inline" rescue LoadError => e $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do source "https://rubygems.org" gem "rspec", "3.7.0" # Activate the gem and version you are reporting the issue against. end puts "Ruby version is: #{RUBY_VERSION}" require 'rspec/autorun' RSpec.describe 'additions' do it 'returns 2' do expect(1 + 1).to eq(2) end it 'returns 1' do expect(3 - 1).to eq(-1) end end ``` Simply copy the content of the appropriate template into a `.rb` file on your computer and make the necessary changes to demonstrate the issue. You can execute it by running `ruby rspec_report.rb` in your terminal. You can then share your executable test case as a [gist](https://gist.github.com), or simply paste the content into the issue description. rspec-expectations-3.13.0/Rakefile000066400000000000000000000021501455770000100170600ustar00rootroot00000000000000require 'bundler' Bundler.setup Bundler::GemHelper.install_tasks require 'rake' require 'rspec/core/rake_task' require 'rspec/expectations/version' require 'cucumber/rake/task' Cucumber::Rake::Task.new(:cucumber) if RUBY_VERSION >= '2.4' && RUBY_ENGINE == 'ruby' require 'rubocop/rake_task' RuboCop::RakeTask.new(:rubocop) end desc "Run all examples" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-w] end namespace :clobber do desc "delete generated .rbc files" task :rbc do sh 'find . -name "*.rbc" | xargs rm' end end desc "delete generated files" task :clobber => ["clobber:rbc"] do rm_rf 'doc' rm_rf '.yardoc' rm_rf 'pkg' rm_rf 'tmp' rm_rf 'coverage' end if RUBY_VERSION >= '2.4' && RUBY_ENGINE == 'ruby' task :default => [:spec, :cucumber, :rubocop] else task :default => [:spec, :cucumber] end task :verify_private_key_present do private_key = File.expand_path('~/.gem/rspec-gem-private_key.pem') unless File.exist?(private_key) raise "Your private key is not present. This gem should not be built without it." end end task :build => :verify_private_key_present rspec-expectations-3.13.0/Should.md000066400000000000000000000106461455770000100172040ustar00rootroot00000000000000# `should` and `should_not` syntax From the beginning RSpec::Expectations provided `should` and `should_not` methods to define expectations on any object. In version 2.11 `expect` method was introduced which is now the recommended way to define expectations on an object. ### Why switch over from `should` to `expect` #### Fix edge case issues `should` and `should_not` work by being added to every object. However, RSpec does not own every object and cannot ensure they work consistently on every object. In particular, they can lead to surprising failures when used with BasicObject-subclassed proxy objects. `expect` avoids these problems altogether by not needing to be available on all objects. #### Unification of block and value syntaxes Before version 2.11 `expect` was just a more readable alternative for block expectations. Since version 2.11 `expect` can be used for both block and value expectations. ```ruby expect(actual).to eq(expected) expect { ... }.to raise_error(ErrorClass) ``` See [http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax](http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax) For a detailed explanation ### One-liners The one-liner syntax supported by [rspec-core](http://rubydoc.info/gems/rspec-core) uses `should` even when `config.syntax = :expect`. It reads better than the alternative, and does not require a global monkey patch: ```ruby describe User do it { should validate_presence_of :email } end ``` It can also be expressed with the `is_expected` syntax: ```ruby describe User do it { is_expected.to validate_presence_of :email } end ``` ### Using either `expect` or `should` or both By default, both `expect` and `should` syntaxes are available. In the future, the default may be changed to only enable the `expect` syntax. If you want your project to only use any one of these syntaxes, you can configure it: ```ruby RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = :expect # disables `should` # or c.syntax = :should # disables `expect` # or c.syntax = [:should, :expect] # default, enables both `should` and `expect` end end ``` See [RSpec::Expectations::Syntax#expect](http://rubydoc.info/gems/rspec-expectations/RSpec/Expectations/Syntax:expect) for more information. ## Usage The `should` and `should_not` methods can be used to define expectations on any object. ```ruby actual.should eq expected actual.should be > 3 [1, 2, 3].should_not include 4 ``` ## Using Built-in matchers ### Equivalence ```ruby actual.should eq(expected) # passes if actual == expected actual.should == expected # passes if actual == expected actual.should_not eql(expected) # passes if actual.eql?(expected) ``` Note: we recommend the `eq` matcher over `==` to avoid Ruby's "== in a useless context" warning when the `==` matcher is used anywhere but the last statement of an example. ### Identity ```ruby actual.should be(expected) # passes if actual.equal?(expected) actual.should_not equal(expected) # passes if actual.equal?(expected) ``` ### Comparisons ```ruby actual.should be > expected actual.should be >= expected actual.should be <= expected actual.should be < expected actual.should be_within(delta).of(expected) ``` ### Regular expressions ```ruby actual.should match(/expression/) actual.should =~ /expression/ ``` ### Types/classes ```ruby actual.should be_an_instance_of(expected) actual.should_not be_a_kind_of(expected) ``` ### Truthiness ```ruby actual.should be_true # passes if actual is truthy (not nil or false) actual.should be_false # passes if actual is falsy (nil or false) actual.should be_nil # passes if actual is nil ``` ### Predicate matchers ```ruby actual.should be_xxx # passes if actual.xxx? actual.should_not have_xxx(:arg) # passes if actual.has_xxx?(:arg) ``` ### Ranges (Ruby >= 1.9 only) ```ruby (1..10).should cover(3) ``` ### Collection membership ```ruby actual.should include(expected) actual.should start_with(expected) actual.should end_with(expected) ``` #### Examples ```ruby [1,2,3].should include(1) [1,2,3].should include(1, 2) [1,2,3].should start_with(1) [1,2,3].should start_with(1,2) [1,2,3].should end_with(3) [1,2,3].should end_with(2,3) {:a => 'b'}.should include(:a => 'b') "this string".should include("is str") "this string".should start_with("this") "this string".should end_with("ring") ``` rspec-expectations-3.13.0/benchmarks/000077500000000000000000000000001455770000100175325ustar00rootroot00000000000000rspec-expectations-3.13.0/benchmarks/2.x_vs_3.x_matcher_dsl_implementation.rb000066400000000000000000000235661455770000100273540ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'benchmark' require 'rspec/expectations' include RSpec::Expectations include RSpec::Matchers n = 1000 puts "3 runs of #{n} times for each example running rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}" puts "Defining a custom matcher" Benchmark.benchmark do |bm| 3.times do |i| bm.report do n.times do |j| RSpec::Matchers.define :"define_matcher_#{i}_#{j}" do match {} end end end end end puts "Getting an instance of a custom matcher" RSpec::Matchers.define :be_a_multiple_of do |x| match { |actual| (actual % x).zero? } end Benchmark.benchmark do |bm| 3.times do bm.report do n.times do |i| be_a_multiple_of(i) end end end end puts "Using a previously gotten custom matcher instance -- positive match" Benchmark.benchmark do |bm| 1.upto(3) do |i| matcher = be_a_multiple_of(i) bm.report do n.times do |j| expect(i * j).to matcher end end end end puts "Using a previously gotten custom matcher instance -- negative match" Benchmark.benchmark do |bm| 2.upto(4) do |i| matcher = be_a_multiple_of(i) bm.report do n.times do |j| begin expect(1 + i * j).to matcher rescue RSpec::Expectations::ExpectationNotMetError end end end end end =begin Results are below for: - MRI 2.0.0, MRI 1.9.3, JRuby 1.7.4 - Against 2.14.3, 3.0.0.pre before matcher DSL rewrite, 3.0.0.pre after matcher DSL rewrite Conclusions: * Getting an instance of a custom matcher was insanely slow in 2.x, and it looks like the `making_declared_methods_public` hack for 1.8.6 was the primary source of that. Without that, getting an instance of a matcher is ~20x faster. To see what changed between 2.14.3 and the commit used for this benchmark, go to: https://github.com/rspec/rspec-expectations/compare/v2.14.3...4c47e4c43ee6961c755d325e73181b1f5b6bf097#diff-a51020971ade2c87f1d5b93f20d711c7L6 * With our new custom matcher DSL, using a matcher is approximately the same perf. However, defining a matcher is a little bit faster, and getting an instance of an already defined matcher is about 10x faster. Overall, this is definitely a net win. Results: 3 runs of 1000 times for each example running rspec-expectations 2.14.3 -- ruby/2.0.0 Defining a custom matcher 0.010000 0.000000 0.010000 ( 0.004612) 0.000000 0.000000 0.000000 ( 0.004674) 0.000000 0.000000 0.000000 ( 0.004944) Getting an instance of a custom matcher 1.470000 0.010000 1.480000 ( 1.472602) 1.420000 0.000000 1.420000 ( 1.426760) 1.440000 0.000000 1.440000 ( 1.442283) Using a previously gotten custom matcher instance -- positive match 0.000000 0.000000 0.000000 ( 0.002213) 0.000000 0.000000 0.000000 ( 0.002019) 0.000000 0.000000 0.000000 ( 0.001884) Using a previously gotten custom matcher instance -- negative match 0.020000 0.000000 0.020000 ( 0.019378) 0.030000 0.000000 0.030000 ( 0.027001) 0.020000 0.010000 0.030000 ( 0.022310) 3 runs of 1000 times for each example running rspec-expectations 2.14.3 -- ruby/1.9.3 Defining a custom matcher 0.000000 0.000000 0.000000 ( 0.004455) 0.010000 0.000000 0.010000 ( 0.004849) 0.010000 0.000000 0.010000 ( 0.010495) Getting an instance of a custom matcher 1.690000 0.010000 1.700000 ( 1.696415) 1.550000 0.000000 1.550000 ( 1.556858) 1.550000 0.000000 1.550000 ( 1.554830) Using a previously gotten custom matcher instance -- positive match 0.000000 0.000000 0.000000 ( 0.002161) 0.000000 0.000000 0.000000 ( 0.002038) 0.010000 0.000000 0.010000 ( 0.002091) Using a previously gotten custom matcher instance -- negative match 0.050000 0.010000 0.060000 ( 0.060512) 0.050000 0.000000 0.050000 ( 0.064532) 0.060000 0.010000 0.070000 ( 0.062206) 3 runs of 1000 times for each example running rspec-expectations 2.14.3 -- jruby/1.9.3 Defining a custom matcher 0.660000 0.010000 0.670000 ( 0.299000) 0.280000 0.000000 0.280000 ( 0.178000) 0.220000 0.010000 0.230000 ( 0.143000) Getting an instance of a custom matcher 1.970000 0.030000 2.000000 ( 1.389000) 1.340000 0.030000 1.370000 ( 0.907000) 0.820000 0.030000 0.850000 ( 0.795000) Using a previously gotten custom matcher instance -- positive match 0.110000 0.000000 0.110000 ( 0.058000) 0.050000 0.000000 0.050000 ( 0.036000) 0.030000 0.000000 0.030000 ( 0.030000) Using a previously gotten custom matcher instance -- negative match 0.930000 0.010000 0.940000 ( 0.474000) 0.620000 0.000000 0.620000 ( 0.376000) 0.390000 0.000000 0.390000 ( 0.279000) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre (before DSL rewrite) -- ruby/2.0.0 Defining a custom matcher 0.010000 0.000000 0.010000 ( 0.004719) 0.000000 0.000000 0.000000 ( 0.004424) 0.010000 0.000000 0.010000 ( 0.005562) Getting an instance of a custom matcher 0.050000 0.000000 0.050000 ( 0.059949) 0.060000 0.000000 0.060000 ( 0.058208) 0.060000 0.010000 0.070000 ( 0.067402) Using a previously gotten custom matcher instance -- positive match 0.010000 0.000000 0.010000 ( 0.001696) 0.000000 0.000000 0.000000 ( 0.001558) 0.000000 0.000000 0.000000 ( 0.001488) Using a previously gotten custom matcher instance -- negative match 0.020000 0.000000 0.020000 ( 0.021522) 0.030000 0.000000 0.030000 ( 0.027728) 0.020000 0.000000 0.020000 ( 0.026185) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre (before DSL rewrite) -- ruby/1.9.3 Defining a custom matcher 0.010000 0.000000 0.010000 ( 0.004650) 0.000000 0.000000 0.000000 ( 0.004658) 0.010000 0.000000 0.010000 ( 0.011111) Getting an instance of a custom matcher 0.050000 0.010000 0.060000 ( 0.047230) 0.060000 0.000000 0.060000 ( 0.065500) 0.070000 0.000000 0.070000 ( 0.073099) Using a previously gotten custom matcher instance -- positive match 0.000000 0.000000 0.000000 ( 0.002007) 0.000000 0.000000 0.000000 ( 0.002370) 0.010000 0.000000 0.010000 ( 0.002121) Using a previously gotten custom matcher instance -- negative match 0.070000 0.010000 0.080000 ( 0.078960) 0.060000 0.000000 0.060000 ( 0.061351) 0.060000 0.000000 0.060000 ( 0.069949) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre (before DSL rewrite) -- jruby/1.9.3 Defining a custom matcher 0.730000 0.010000 0.740000 ( 0.303000) 0.240000 0.010000 0.250000 ( 0.153000) 0.210000 0.000000 0.210000 ( 0.140000) Getting an instance of a custom matcher 0.940000 0.010000 0.950000 ( 0.538000) 0.510000 0.000000 0.510000 ( 0.174000) 0.160000 0.000000 0.160000 ( 0.090000) Using a previously gotten custom matcher instance -- positive match 0.120000 0.000000 0.120000 ( 0.053000) 0.040000 0.000000 0.040000 ( 0.025000) 0.030000 0.000000 0.030000 ( 0.026000) Using a previously gotten custom matcher instance -- negative match 0.970000 0.010000 0.980000 ( 0.458000) 0.480000 0.010000 0.490000 ( 0.314000) 0.360000 0.000000 0.360000 ( 0.269000) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre -- ruby/2.0.0 Defining a custom matcher 0.000000 0.000000 0.000000 ( 0.003138) 0.000000 0.000000 0.000000 ( 0.003083) 0.010000 0.000000 0.010000 ( 0.003448) Getting an instance of a custom matcher 0.000000 0.000000 0.000000 ( 0.007273) 0.010000 0.000000 0.010000 ( 0.007096) 0.020000 0.000000 0.020000 ( 0.021662) Using a previously gotten custom matcher instance -- positive match 0.000000 0.000000 0.000000 ( 0.002582) 0.000000 0.000000 0.000000 ( 0.001832) 0.010000 0.000000 0.010000 ( 0.001588) Using a previously gotten custom matcher instance -- negative match 0.010000 0.000000 0.010000 ( 0.017756) 0.030000 0.000000 0.030000 ( 0.021225) 0.020000 0.010000 0.030000 ( 0.021281) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre -- ruby/1.9.3 Defining a custom matcher 0.000000 0.000000 0.000000 ( 0.002903) 0.000000 0.000000 0.000000 ( 0.002919) 0.010000 0.000000 0.010000 ( 0.008956) Getting an instance of a custom matcher 0.010000 0.000000 0.010000 ( 0.006640) 0.000000 0.000000 0.000000 ( 0.006557) 0.010000 0.000000 0.010000 ( 0.007869) Using a previously gotten custom matcher instance -- positive match 0.010000 0.000000 0.010000 ( 0.003332) 0.000000 0.000000 0.000000 ( 0.003288) 0.000000 0.000000 0.000000 ( 0.002769) Using a previously gotten custom matcher instance -- negative match 0.070000 0.010000 0.080000 ( 0.075547) 0.050000 0.000000 0.050000 ( 0.053149) 0.060000 0.010000 0.070000 ( 0.062583) 3 runs of 1000 times for each example running rspec-expectations 3.0.0.pre -- jruby/1.9.3 Defining a custom matcher 0.780000 0.020000 0.800000 ( 0.316000) 0.170000 0.010000 0.180000 ( 0.139000) 0.220000 0.000000 0.220000 ( 0.135000) Getting an instance of a custom matcher 0.340000 0.000000 0.340000 ( 0.183000) 0.230000 0.010000 0.240000 ( 0.131000) 0.180000 0.000000 0.180000 ( 0.104000) Using a previously gotten custom matcher instance -- positive match 0.170000 0.000000 0.170000 ( 0.076000) 0.070000 0.000000 0.070000 ( 0.049000) 0.110000 0.000000 0.110000 ( 0.047000) Using a previously gotten custom matcher instance -- negative match 0.970000 0.010000 0.980000 ( 0.461000) 0.410000 0.000000 0.410000 ( 0.316000) 0.350000 0.010000 0.360000 ( 0.256000) =end rspec-expectations-3.13.0/benchmarks/autoload_v_require.rb000066400000000000000000000011531455770000100237500ustar00rootroot00000000000000require 'benchmark' n = 10 Benchmark.benchmark do |bm| 3.times do bm.report do n.times do `bin/rspec benchmarks/example_spec.rb` end end end end # Before autoloading matcher class files # 0.000000 0.010000 8.800000 ( 8.906383) # 0.010000 0.010000 8.880000 ( 8.980907) # 0.000000 0.010000 8.820000 ( 8.918083) # # After autoloading matcher class files # 0.000000 0.010000 8.610000 ( 8.701434) # 0.010000 0.010000 8.620000 ( 8.741811) # 0.000000 0.000000 8.580000 ( 8.677235) # # Roughly 2.5% improvement in load time (every bit counts!) rspec-expectations-3.13.0/benchmarks/caller_vs_raise_for_backtrace.rb000066400000000000000000000041151455770000100260620ustar00rootroot00000000000000require 'benchmark/ips' def create_stack_trace(n, &block) return create_stack_trace(n - 1, &block) if n > 0 yield end [10, 50, 100].each do |frames| create_stack_trace(frames) do Benchmark.ips do |x| x.report("use caller (#{caller.count} frames)") do exception = RuntimeError.new("boom") exception.set_backtrace caller exception.backtrace end x.report("use raise (#{caller.count} frames)") do exception = begin raise "boom" rescue => e e end exception.backtrace end x.compare! end end end __END__ Calculating ------------------------------------- use caller (16 frames) 4.986k i/100ms use raise (16 frames) 4.255k i/100ms ------------------------------------------------- use caller (16 frames) 52.927k (± 9.9%) i/s - 264.258k use raise (16 frames) 50.079k (±10.1%) i/s - 251.045k Comparison: use caller (16 frames): 52927.3 i/s use raise (16 frames): 50078.6 i/s - 1.06x slower Calculating ------------------------------------- use caller (56 frames) 2.145k i/100ms use raise (56 frames) 2.065k i/100ms ------------------------------------------------- use caller (56 frames) 22.282k (± 9.3%) i/s - 111.540k use raise (56 frames) 21.428k (± 9.9%) i/s - 107.380k Comparison: use caller (56 frames): 22281.5 i/s use raise (56 frames): 21428.1 i/s - 1.04x slower Calculating ------------------------------------- use caller (106 frames) 1.284k i/100ms use raise (106 frames) 1.253k i/100ms ------------------------------------------------- use caller (106 frames) 12.437k (±10.6%) i/s - 62.916k use raise (106 frames) 10.873k (±12.6%) i/s - 53.879k Comparison: use caller (106 frames): 12437.4 i/s use raise (106 frames): 10873.2 i/s - 1.14x slower rspec-expectations-3.13.0/benchmarks/cloning_matchers.rb000066400000000000000000000004751455770000100234040ustar00rootroot00000000000000require 'benchmark' require 'rspec/expectations' include RSpec::Matchers n = 1_000_000 matcher = eq(3) Benchmark.bm do |x| x.report do n.times { matcher.clone } end end __END__ We can do about 1000 clones per ms: user system total real 1.080000 0.030000 1.110000 ( 1.120009) rspec-expectations-3.13.0/benchmarks/count_vs_select_size.rb000066400000000000000000000053641455770000100243200ustar00rootroot00000000000000require 'benchmark/ips' [10, 100, 1000, 10_000, 100_000].each do |array_size| array = (1..array_size).to_a Benchmark.ips do |ips| ips.report("#select { true }.size for #{array_size}") do array.select { true }.size end ips.report("#count { true } for #{array_size}") do array.count { true } end end end __END__ ruby benchmarks/count_vs_select_size.rb (git)-[main] Warming up -------------------------------------- #select { true }.size for 10 129.033k i/100ms #count { true } for 10 168.627k i/100ms Calculating ------------------------------------- #select { true }.size for 10 1.397M (± 6.8%) i/s - 6.968M in 5.011533s #count { true } for 10 1.716M (± 7.8%) i/s - 8.600M in 5.048212s Warming up -------------------------------------- #select { true }.size for 100 16.633k i/100ms #count { true } for 100 19.215k i/100ms Calculating ------------------------------------- #select { true }.size for 100 170.209k (± 8.1%) i/s - 848.283k in 5.036749s #count { true } for 100 212.102k (± 4.1%) i/s - 1.076M in 5.081653s Warming up -------------------------------------- #select { true }.size for 1000 1.650k i/100ms #count { true } for 1000 1.803k i/100ms Calculating ------------------------------------- #select { true }.size for 1000 15.651k (±17.0%) i/s - 75.900k in 5.073128s #count { true } for 1000 20.613k (± 5.6%) i/s - 104.574k in 5.091257s Warming up -------------------------------------- #select { true }.size for 10000 146.000 i/100ms #count { true } for 10000 202.000 i/100ms Calculating ------------------------------------- #select { true }.size for 10000 1.613k (± 8.4%) i/s - 8.030k in 5.014577s #count { true } for 10000 2.031k (± 4.8%) i/s - 10.302k in 5.085695s Warming up -------------------------------------- #select { true }.size for 100000 15.000 i/100ms #count { true } for 100000 21.000 i/100ms Calculating ------------------------------------- #select { true }.size for 100000 170.963 (± 4.1%) i/s - 855.000 in 5.010050s #count { true } for 100000 211.185 (± 4.7%) i/s - 1.071k in 5.083109s rspec-expectations-3.13.0/benchmarks/default_messages_as_methods_v_blocks.rb000066400000000000000000000007341455770000100274660ustar00rootroot00000000000000require 'benchmark' require 'rspec/expectations' include RSpec::Expectations include RSpec::Matchers RSpec::Matchers.define :eq_using_dsl do |expected| match do |actual| actual == expected end end n = 10_000 Benchmark.benchmark do |bm| 3.times do bm.report do n.times do eq_using_dsl(5).tap do |m| m.description m.failure_message_for_should m.failure_message_for_should_not end end end end end rspec-expectations-3.13.0/benchmarks/example_spec.rb000066400000000000000000000002301455770000100225170ustar00rootroot00000000000000describe "something" do it "does something that passes" do 1.should eq(1) end it "does something that fails" do 1.should eq(2) end end rspec-expectations-3.13.0/benchmarks/gsub_vs_tr_single_character.rb000066400000000000000000000011611455770000100256100ustar00rootroot00000000000000require 'benchmark/ips' Benchmark.ips do |x| y = '1_2_3_4_5_6_7_8_9_10' x.report('gsub') do |_times| y.tr('_', ' ') end x.report('tr') do |_times| y.tr('_', ' ') end x.compare! end __END__ Calculating ------------------------------------- gsub 29.483k i/100ms tr 79.170k i/100ms ------------------------------------------------- gsub 10.420B (±23.7%) i/s - 31.106B tr 78.139B (±20.6%) i/s - 129.289B Comparison: tr: 78139428607.9 i/s gsub: 10419757735.7 i/s - 7.50x slower rspec-expectations-3.13.0/benchmarks/include_matcher.rb000066400000000000000000000153251455770000100232130ustar00rootroot00000000000000require 'benchmark/ips' require 'rspec/expectations' include RSpec::Matchers module RSpec module Matchers module BuiltIn class OldInclude < BaseMatcher def initialize(*expected) @expected = expected end def matches?(actual) @actual = actual perform_match(:all?, :all?) end def does_not_match?(actual) @actual = actual perform_match(:none?, :any?) end def description described_items = surface_descriptions_in(expected) item_list = EnglishPhrasing.list(described_items) improve_hash_formatting "include#{item_list}" end def failure_message improve_hash_formatting(super) + invalid_object_message end def failure_message_when_negated improve_hash_formatting(super) + invalid_object_message end def diffable? !diff_would_wrongly_highlight_matched_item? end private def invalid_object_message return '' if actual.respond_to?(:include?) ", but it does not respond to `include?`" end def perform_match(predicate, hash_subset_predicate) return false unless actual.respond_to?(:include?) expected.__send__(predicate) do |expected_item| if comparing_hash_to_a_subset?(expected_item) expected_item.__send__(hash_subset_predicate) do |(key, value)| actual_hash_includes?(key, value) end elsif comparing_hash_keys?(expected_item) actual_hash_has_key?(expected_item) else actual_collection_includes?(expected_item) end end end def comparing_hash_to_a_subset?(expected_item) actual.is_a?(Hash) && expected_item.is_a?(Hash) end def actual_hash_includes?(expected_key, expected_value) actual_value = actual.fetch(expected_key) { return false } values_match?(expected_value, actual_value) end def comparing_hash_keys?(expected_item) actual.is_a?(Hash) && !expected_item.is_a?(Hash) end def actual_hash_has_key?(expected_key) actual.key?(expected_key) || actual.keys.any? { |key| values_match?(expected_key, key) } end def actual_collection_includes?(expected_item) return true if actual.include?(expected_item) return false unless actual.respond_to?(:any?) actual.any? { |value| values_match?(expected_item, value) } end def diff_would_wrongly_highlight_matched_item? return false unless actual.is_a?(String) && expected.is_a?(Array) lines = actual.split("\n") expected.any? do |str| actual.include?(str) && lines.none? { |line| line == str } end end end end def old_include(*expected) BuiltIn::OldInclude.new(*expected) end end end array_sizes = [10, 50, 100, 500] # *maniacal laugh* class << self; alias_method :inc, :include; remove_method :include; end Benchmark.ips do |x| x.report("Old `to include` successes") do array_sizes.each do |n| expect([*1..n]).to old_include(*n/2..n) end end x.report("New `to include` successes") do array_sizes.each do |n| expect([*1..n]).to include(*n/2..n) end end x.compare! end Benchmark.ips do |x| x.report("Old `to include` failures") do array_sizes.each do |n| begin expect([*1..n]).to old_include(*n+1..n*1.5) rescue RSpec::Expectations::ExpectationNotMetError end end end x.report("New `to include` failures") do array_sizes.each do |n| begin expect([*1..n]).to include(*n+1..n*1.5) rescue RSpec::Expectations::ExpectationNotMetError end end end x.compare! end Benchmark.ips do |x| x.report("Old `to not include` successes") do array_sizes.each do |n| expect([*1..n]).to_not old_include(*n+1..n*1.5) end end x.report("New `to not include` successes") do array_sizes.each do |n| expect([*1..n]).to_not include(*n+1..n*1.5) end end x.compare! end Benchmark.ips do |x| x.report("Old `to not include` failures") do array_sizes.each do |n| begin expect([*1..n]).to_not old_include(*n/2..n) rescue RSpec::Expectations::ExpectationNotMetError end end end x.report("New `to not include` failures") do array_sizes.each do |n| begin expect([*1..n]).to_not include(*n/2..n) rescue RSpec::Expectations::ExpectationNotMetError end end end x.compare! end __END__ Calculating ------------------------------------- Old `to include` successes 30.000 i/100ms New `to include` successes 28.000 i/100ms ------------------------------------------------- Old `to include` successes 307.740 (± 4.2%) i/s - 1.560k New `to include` successes 299.321 (± 2.7%) i/s - 1.512k Comparison: Old `to include` successes: 307.7 i/s New `to include` successes: 299.3 i/s - 1.03x slower Calculating ------------------------------------- Old `to include` failures 2.000 i/100ms New `to include` failures 1.000 i/100ms ------------------------------------------------- Old `to include` failures 20.611 (± 4.9%) i/s - 104.000 New `to include` failures 2.990 (± 0.0%) i/s - 15.000 Comparison: Old `to include` failures: 20.6 i/s New `to include` failures: 3.0 i/s - 6.89x slower Calculating ------------------------------------- Old `to not include` successes 1.000 i/100ms New `to not include` successes 1.000 i/100ms ------------------------------------------------- Old `to not include` successes 3.505 (± 0.0%) i/s - 18.000 New `to not include` successes 3.475 (± 0.0%) i/s - 18.000 Comparison: Old `to not include` successes: 3.5 i/s New `to not include` successes: 3.5 i/s - 1.01x slower Calculating ------------------------------------- Old `to not include` failures 2.000 i/100ms New `to include` failures 1.000 i/100ms ------------------------------------------------- Old `to not include` failures 21.187 (± 4.7%) i/s - 106.000 New `to include` failures 19.899 (± 5.0%) i/s - 100.000 Comparison: Old `to not include` failures: 21.2 i/s New `to include` failures: 19.9 i/s - 1.06x slower rspec-expectations-3.13.0/benchmarks/include_v_superclass.rb000066400000000000000000000013411455770000100242720ustar00rootroot00000000000000require 'benchmark' n = 10_000 class Foo; end module Bar; end Benchmark.benchmark do |bm| puts "Class.new(Foo)" 3.times do bm.report do n.times do Class.new(Foo) end end end puts "Class.new { include Bar }" 3.times do bm.report do n.times do Class.new { include Bar } end end end end # $ ruby benchmarks/include_v_superclass.rb # Class.new(Foo) # 0.030000 0.000000 0.030000 ( 0.033536) # 0.020000 0.000000 0.020000 ( 0.022077) # 0.040000 0.010000 0.050000 ( 0.035813) # Class.new { include Bar } # 0.040000 0.000000 0.040000 ( 0.041427) # 0.040000 0.000000 0.040000 ( 0.039019) # 0.030000 0.000000 0.030000 ( 0.037018) rspec-expectations-3.13.0/benchmarks/match_array/000077500000000000000000000000001455770000100220245ustar00rootroot00000000000000rspec-expectations-3.13.0/benchmarks/match_array/failing_with_distinct_items.rb000066400000000000000000000143371455770000100301270ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'benchmark' require 'rspec/expectations' require 'securerandom' extend RSpec::Matchers sizes = [10, 100, 1000, 2000, 4000] puts "rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}" puts puts "Failing `match_array` expectation with lists of distinct strings having 1 unmatched pair" puts Benchmark.benchmark do |bm| sizes.each do |size| actual = Array.new(size) { SecureRandom.uuid } expecteds = Array.new(3) do array = actual.shuffle # replace one entry with a different value array[rand(array.length)] = SecureRandom.uuid array end expecteds.each do |expected| bm.report("#{size.to_s.rjust(5)} items") do begin expect(actual).to match_array(expected) rescue RSpec::Expectations::ExpectationNotMetError else raise "did not fail but should have" end end end end end __END__ Before new composable matchers algo: 10 items 0.000000 0.000000 0.000000 ( 0.000813) 10 items 0.000000 0.000000 0.000000 ( 0.000099) 10 items 0.000000 0.000000 0.000000 ( 0.000127) 100 items 0.000000 0.000000 0.000000 ( 0.000707) 100 items 0.000000 0.000000 0.000000 ( 0.000612) 100 items 0.000000 0.000000 0.000000 ( 0.000600) 1000 items 0.040000 0.000000 0.040000 ( 0.038679) 1000 items 0.040000 0.000000 0.040000 ( 0.041379) 1000 items 0.040000 0.000000 0.040000 ( 0.036680) 2000 items 0.130000 0.000000 0.130000 ( 0.131681) 2000 items 0.120000 0.000000 0.120000 ( 0.123664) 2000 items 0.130000 0.000000 0.130000 ( 0.128799) 4000 items 0.490000 0.000000 0.490000 ( 0.489446) 4000 items 0.510000 0.000000 0.510000 ( 0.511915) 4000 items 0.480000 0.010000 0.490000 ( 0.477616) After: 10 items 0.000000 0.000000 0.000000 ( 0.001382) 10 items 0.000000 0.000000 0.000000 ( 0.000156) 10 items 0.000000 0.000000 0.000000 ( 0.000161) 100 items 0.010000 0.000000 0.010000 ( 0.005052) 100 items 0.000000 0.000000 0.000000 ( 0.004991) 100 items 0.010000 0.000000 0.010000 ( 0.004984) 1000 items 0.470000 0.000000 0.470000 ( 0.470043) 1000 items 0.500000 0.000000 0.500000 ( 0.499316) 1000 items 0.490000 0.000000 0.490000 ( 0.488582) 2000 items 1.910000 0.000000 1.910000 ( 1.917279) 2000 items 1.930000 0.010000 1.940000 ( 1.931002) 2000 items 1.920000 0.000000 1.920000 ( 1.928989) 4000 items 7.860000 0.010000 7.870000 ( 7.881995) 4000 items 7.980000 0.010000 7.990000 ( 8.003643) 4000 items 8.000000 0.010000 8.010000 ( 8.031382) With "smaller subproblem" optimization: (about 25% slower) 10 items 0.010000 0.000000 0.010000 ( 0.001331) 10 items 0.000000 0.000000 0.000000 ( 0.000175) 10 items 0.000000 0.000000 0.000000 ( 0.000165) 100 items 0.000000 0.000000 0.000000 ( 0.006137) 100 items 0.010000 0.000000 0.010000 ( 0.005880) 100 items 0.000000 0.000000 0.000000 ( 0.005950) 1000 items 0.630000 0.000000 0.630000 ( 0.634294) 1000 items 0.620000 0.000000 0.620000 ( 0.622427) 1000 items 0.640000 0.000000 0.640000 ( 0.641505) 2000 items 2.420000 0.000000 2.420000 ( 2.419876) 2000 items 2.430000 0.000000 2.430000 ( 2.442544) 2000 items 2.380000 0.010000 2.390000 ( 2.385106) 4000 items 9.780000 0.010000 9.790000 ( 9.811499) 4000 items 9.670000 0.010000 9.680000 ( 9.688799) 4000 items 9.710000 0.010000 9.720000 ( 9.743054) With "implement `values_match?` ourselves" optimization: (more than twice as fast!) 10 items 0.000000 0.000000 0.000000 ( 0.001189) 10 items 0.000000 0.000000 0.000000 ( 0.000149) 10 items 0.000000 0.000000 0.000000 ( 0.000130) 100 items 0.000000 0.000000 0.000000 ( 0.002927) 100 items 0.000000 0.000000 0.000000 ( 0.002856) 100 items 0.010000 0.000000 0.010000 ( 0.003028) 1000 items 0.250000 0.000000 0.250000 ( 0.245146) 1000 items 0.240000 0.000000 0.240000 ( 0.246291) 1000 items 0.320000 0.000000 0.320000 ( 0.315192) 2000 items 1.120000 0.000000 1.120000 ( 1.128162) 2000 items 1.030000 0.000000 1.030000 ( 1.034982) 2000 items 1.060000 0.000000 1.060000 ( 1.063870) 4000 items 4.530000 0.000000 4.530000 ( 4.556346) 4000 items 4.400000 0.010000 4.410000 ( 4.414447) 4000 items 4.410000 0.000000 4.410000 ( 4.417440) With e === a || a == e || values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.001466) 10 items 0.000000 0.000000 0.000000 ( 0.000258) 10 items 0.000000 0.000000 0.000000 ( 0.000251) 100 items 0.020000 0.000000 0.020000 ( 0.012369) 100 items 0.010000 0.000000 0.010000 ( 0.012345) 100 items 0.010000 0.000000 0.010000 ( 0.012744) 1000 items 1.180000 0.000000 1.180000 ( 1.187754) 1000 items 1.200000 0.000000 1.200000 ( 1.198681) 1000 items 1.210000 0.000000 1.210000 ( 1.210159) 2000 items 4.760000 0.000000 4.760000 ( 4.764911) 2000 items 4.760000 0.000000 4.760000 ( 4.757022) 2000 items 4.760000 0.000000 4.760000 ( 4.771776) 4000 items 19.070000 0.010000 19.080000 ( 19.077930) 4000 items 19.090000 0.010000 19.100000 ( 19.104171) 4000 items 19.260000 0.010000 19.270000 ( 19.289653) With values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.001462) 10 items 0.000000 0.000000 0.000000 ( 0.000253) 10 items 0.000000 0.000000 0.000000 ( 0.000244) 100 items 0.010000 0.000000 0.010000 ( 0.011913) 100 items 0.010000 0.000000 0.010000 ( 0.011858) 100 items 0.020000 0.000000 0.020000 ( 0.011992) 1000 items 1.210000 0.000000 1.210000 ( 1.226960) 1000 items 1.140000 0.000000 1.140000 ( 1.147002) 1000 items 1.180000 0.000000 1.180000 ( 1.194010) 2000 items 4.690000 0.010000 4.700000 ( 4.740503) 2000 items 4.680000 0.000000 4.680000 ( 4.676084) 2000 items 4.570000 0.000000 4.570000 ( 4.581262) 4000 items 18.450000 0.010000 18.460000 ( 18.532578) 4000 items 18.400000 0.010000 18.410000 ( 18.520454) 4000 items 18.490000 0.020000 18.510000 ( 18.592491) rspec-expectations-3.13.0/benchmarks/match_array/failing_with_duplicate_items.rb000066400000000000000000000111611455770000100302500ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'benchmark' require 'rspec/expectations' extend RSpec::Matchers sizes = [10, 100, 1000] puts "rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}" puts puts "Failing `match_array` expectation with lists of integers (w/dups) having 1 unmatched pair" puts Benchmark.benchmark do |bm| sizes.each do |size| actual = Array.new(size) { rand(size / 2) } expecteds = Array.new(3) do array = actual.shuffle array[rand(array.length)] = 9_999_999 array end expecteds.each do |expected| bm.report("#{size.to_s.rjust(5)} items") do begin expect(actual).to match_array(expected) rescue RSpec::Expectations::ExpectationNotMetError else raise "did not fail but should have" end end end end end __END__ Before new composable matchers algo: 10 items 0.000000 0.000000 0.000000 ( 0.000711) 10 items 0.000000 0.000000 0.000000 ( 0.000079) 10 items 0.000000 0.000000 0.000000 ( 0.000080) 20 items 0.000000 0.000000 0.000000 ( 0.000105) 20 items 0.000000 0.000000 0.000000 ( 0.000122) 20 items 0.000000 0.000000 0.000000 ( 0.000101) 25 items 0.000000 0.000000 0.000000 ( 0.000125) 25 items 0.000000 0.000000 0.000000 ( 0.000137) 25 items 0.000000 0.000000 0.000000 ( 0.000116) After: This varies widly based on the inputs. One run: 10 items 0.010000 0.000000 0.010000 ( 0.005884) 10 items 0.000000 0.000000 0.000000 ( 0.004429) 10 items 0.000000 0.000000 0.000000 ( 0.004733) 20 items 2.040000 0.000000 2.040000 ( 2.049461) 20 items 2.080000 0.010000 2.090000 ( 2.087983) 20 items 1.950000 0.000000 1.950000 ( 1.950013) 25 items 10.240000 0.020000 10.260000 ( 10.280575) 25 items 10.390000 0.010000 10.400000 ( 10.433754) 25 items 10.250000 0.020000 10.270000 ( 10.311604) Another run: 10 items 0.010000 0.010000 0.020000 ( 0.015355) 10 items 0.010000 0.000000 0.010000 ( 0.010347) 10 items 0.020000 0.000000 0.020000 ( 0.013657) 20 items 36.140000 0.030000 36.170000 ( 36.236651) 20 items 36.010000 0.040000 36.050000 ( 36.098006) 20 items 35.990000 0.030000 36.020000 ( 36.071397) (I lost patience and didn't wait for it to finish 25 items...) With "smaller subproblem" optimization: (way faster!) 10 items 0.000000 0.000000 0.000000 ( 0.001411) 10 items 0.000000 0.000000 0.000000 ( 0.000615) 10 items 0.000000 0.000000 0.000000 ( 0.000413) 20 items 0.000000 0.000000 0.000000 ( 0.000947) 20 items 0.000000 0.000000 0.000000 ( 0.001725) 20 items 0.000000 0.000000 0.000000 ( 0.001345) 25 items 0.010000 0.000000 0.010000 ( 0.002348) 25 items 0.000000 0.000000 0.000000 ( 0.002836) 25 items 0.000000 0.000000 0.000000 ( 0.002721) With "implement `values_match?` ourselves" optimization: (about twice as fast!) 10 items 0.000000 0.000000 0.000000 ( 0.002450) 10 items 0.000000 0.000000 0.000000 ( 0.000857) 10 items 0.000000 0.000000 0.000000 ( 0.000883) 100 items 0.040000 0.000000 0.040000 ( 0.043661) 100 items 0.060000 0.000000 0.060000 ( 0.053046) 100 items 0.040000 0.010000 0.050000 ( 0.051760) 1000 items 3.620000 0.060000 3.680000 ( 3.688289) 1000 items 2.600000 0.020000 2.620000 ( 2.628405) 1000 items 4.660000 0.040000 4.700000 ( 4.712196) With e === a || a == e || values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.001992) 10 items 0.000000 0.000000 0.000000 ( 0.000821) 10 items 0.000000 0.000000 0.000000 ( 0.000794) 100 items 0.060000 0.000000 0.060000 ( 0.068597) 100 items 0.060000 0.000000 0.060000 ( 0.056409) 100 items 0.070000 0.010000 0.080000 ( 0.072950) 1000 items 4.090000 0.100000 4.190000 ( 4.218107) 1000 items 3.000000 0.050000 3.050000 ( 3.070019) 1000 items 6.040000 0.070000 6.110000 ( 6.102311) With values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.002177) 10 items 0.000000 0.000000 0.000000 ( 0.001201) 10 items 0.000000 0.000000 0.000000 ( 0.000928) 100 items 0.050000 0.000000 0.050000 ( 0.051785) 100 items 0.040000 0.000000 0.040000 ( 0.032323) 100 items 0.040000 0.000000 0.040000 ( 0.046934) 1000 items 4.050000 0.100000 4.150000 ( 4.175914) 1000 items 3.040000 0.050000 3.090000 ( 3.130656) 1000 items 4.110000 0.050000 4.160000 ( 4.161170) rspec-expectations-3.13.0/benchmarks/match_array/passing_with_distinct_items.rb000066400000000000000000000155231455770000100301600ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'benchmark' require 'rspec/expectations' require 'securerandom' extend RSpec::Matchers sizes = [10, 100, 1000, 2000, 4000] puts "rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}" puts puts "Passing `match_array` expectation with lists of distinct strings" puts Benchmark.benchmark do |bm| sizes.each do |size| actual = Array.new(size) { SecureRandom.uuid } expecteds = Array.new(3) { actual.shuffle } expecteds.each do |expected| bm.report("#{size.to_s.rjust(5)} items") do expect(actual).to match_array(expected) end end end end __END__ Before new composable matchers algo: 10 items 0.000000 0.000000 0.000000 ( 0.000857) 10 items 0.000000 0.000000 0.000000 ( 0.000029) 10 items 0.000000 0.000000 0.000000 ( 0.000018) 100 items 0.000000 0.000000 0.000000 ( 0.000334) 100 items 0.000000 0.000000 0.000000 ( 0.000372) 100 items 0.000000 0.000000 0.000000 ( 0.000331) 1000 items 0.030000 0.000000 0.030000 ( 0.029778) 1000 items 0.030000 0.000000 0.030000 ( 0.030566) 1000 items 0.030000 0.000000 0.030000 ( 0.033150) 2000 items 0.140000 0.000000 0.140000 ( 0.141719) 2000 items 0.120000 0.000000 0.120000 ( 0.124348) 2000 items 0.120000 0.000000 0.120000 ( 0.121202) 4000 items 0.490000 0.000000 0.490000 ( 0.500631) 4000 items 0.470000 0.000000 0.470000 ( 0.468477) 4000 items 0.490000 0.010000 0.500000 ( 0.492957) After: 10 items 0.000000 0.000000 0.000000 ( 0.001165) 10 items 0.000000 0.000000 0.000000 ( 0.000131) 10 items 0.000000 0.000000 0.000000 ( 0.000127) 100 items 0.000000 0.000000 0.000000 ( 0.005636) 100 items 0.010000 0.000000 0.010000 ( 0.004881) 100 items 0.000000 0.000000 0.000000 ( 0.004676) 1000 items 0.500000 0.000000 0.500000 ( 0.505676) 1000 items 0.490000 0.000000 0.490000 ( 0.483469) 1000 items 0.490000 0.000000 0.490000 ( 0.497841) 2000 items 1.950000 0.000000 1.950000 ( 1.966324) 2000 items 1.970000 0.000000 1.970000 ( 1.975567) 2000 items 1.900000 0.000000 1.900000 ( 1.902315) 4000 items 7.650000 0.010000 7.660000 ( 7.672907) 4000 items 7.720000 0.010000 7.730000 ( 7.735615) 4000 items 7.730000 0.000000 7.730000 ( 7.756837) With "smaller subproblem" optimization: (about 20% slower) 10 items 0.000000 0.000000 0.000000 ( 0.001099) 10 items 0.000000 0.000000 0.000000 ( 0.000110) 10 items 0.000000 0.000000 0.000000 ( 0.000102) 100 items 0.010000 0.000000 0.010000 ( 0.005462) 100 items 0.010000 0.000000 0.010000 ( 0.005433) 100 items 0.000000 0.000000 0.000000 ( 0.005409) 1000 items 0.570000 0.000000 0.570000 ( 0.569302) 1000 items 0.570000 0.000000 0.570000 ( 0.577496) 1000 items 0.560000 0.000000 0.560000 ( 0.555496) 2000 items 2.330000 0.000000 2.330000 ( 2.325537) 2000 items 2.450000 0.000000 2.450000 ( 2.464415) 2000 items 2.470000 0.000000 2.470000 ( 2.472999) 4000 items 9.380000 0.010000 9.390000 ( 9.406678) 4000 items 9.320000 0.010000 9.330000 ( 9.340727) 4000 items 9.330000 0.010000 9.340000 ( 9.358326) With "implement `values_match?` ourselves" optimization: (about twice as fast!) 10 items 0.000000 0.000000 0.000000 ( 0.001113) 10 items 0.000000 0.000000 0.000000 ( 0.000074) 10 items 0.000000 0.000000 0.000000 ( 0.000071) 100 items 0.000000 0.000000 0.000000 ( 0.002558) 100 items 0.010000 0.000000 0.010000 ( 0.002528) 100 items 0.000000 0.000000 0.000000 ( 0.002555) 1000 items 0.300000 0.000000 0.300000 ( 0.306318) 1000 items 0.260000 0.000000 0.260000 ( 0.253526) 1000 items 0.240000 0.000000 0.240000 ( 0.246096) 2000 items 1.070000 0.000000 1.070000 ( 1.065989) 2000 items 1.040000 0.000000 1.040000 ( 1.047495) 2000 items 1.080000 0.000000 1.080000 ( 1.078392) 4000 items 4.520000 0.000000 4.520000 ( 4.529568) 4000 items 4.570000 0.010000 4.580000 ( 4.597785) 4000 items 5.030000 0.010000 5.040000 ( 5.079452) With `match_when_sorted?` optimization: (many orders of magnitude faster!) 10 items 0.010000 0.000000 0.010000 ( 0.002044) 10 items 0.000000 0.000000 0.000000 ( 0.000038) 10 items 0.000000 0.000000 0.000000 ( 0.000031) 100 items 0.000000 0.000000 0.000000 ( 0.000149) 100 items 0.000000 0.000000 0.000000 ( 0.000137) 100 items 0.000000 0.000000 0.000000 ( 0.000136) 1000 items 0.000000 0.000000 0.000000 ( 0.001426) 1000 items 0.000000 0.000000 0.000000 ( 0.001369) 1000 items 0.000000 0.000000 0.000000 ( 0.001355) 2000 items 0.010000 0.000000 0.010000 ( 0.003304) 2000 items 0.000000 0.000000 0.000000 ( 0.002192) 2000 items 0.000000 0.000000 0.000000 ( 0.002849) 4000 items 0.000000 0.000000 0.000000 ( 0.007730) 4000 items 0.010000 0.000000 0.010000 ( 0.006074) 4000 items 0.010000 0.000000 0.010000 ( 0.006514) With e === a || a == e || values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.002202) 10 items 0.000000 0.000000 0.000000 ( 0.000054) 10 items 0.000000 0.000000 0.000000 ( 0.000046) 100 items 0.000000 0.000000 0.000000 ( 0.000203) 100 items 0.000000 0.000000 0.000000 ( 0.000199) 100 items 0.000000 0.000000 0.000000 ( 0.000192) 1000 items 0.010000 0.000000 0.010000 ( 0.001438) 1000 items 0.000000 0.000000 0.000000 ( 0.001419) 1000 items 0.000000 0.000000 0.000000 ( 0.001474) 2000 items 0.010000 0.000000 0.010000 ( 0.003341) 2000 items 0.000000 0.000000 0.000000 ( 0.003224) 2000 items 0.000000 0.000000 0.000000 ( 0.003251) 4000 items 0.010000 0.000000 0.010000 ( 0.007156) 4000 items 0.010000 0.000000 0.010000 ( 0.006715) 4000 items 0.000000 0.000000 0.000000 ( 0.006676) With values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.001173) 10 items 0.000000 0.000000 0.000000 ( 0.000051) 10 items 0.000000 0.000000 0.000000 ( 0.000026) 100 items 0.000000 0.000000 0.000000 ( 0.000171) 100 items 0.000000 0.000000 0.000000 ( 0.000138) 100 items 0.000000 0.000000 0.000000 ( 0.000136) 1000 items 0.010000 0.000000 0.010000 ( 0.001506) 1000 items 0.000000 0.000000 0.000000 ( 0.001486) 1000 items 0.000000 0.000000 0.000000 ( 0.001510) 2000 items 0.010000 0.000000 0.010000 ( 0.003153) 2000 items 0.000000 0.010000 0.010000 ( 0.003883) 2000 items 0.000000 0.000000 0.000000 ( 0.003199) 4000 items 0.010000 0.000000 0.010000 ( 0.007178) 4000 items 0.000000 0.000000 0.000000 ( 0.006629) 4000 items 0.010000 0.000000 0.010000 ( 0.006435) rspec-expectations-3.13.0/benchmarks/match_array/passing_with_duplicate_items.rb000066400000000000000000000132251455770000100303060ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'benchmark' require 'rspec/expectations' extend RSpec::Matchers sizes = [10, 100, 1000, 2000] puts "rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}" puts puts "Passing `match_array` expectation with lists of integers including duplicate values" puts Benchmark.benchmark do |bm| sizes.each do |size| actual = Array.new(size) { rand(size / 2) } expecteds = Array.new(3) { actual.shuffle } expecteds.each do |expected| bm.report("#{size.to_s.rjust(5)} items") do expect(actual).to match_array(expected) end end end end __END__ Before new composable matchers algo: 10 items 0.000000 0.000000 0.000000 ( 0.000665) 10 items 0.000000 0.000000 0.000000 ( 0.000027) 10 items 0.000000 0.000000 0.000000 ( 0.000015) 100 items 0.000000 0.000000 0.000000 ( 0.000250) 100 items 0.000000 0.000000 0.000000 ( 0.000176) 100 items 0.000000 0.000000 0.000000 ( 0.000181) 1000 items 0.010000 0.000000 0.010000 ( 0.013612) 1000 items 0.020000 0.000000 0.020000 ( 0.013409) 1000 items 0.020000 0.000000 0.020000 ( 0.018222) 2000 items 0.060000 0.000000 0.060000 ( 0.057428) 2000 items 0.060000 0.000000 0.060000 ( 0.058242) 2000 items 0.060000 0.000000 0.060000 ( 0.063026) After: 10 items 0.000000 0.000000 0.000000 ( 0.001835) 10 items 0.000000 0.000000 0.000000 ( 0.000327) 10 items 0.000000 0.000000 0.000000 ( 0.000336) 100 items 0.030000 0.000000 0.030000 ( 0.025134) 100 items 0.030000 0.000000 0.030000 ( 0.032476) 100 items 0.020000 0.000000 0.020000 ( 0.024273) 1000 items 2.600000 0.040000 2.640000 ( 2.649328) 1000 items 2.510000 0.020000 2.530000 ( 2.523448) 1000 items 2.470000 0.000000 2.470000 ( 2.476770) 2000 items 11.590000 0.110000 11.700000 ( 11.719525) 2000 items 10.750000 0.080000 10.830000 ( 10.845655) 2000 items 11.140000 0.080000 11.220000 ( 11.241852) With "smaller subproblem" optimization: (about 35% faster) 10 items 0.000000 0.000000 0.000000 ( 0.001236) 10 items 0.000000 0.000000 0.000000 ( 0.000278) 10 items 0.000000 0.000000 0.000000 ( 0.000293) 100 items 0.010000 0.000000 0.010000 ( 0.013229) 100 items 0.020000 0.000000 0.020000 ( 0.013932) 100 items 0.020000 0.000000 0.020000 ( 0.019739) 1000 items 1.580000 0.030000 1.610000 ( 1.622586) 1000 items 1.670000 0.020000 1.690000 ( 1.683174) 1000 items 1.570000 0.010000 1.580000 ( 1.588718) 2000 items 7.030000 0.100000 7.130000 ( 7.139178) 2000 items 7.220000 0.090000 7.310000 ( 7.328606) 2000 items 6.930000 0.130000 7.060000 ( 7.070295) With "implement `values_match?` ourselves" optimization: (about 20% faster) 10 items 0.000000 0.000000 0.000000 ( 0.001352) 10 items 0.000000 0.000000 0.000000 ( 0.000313) 10 items 0.000000 0.000000 0.000000 ( 0.000298) 100 items 0.010000 0.000000 0.010000 ( 0.011200) 100 items 0.010000 0.000000 0.010000 ( 0.013465) 100 items 0.020000 0.000000 0.020000 ( 0.021589) 1000 items 1.320000 0.030000 1.350000 ( 1.350071) 1000 items 1.280000 0.020000 1.300000 ( 1.298206) 1000 items 1.370000 0.010000 1.380000 ( 1.392149) 2000 items 6.120000 0.110000 6.230000 ( 6.252104) 2000 items 6.170000 0.090000 6.260000 ( 6.270807) 2000 items 5.910000 0.150000 6.060000 ( 6.066389) With `match_when_sorted?` optimization: (many orders of magnitude faster!) 10 items 0.000000 0.000000 0.000000 ( 0.001134) 10 items 0.000000 0.000000 0.000000 ( 0.000029) 10 items 0.000000 0.000000 0.000000 ( 0.000020) 100 items 0.000000 0.000000 0.000000 ( 0.000070) 100 items 0.000000 0.000000 0.000000 ( 0.000066) 100 items 0.000000 0.000000 0.000000 ( 0.000065) 1000 items 0.000000 0.000000 0.000000 ( 0.000612) 1000 items 0.000000 0.000000 0.000000 ( 0.000608) 1000 items 0.000000 0.000000 0.000000 ( 0.000613) 2000 items 0.010000 0.000000 0.010000 ( 0.001235) 2000 items 0.000000 0.000000 0.000000 ( 0.001282) 2000 items 0.000000 0.000000 0.000000 ( 0.001227) With e === a || a == e || values_match?(e,a) 10 items 0.010000 0.000000 0.010000 ( 0.001258) 10 items 0.000000 0.000000 0.000000 ( 0.000034) 10 items 0.000000 0.000000 0.000000 ( 0.000027) 100 items 0.000000 0.000000 0.000000 ( 0.000124) 100 items 0.000000 0.000000 0.000000 ( 0.000151) 100 items 0.000000 0.000000 0.000000 ( 0.000121) 1000 items 0.000000 0.000000 0.000000 ( 0.001212) 1000 items 0.000000 0.000000 0.000000 ( 0.001193) 1000 items 0.000000 0.000000 0.000000 ( 0.001293) 2000 items 0.000000 0.000000 0.000000 ( 0.002433) 2000 items 0.010000 0.000000 0.010000 ( 0.002351) 2000 items 0.000000 0.000000 0.000000 ( 0.002404) With values_match?(e,a) 10 items 0.000000 0.000000 0.000000 ( 0.001202) 10 items 0.000000 0.000000 0.000000 ( 0.000028) 10 items 0.000000 0.000000 0.000000 ( 0.000024) 100 items 0.000000 0.000000 0.000000 ( 0.000147) 100 items 0.000000 0.000000 0.000000 ( 0.000122) 100 items 0.000000 0.000000 0.000000 ( 0.000142) 1000 items 0.000000 0.000000 0.000000 ( 0.001201) 1000 items 0.000000 0.000000 0.000000 ( 0.001233) 1000 items 0.000000 0.000000 0.000000 ( 0.001221) 2000 items 0.010000 0.000000 0.010000 ( 0.002382) 2000 items 0.000000 0.000000 0.000000 ( 0.002353) 2000 items 0.000000 0.000000 0.000000 ( 0.002371) rspec-expectations-3.13.0/benchmarks/match_array/rubyprof/000077500000000000000000000000001455770000100236745ustar00rootroot00000000000000rspec-expectations-3.13.0/benchmarks/match_array/rubyprof/passing_with_distinct_items.rb000066400000000000000000000003351455770000100320230ustar00rootroot00000000000000$LOAD_PATH.unshift "./lib" require 'rspec/expectations' require 'securerandom' extend RSpec::Matchers actual = Array.new(1000) { SecureRandom.uuid } expected = actual.shuffle expect(actual).to match_array(expected) rspec-expectations-3.13.0/benchmarks/matcher_dsl_vs_classes.rb000066400000000000000000000115651455770000100246010ustar00rootroot00000000000000require 'benchmark' require 'rspec/expectations' include RSpec::Expectations include RSpec::Matchers RSpec::Matchers.define :eq_using_dsl do |expected| match do |actual| actual == expected end end n = 1000 puts "3 runs of #{n} times for each example running #{RUBY_ENGINE}/#{RUBY_VERSION}" puts "passing examples: 5.should eq(5)" puts "* using the DSL" Benchmark.benchmark do |bm| 3.times do bm.report do n.times do 5.should eq_using_dsl(5) end end end end puts puts "* using a class" Benchmark.benchmark do |bm| 3.times do bm.report do n.times do 5.should eq(5) end end end end puts puts "failing examples: 5.should eq(3)" puts "* using the DSL" Benchmark.benchmark do |bm| 3.times do bm.report do n.times do 5.should eq_using_dsl(3) rescue nil end end end end puts puts "* using a class" Benchmark.benchmark do |bm| 3.times do bm.report do n.times do 5.should eq(3) rescue nil end end end end # 3 runs of 1000 times for each example running ruby/1.8.7 # passing examples: 5.should eq(5) # * using the DSL # 0.340000 0.000000 0.340000 ( 0.342052) # 0.330000 0.010000 0.340000 ( 0.340618) # 0.340000 0.000000 0.340000 ( 0.339149) # # * using a class # 0.000000 0.000000 0.000000 ( 0.003762) # 0.010000 0.000000 0.010000 ( 0.004192) # 0.000000 0.000000 0.000000 ( 0.003791) # # failing examples: 5.should eq(3) # * using the DSL # 0.380000 0.000000 0.380000 ( 0.384415) # 0.380000 0.010000 0.390000 ( 0.381604) # 0.370000 0.000000 0.370000 ( 0.380255) # # * using a class # 0.040000 0.000000 0.040000 ( 0.034528) # 0.030000 0.000000 0.030000 ( 0.032021) # 0.060000 0.010000 0.070000 ( 0.067579) # # 3 runs of 1000 times for each example running ruby/1.9.2 # passing examples: 5.should eq(5) # * using the DSL # 0.250000 0.010000 0.260000 ( 0.249692) # 0.250000 0.000000 0.250000 ( 0.253856) # 0.230000 0.000000 0.230000 ( 0.232787) # # * using a class # 0.000000 0.000000 0.000000 ( 0.001069) # 0.000000 0.000000 0.000000 ( 0.001041) # 0.000000 0.000000 0.000000 ( 0.001023) # # failing examples: 5.should eq(3) # * using the DSL # 0.370000 0.000000 0.370000 ( 0.377139) # 0.360000 0.010000 0.370000 ( 0.358379) # 0.370000 0.000000 0.370000 ( 0.373795) # # * using a class # 0.060000 0.010000 0.070000 ( 0.073325) # 0.050000 0.000000 0.050000 ( 0.053562) # 0.070000 0.000000 0.070000 ( 0.075382) # # 3 runs of 1000 times for each example running ruby/1.9.3 # passing examples: 5.should eq(5) # * using the DSL # 0.210000 0.000000 0.210000 ( 0.219539) # 0.220000 0.010000 0.230000 ( 0.217905) # 0.220000 0.000000 0.220000 ( 0.219657) # # * using a class # 0.000000 0.000000 0.000000 ( 0.001054) # 0.000000 0.000000 0.000000 ( 0.001048) # 0.000000 0.000000 0.000000 ( 0.001035) # # failing examples: 5.should eq(3) # * using the DSL # 0.350000 0.000000 0.350000 ( 0.351742) # 0.360000 0.000000 0.360000 ( 0.362456) # 0.340000 0.010000 0.350000 ( 0.351098) # # * using a class # 0.080000 0.000000 0.080000 ( 0.079964) # 0.080000 0.000000 0.080000 ( 0.076579) # 0.070000 0.000000 0.070000 ( 0.080587) # # 3 runs of 1000 times for each example running rbx/1.8.7 # passing examples: 5.should eq(5) # * using the DSL # 1.926107 0.009784 1.935891 ( 1.629354) # 0.583860 0.004390 0.588250 ( 0.580396) # 0.868571 0.003510 0.872081 ( 0.796644) # # * using a class # 0.002652 0.000013 0.002665 ( 0.002679) # 0.001845 0.000016 0.001861 ( 0.001848) # 0.002656 0.000010 0.002666 ( 0.001823) # # failing examples: 5.should eq(3) # * using the DSL # 0.694148 0.002006 0.696154 ( 0.648551) # 1.063773 0.004653 1.068426 ( 0.998837) # 0.643594 0.001356 0.644950 ( 0.638358) # # * using a class # 0.020139 0.000036 0.020175 ( 0.020161) # 0.097540 0.000575 0.098115 ( 0.084680) # 0.058366 0.000269 0.058635 ( 0.044372) # # 3 runs of 1000 times for each example running jruby/1.8.7 # passing examples: 5.should eq(5) # * using the DSL # 0.355000 0.000000 0.355000 ( 0.355000) # 0.261000 0.000000 0.261000 ( 0.261000) # 0.242000 0.000000 0.242000 ( 0.242000) # # * using a class # 0.007000 0.000000 0.007000 ( 0.007000) # 0.004000 0.000000 0.004000 ( 0.004000) # 0.001000 0.000000 0.001000 ( 0.001000) # # failing examples: 5.should eq(3) # * using the DSL # 0.507000 0.000000 0.507000 ( 0.507000) # 0.468000 0.000000 0.468000 ( 0.468000) # 0.476000 0.000000 0.476000 ( 0.476000) # # * using a class # 0.259000 0.000000 0.259000 ( 0.259000) # 0.521000 0.000000 0.521000 ( 0.521000) # 0.244000 0.000000 0.244000 ( 0.244000) # rspec-expectations-3.13.0/benchmarks/method_to_proc.rb000066400000000000000000000042001455770000100230600ustar00rootroot00000000000000require 'benchmark' n = 10_000_000 puts "3 runs of #{n} times running #{RUBY_ENGINE}/#{RUBY_VERSION}" def foo(x); end def extract_method_proc(&b); b; end Benchmark.benchmark do |bm| puts "calling foo = method(:foo).to_proc" foo_proc = method(:foo).to_proc 3.times do bm.report do n.times { foo_proc.call(1) } end end puts "calling Proc.new { |x| foo(x) }" foo_proc = extract_method_proc { |x| foo(x) } 3.times do bm.report do n.times { foo_proc.call(1) } end end end __END__ Surprisingly, `Method#to_proc` is slower, except on 1.9.3 where it's a wash. 3 runs of 10000000 times running ruby/2.1.1 calling foo = method(:foo).to_proc 2.190000 0.010000 2.200000 ( 2.206627) 2.370000 0.010000 2.380000 ( 2.391100) 2.190000 0.000000 2.190000 ( 2.193119) calling Proc.new { |x| foo(x) } 1.640000 0.000000 1.640000 ( 1.648841) 1.610000 0.000000 1.610000 ( 1.617186) 1.590000 0.010000 1.600000 ( 1.600570) 3 runs of 10000000 times running ruby/2.0.0 calling foo = method(:foo).to_proc 2.170000 0.010000 2.180000 ( 2.192418) 2.140000 0.000000 2.140000 ( 2.141015) 2.150000 0.010000 2.160000 ( 2.172794) calling Proc.new { |x| foo(x) } 1.680000 0.000000 1.680000 ( 1.686904) 1.650000 0.000000 1.650000 ( 1.654465) 1.640000 0.000000 1.640000 ( 1.648229) 3 runs of 10000000 times running ruby/1.9.3 calling foo = method(:foo).to_proc 2.440000 0.010000 2.450000 ( 2.457211) 2.430000 0.000000 2.430000 ( 2.450140) 2.480000 0.010000 2.490000 ( 2.496520) calling Proc.new { |x| foo(x) } 2.400000 0.000000 2.400000 ( 2.415641) 2.480000 0.000000 2.480000 ( 2.489564) 2.460000 0.000000 2.460000 ( 2.477368) 3 runs of 10000000 times running ruby/1.9.2 calling foo = method(:foo).to_proc 2.490000 0.010000 2.500000 ( 2.502401) 2.580000 0.000000 2.580000 ( 2.589306) 2.310000 0.010000 2.320000 ( 2.328342) calling Proc.new { |x| foo(x) } 1.860000 0.000000 1.860000 ( 1.866537) 1.860000 0.000000 1.860000 ( 1.871056) 1.850000 0.010000 1.860000 ( 1.857426) rspec-expectations-3.13.0/benchmarks/output_stringio_vs_tempfile.rb000066400000000000000000000017321455770000100257350ustar00rootroot00000000000000require 'rubygems' require 'bundler/setup' require 'benchmark' require 'rspec/expectations' include RSpec::Matchers n = 100_000 Benchmark.bm(25) do |bm| bm.report("to_stdout with StringIO") do n.times { expect {}.not_to output('foo').to_stdout } end bm.report("to_stdout with Tempfile") do n.times { expect {}.not_to output('foo').to_stdout_from_any_process } end bm.report("to_stderr with StringIO") do n.times { expect {}.not_to output('foo').to_stderr } end bm.report("to_stderr with Tempfile") do n.times { expect {}.not_to output('foo').to_stderr_from_any_process } end end # user system total real # to_stdout with StringIO 0.470000 0.010000 0.480000 ( 0.467317) # to_stdout with Tempfile 8.920000 7.420000 16.340000 ( 16.355174) # to_stderr with StringIO 0.460000 0.000000 0.460000 ( 0.454059) # to_stderr with Tempfile 8.930000 7.560000 16.490000 ( 16.494696) rspec-expectations-3.13.0/benchmarks/set_vs_array_include.rb000066400000000000000000000050151455770000100242640ustar00rootroot00000000000000require 'benchmark' require 'set' n = 10_000_000 array = [ :@name, :@declarations, :@diffable, :@messages, :@match_block, :@match_for_should_not_block, :@expected_exception ] set = array.to_set puts "Positive examples: " Benchmark.bm(25) do |x| array.each_with_index do |var, i| x.report("set.include?(item #{i}) ") do n.times { set.include?(var) } end x.report("array.include?(item #{i})") do n.times { array.include?(var) } end puts "=" * 80 end end puts "\n\nNegative examples: " Benchmark.bm(5) do |x| x.report("set ") do n.times { set.include?(:@other) } end x.report("array") do n.times { array.include?(:@other) } end end # Positive examples: # user system total real # set.include?(item 0) 2.000000 0.010000 2.010000 ( 1.999305) # array.include?(item 0) 1.170000 0.000000 1.170000 ( 1.173168) # ================================================================================ # set.include?(item 1) 2.020000 0.000000 2.020000 ( 2.016389) # array.include?(item 1) 1.580000 0.000000 1.580000 ( 1.585301) # ================================================================================ # set.include?(item 2) 1.980000 0.010000 1.990000 ( 1.984699) # array.include?(item 2) 2.170000 0.000000 2.170000 ( 2.167163) # ================================================================================ # set.include?(item 3) 2.110000 0.010000 2.120000 ( 2.125914) # array.include?(item 3) 2.450000 0.000000 2.450000 ( 2.445224) # ================================================================================ # set.include?(item 4) 2.090000 0.010000 2.100000 ( 2.094182) # array.include?(item 4) 2.920000 0.000000 2.920000 ( 2.924850) # ================================================================================ # set.include?(item 5) 2.000000 0.000000 2.000000 ( 2.000656) # array.include?(item 5) 3.540000 0.010000 3.550000 ( 3.547563) # ================================================================================ # set.include?(item 6) 2.030000 0.000000 2.030000 ( 2.032430) # array.include?(item 6) 3.800000 0.010000 3.810000 ( 3.810014) # ================================================================================ # Negative examples: # user system total real # set 1.940000 0.000000 1.940000 ( 1.941780) # array 4.240000 0.010000 4.250000 ( 4.238137) rspec-expectations-3.13.0/cucumber.yml000066400000000000000000000007161455770000100177510ustar00rootroot00000000000000<% USE_TILDE_TAGS = !defined?(::RUBY_ENGINE_VERSION) || (::RUBY_ENGINE_VERSION < '2.0.0') NOT_WIP_TAG = USE_TILDE_TAGS ? '~@wip' : '"not @wip"' NOT_RUBY_1_9_TAG = USE_TILDE_TAGS ? '~@ruby-1.9' : '"not @ruby-1.9"' def tags(tag = NOT_WIP_TAG) tags = [tag] tags << NOT_RUBY_1_9_TAG if RUBY_VERSION.to_f < 1.9 tags.join(" --tags ") end %> default: --require features --tags <%= tags %> --format progress wip: --require features --tags @wip:3 --wip features rspec-expectations-3.13.0/demo.rb000066400000000000000000000003161455770000100166660ustar00rootroot00000000000000require './lib/rspec/expectations' class IsolatedTest include RSpec::Matchers def test expect(nil).to(eq("")) end end RSpec::Expectations::Syntax.enable_expect(IsolatedTest) IsolatedTest.new.test rspec-expectations-3.13.0/features/000077500000000000000000000000001455770000100172335ustar00rootroot00000000000000rspec-expectations-3.13.0/features/.nav000066400000000000000000000017701455770000100200250ustar00rootroot00000000000000- built_in_matchers: - equality.feature - comparisons.feature - predicates.feature - types.feature - all.feature - be.feature - be_within.feature - exist.feature - change.feature - contain_exactly.feature - cover.feature - end_with.feature - exist.feature - have.feature - have_attributes.feature - include.feature - match.feature - operators.feature - raise_error.feature - respond_to.feature - satisfy.feature - start_with.feature - throw_symbol.feature - yield.feature - custom_matchers: - define_matcher.feature - define_diffable_matcher.feature - define_matcher_with_fluent_interface.feature - access_running_example.feature - define_matcher_outside_rspec.feature - aggregating_failures.feature - composing_matchers.feature - compound_expectations.feature - define_negated_matcher.feature - customized_message.feature - diffing.feature - implicit_docstrings.feature - syntax_configuration.feature - test_frameworks: - test_unit.feature - Changelog.md rspec-expectations-3.13.0/features/README.md000066400000000000000000000030141455770000100205100ustar00rootroot00000000000000# RSpec Expectations rspec-expectations is used to define expected outcomes. ```ruby RSpec.describe Account do it "has a balance of zero when first created" do expect(Account.new.balance).to eq(Money.new(0)) end end ``` ## Basic structure The basic structure of an rspec expectation is: ```ruby expect(actual).to matcher(expected) expect(actual).not_to matcher(expected) ``` Note: You can also use `expect(..).to_not` instead of `expect(..).not_to`. One is an alias to the other, so you can use whichever reads better to you. #### Examples ```ruby expect(5).to eq(5) expect(5).not_to eq(4) ``` ## What is a matcher? A matcher is any object that responds to the following methods: ```ruby matches?(actual) failure_message ``` These methods are also part of the matcher protocol, but are optional: ```ruby does_not_match?(actual) failure_message_when_negated description supports_block_expectations? ``` RSpec ships with a number of built-in matchers and a DSL for writing custom matchers. ## Issues The documentation for rspec-expectations is a work in progress. We'll be adding Cucumber features over time, and clarifying existing ones. If you have specific features you'd like to see added, find the existing documentation incomplete or confusing, or, better yet, wish to write a missing Cucumber feature yourself, please [submit an issue](http://github.com/rspec/rspec-expectations/issues) or a [pull request](http://github.com/rspec/rspec-expectations). rspec-expectations-3.13.0/features/aggregating_failures.feature000066400000000000000000000050321455770000100247610ustar00rootroot00000000000000Feature: Aggregating Failures Normally, an expectation failure causes the example to immediately abort. When you have multiple independent expectations, it's nice to be able to see all of the failures rather than just the first. One solution is to split off a separate example for each expectation, but if the setup for the examples is slow, that's going to take extra time and slow things down. `aggregate_failures` provides an alternate solution. It wraps a set of expectations with a block. Within the block, expectation failures will not immediatly abort like normal; instead, the failures will be aggregated into a single exception that is raised at the end of the block, allowing you to see all expectations that failed. `aggregate_failures` takes an optional string argument that will be used in the aggregated failure message as a label. RSpec::Core expands this feature a bit; see [the rspec-core docs](../rspec-core/expectation-framework-integration/aggregating-failures) for more detail. Note: The implementation of `aggregate_failures` uses a thread-local variable, which means that if you have an expectation failure in another thread, it'll abort like normal. Scenario: Multiple expectation failures within `aggregate_failures` are all reported Given a file named "spec/aggregated_failure_spec.rb" with: """ruby require 'rspec/expectations' include RSpec::Matchers Response = Struct.new(:status, :headers, :body) response = Response.new(404, { "Content-Type" => "text/plain" }, "Not Found") begin aggregate_failures "testing response" do expect(response.status).to eq(200) expect(response.headers["Content-Type"]).to eq("application/json") expect(response.body).to eq('{"message":"Success"}') end rescue RSpec::Expectations::MultipleExpectationsNotMetError => e puts e.message.gsub(/(:in).+/, '') exit(1) end """ When I run `ruby spec/aggregated_failure_spec.rb` Then it should fail with: """ Got 3 failures from failure aggregation block "testing response": 1) expected: 200 got: 404 (compared using ==) spec/aggregated_failure_spec.rb:9 2) expected: "application/json" got: "text/plain" (compared using ==) spec/aggregated_failure_spec.rb:10 3) expected: "{"message":"Success"}" got: "Not Found" (compared using ==) spec/aggregated_failure_spec.rb:11 """ rspec-expectations-3.13.0/features/built_in_matchers/000077500000000000000000000000001455770000100227265ustar00rootroot00000000000000rspec-expectations-3.13.0/features/built_in_matchers/README.md000066400000000000000000000120631455770000100242070ustar00rootroot00000000000000# Built in matchers `rspec-expectations` ships with a number of built-in matchers. Each matcher can be used with `expect(..).to` or `expect(..).not_to` to define positive and negative expectations respectively on an object. Most matchers can also be accessed using the `(...).should` and `(...).should_not` syntax; see [using should syntax](https://github.com/rspec/rspec-expectations/blob/main/Should.md) for why we recommend using `expect`. e.g. ```ruby expect(result).to eq(3) expect(list).not_to be_empty pi.should be > 3 ``` ## Object identity ```ruby expect(actual).to be(expected) # passes if actual.equal?(expected) ``` ## Object equivalence ```ruby expect(actual).to eq(expected) # passes if actual == expected ``` ## Optional APIs for identity/equivalence ```ruby expect(actual).to eql(expected) # passes if actual.eql?(expected) expect(actual).to equal(expected) # passes if actual.equal?(expected) # NOTE: `expect` does not support `==` matcher. ``` ## Comparisons ```ruby expect(actual).to be > expected expect(actual).to be >= expected expect(actual).to be <= expected expect(actual).to be < expected expect(actual).to be_between(minimum, maximum).inclusive expect(actual).to be_between(minimum, maximum).exclusive expect(actual).to match(/expression/) expect(actual).to be_within(delta).of(expected) expect(actual).to start_with expected expect(actual).to end_with expected # NOTE: `expect` does not support `=~` matcher. ``` ## Types/classes/response ```ruby expect(actual).to be_instance_of(expected) expect(actual).to be_kind_of(expected) expect(actual).to respond_to(expected) ``` ## Truthiness and existentialism ```ruby expect(actual).to be_truthy # passes if actual is truthy (not nil or false) expect(actual).to be true # passes if actual == true expect(actual).to be_falsey # passes if actual is falsy (nil or false) expect(actual).to be false # passes if actual == false expect(actual).to be_nil # passes if actual is nil expect(actual).to exist # passes if actual.exist? and/or actual.exists? are truthy expect(actual).to exist(*args) # passes if actual.exist?(*args) and/or actual.exists?(*args) are truthy ``` ## Expecting errors ```ruby expect { ... }.to raise_error expect { ... }.to raise_error(ErrorClass) expect { ... }.to raise_error("message") expect { ... }.to raise_error(ErrorClass, "message") ``` ## Expecting throws ```ruby expect { ... }.to throw_symbol expect { ... }.to throw_symbol(:symbol) expect { ... }.to throw_symbol(:symbol, 'value') ``` ## Predicate matchers ```ruby expect(actual).to be_xxx # passes if actual.xxx? expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg) ``` ### Examples ```ruby expect([]).to be_empty expect(:a => 1).to have_key(:a) ``` ## Collection membership ```ruby expect(actual).to include(expected) expect(array).to match_array(expected_array) # ...which is the same as: expect(array).to contain_exactly(individual, elements) ``` ### Examples ```ruby expect([1, 2, 3]).to include(1) expect([1, 2, 3]).to include(1, 2) expect(:a => 'b').to include(:a => 'b') expect("this string").to include("is str") expect([1, 2, 3]).to contain_exactly(2, 1, 3) expect([1, 2, 3]).to match_array([3, 2, 1]) ``` ## Ranges (1.9+ only) ```ruby expect(1..10).to cover(3) ``` ## Change observation ```ruby expect { object.action }.to change(object, :value).from(old).to(new) expect { object.action }.to change(object, :value).by(delta) expect { object.action }.to change(object, :value).by_at_least(minimum_delta) expect { object.action }.to change(object, :value).by_at_most(maximum_delta) ``` ### Examples ```ruby expect { a += 1 }.to change { a }.by(1) expect { a += 3 }.to change { a }.from(2) expect { a += 3 }.to change { a }.by_at_least(2) ``` ## Satisfy ```ruby expect(actual).to satisfy { |value| value == expected } ``` ## Output capture ```ruby expect { actual }.to output("some output").to_stdout expect { actual }.to output("some error").to_stderr ``` ## Block expectation ```ruby expect { |b| object.action(&b) }.to yield_control expect { |b| object.action(&b) }.to yield_with_no_args # only matches no args expect { |b| object.action(&b) }.to yield_with_args # matches any args expect { |b| object.action(&b) }.to yield_successive_args(*args) # matches args against multiple yields ``` ### Examples ```ruby expect { |b| User.transaction(&b) }.to yield_control expect { |b| User.transaction(&b) }.to yield_with_no_args expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5` expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5 expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5 expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) ``` rspec-expectations-3.13.0/features/built_in_matchers/all.feature000066400000000000000000000050141455770000100250530ustar00rootroot00000000000000Feature: `all` matcher Use the `all` matcher to specify that a collection's objects all pass an expected matcher. This works on any enumerable object. ```ruby expect([1, 3, 5]).to all( be_odd ) expect([1, 3, 5]).to all( be_an(Integer) ) expect([1, 3, 5]).to all( be < 10 ) expect([1, 3, 4]).to all( be_odd ) # fails ``` The matcher also supports compound matchers: ```ruby expect([1, 3, 5]).to all( be_odd.and be < 10 ) expect([1, 4, 21]).to all( be_odd.or be < 10 ) ``` If you are looking for "any" member of a collection that passes an expectation, look at the `include`-matcher. Scenario: Array usage Given a file named "array_all_matcher_spec.rb" with: """ruby RSpec.describe [1, 3, 5] do it { is_expected.to all( be_odd ) } it { is_expected.to all( be_an(Integer) ) } it { is_expected.to all( be < 10 ) } # deliberate failures it { is_expected.to all( be_even ) } it { is_expected.to all( be_a(String) ) } it { is_expected.to all( be > 2 ) } end """ When I run `rspec array_all_matcher_spec.rb` Then the output should contain all of these: | 6 examples, 3 failures | | expected [1, 3, 5] to all be even | | expected [1, 3, 5] to all be a kind of String | | expected [1, 3, 5] to all be > 2 | Scenario: Compound matcher usage Given a file named "compound_all_matcher_spec.rb" with: """ruby RSpec.describe ['anything', 'everything', 'something'] do it { is_expected.to all( be_a(String).and include("thing") ) } it { is_expected.to all( be_a(String).and end_with("g") ) } it { is_expected.to all( start_with("s").or include("y") ) } # deliberate failures it { is_expected.to all( include("foo").and include("bar") ) } it { is_expected.to all( be_a(String).and start_with("a") ) } it { is_expected.to all( start_with("a").or include("z") ) } end """ When I run `rspec compound_all_matcher_spec.rb` Then the output should contain all of these: | 6 examples, 3 failures | | expected ["anything", "everything", "something"] to all include "foo" and include "bar" | | expected ["anything", "everything", "something"] to all be a kind of String and start with "a" | | expected ["anything", "everything", "something"] to all start with "a" or include "z" | rspec-expectations-3.13.0/features/built_in_matchers/be.feature000066400000000000000000000122771455770000100247020ustar00rootroot00000000000000Feature: `be` matchers There are several related "be" matchers: ```ruby expect(obj).to be_truthy # passes if obj is truthy (not nil or false) expect(obj).to be_falsey # passes if obj is falsy (nil or false) expect(obj).to be_nil # passes if obj is nil expect(obj).to be # passes if obj is truthy (not nil or false) ``` Scenario: The `be_truthy` matcher Given a file named "be_truthy_spec.rb" with: """ruby RSpec.describe "be_truthy matcher" do specify { expect(true).to be_truthy } specify { expect(7).to be_truthy } specify { expect("foo").to be_truthy } specify { expect(nil).not_to be_truthy } specify { expect(false).not_to be_truthy } # deliberate failures specify { expect(true).not_to be_truthy } specify { expect(7).not_to be_truthy } specify { expect("foo").not_to be_truthy } specify { expect(nil).to be_truthy } specify { expect(false).to be_truthy } end """ When I run `rspec be_truthy_spec.rb` Then the output should contain "10 examples, 5 failures" And the output should contain: """ expected: falsey value got: true """ And the output should contain: """ expected: falsey value got: 7 """ And the output should contain: """ expected: falsey value got: "foo" """ And the output should contain: """ expected: truthy value got: nil """ And the output should contain: """ expected: truthy value got: false """ Scenario: The `be_falsey` matcher Given a file named "be_falsey_spec.rb" with: """ruby RSpec.describe "be_falsey matcher" do specify { expect(nil).to be_falsey } specify { expect(false).to be_falsey } specify { expect(true).not_to be_falsey } specify { expect(7).not_to be_falsey } specify { expect("foo").not_to be_falsey } # deliberate failures specify { expect(nil).not_to be_falsey } specify { expect(false).not_to be_falsey } specify { expect(true).to be_falsey } specify { expect(7).to be_falsey } specify { expect("foo").to be_falsey } end """ When I run `rspec be_falsey_spec.rb` Then the output should contain "10 examples, 5 failures" And the output should contain: """ expected: truthy value got: nil """ And the output should contain: """ expected: truthy value got: false """ And the output should contain: """ expected: falsey value got: true """ And the output should contain: """ expected: falsey value got: 7 """ And the output should contain: """ expected: falsey value got: "foo" """ Scenario: The `be_nil` matcher Given a file named "be_nil_spec.rb" with: """ruby RSpec.describe "be_nil matcher" do specify { expect(nil).to be_nil } specify { expect(false).not_to be_nil } specify { expect(true).not_to be_nil } specify { expect(7).not_to be_nil } specify { expect("foo").not_to be_nil } # deliberate failures specify { expect(nil).not_to be_nil } specify { expect(false).to be_nil } specify { expect(true).to be_nil } specify { expect(7).to be_nil } specify { expect("foo").to be_nil } end """ When I run `rspec be_nil_spec.rb` Then the output should contain "10 examples, 5 failures" And the output should contain: """ expected: not nil got: nil """ And the output should contain: """ expected: nil got: false """ And the output should contain: """ expected: nil got: true """ And the output should contain: """ expected: nil got: 7 """ And the output should contain: """ expected: nil got: "foo" """ Scenario: The `be` matcher Given a file named "be_spec.rb" with: """ruby RSpec.describe "be_matcher" do specify { expect(true).to be } specify { expect(7).to be } specify { expect("foo").to be } specify { expect(nil).not_to be } specify { expect(false).not_to be } # deliberate failures specify { expect(true).not_to be } specify { expect(7).not_to be } specify { expect("foo").not_to be } specify { expect(nil).to be } specify { expect(false).to be } end """ When I run `rspec be_spec.rb` Then the output should contain all of these: | 10 examples, 5 failures | | expected true to evaluate to false | | expected 7 to evaluate to false | | expected "foo" to evaluate to false | | expected nil to evaluate to true | | expected false to evaluate to true | rspec-expectations-3.13.0/features/built_in_matchers/be_within.feature000066400000000000000000000033031455770000100262520ustar00rootroot00000000000000Feature: `be_within` matcher Normal equality expectations do not work well for floating point values. Consider this irb session: > radius = 3 => 3 > area_of_circle = radius * radius * Math::PI => 28.2743338823081 > area_of_circle == 28.2743338823081 => false Instead, you should use the `be_within` matcher to check that the value is within a delta of your expected value: ```ruby expect(area_of_circle).to be_within(0.1).of(28.3) ``` Note that the difference between the actual and expected values must be smaller than your delta; if it is equal, the matcher will fail. Scenario: Basic usage Given a file named "be_within_matcher_spec.rb" with: """ruby RSpec.describe 27.5 do it { is_expected.to be_within(0.5).of(27.9) } it { is_expected.to be_within(0.5).of(28.0) } it { is_expected.to be_within(0.5).of(27.1) } it { is_expected.to be_within(0.5).of(27.0) } it { is_expected.not_to be_within(0.5).of(28.1) } it { is_expected.not_to be_within(0.5).of(26.9) } # deliberate failures it { is_expected.not_to be_within(0.5).of(28) } it { is_expected.not_to be_within(0.5).of(27) } it { is_expected.to be_within(0.5).of(28.1) } it { is_expected.to be_within(0.5).of(26.9) } end """ When I run `rspec be_within_matcher_spec.rb` Then the output should contain all of these: | 10 examples, 4 failures | | expected 27.5 not to be within 0.5 of 28 | | expected 27.5 not to be within 0.5 of 27 | | expected 27.5 to be within 0.5 of 28.1 | | expected 27.5 to be within 0.5 of 26.9 | rspec-expectations-3.13.0/features/built_in_matchers/change.feature000066400000000000000000000041431455770000100255320ustar00rootroot00000000000000Feature: `change` matcher The `change` matcher is used to specify that a block of code changes some mutable state. You can specify what will change using either of two forms: * `expect { do_something }.to change(object, :attribute)` * `expect { do_something }.to change { object.attribute }` You can further qualify the change by chaining `from` and/or `to` or one of `by`, `by_at_most`, `by_at_least`. Background: Given a file named "lib/counter.rb" with: """ruby class Counter class << self def increment @count ||= 0 @count += 1 end def count @count ||= 0 end end end """ @skip-when-ripper-unsupported Scenario: Expect change Given a file named "spec/example_spec.rb" with: """ruby require "counter" RSpec.describe Counter, "#increment" do it "should increment the count" do expect { Counter.increment }.to change { Counter.count }.from(0).to(1) end # deliberate failure it "should increment the count by 2" do expect { Counter.increment }.to change { Counter.count }.by(2) end end """ When I run `rspec spec/example_spec.rb` Then the output should contain "1 failure" Then the output should contain "expected `Counter.count` to have changed by 2, but was changed by 1" @skip-when-ripper-unsupported Scenario: Expect no change Given a file named "spec/example_spec.rb" with: """ruby require "counter" RSpec.describe Counter, "#increment" do it "should not increment the count by 1 (using not_to)" do expect { Counter.increment }.not_to change { Counter.count } end it "should not increment the count by 1 (using to_not)" do expect { Counter.increment }.to_not change { Counter.count } end end """ When I run `rspec spec/example_spec.rb` Then the output should contain "2 failures" Then the output should contain "expected `Counter.count` not to have changed, but did change from 1 to 2" rspec-expectations-3.13.0/features/built_in_matchers/comparisons.feature000066400000000000000000000070151455770000100266430ustar00rootroot00000000000000Feature: Comparison matchers RSpec provides a number of matchers that are based on Ruby's built-in operators. These can be used for generalized comparison of values. E.g. ```ruby expect(9).to be > 6 expect(3).to be <= 3 expect(1).to be < 6 expect('a').to be < 'b' ``` Scenario: Numeric operator matchers Given a file named "numeric_operator_matchers_spec.rb" with: """ruby RSpec.describe 18 do it { is_expected.to be < 20 } it { is_expected.to be > 15 } it { is_expected.to be <= 19 } it { is_expected.to be >= 17 } # deliberate failures it { is_expected.to be < 15 } it { is_expected.to be > 20 } it { is_expected.to be <= 17 } it { is_expected.to be >= 19 } it { is_expected.to be < 'a' } end RSpec.describe 'a' do it { is_expected.to be < 'b' } # deliberate failures it { is_expected.to be < 18 } end """ When I run `rspec numeric_operator_matchers_spec.rb` Then the output should contain "11 examples, 6 failures" And the output should contain: """ Failure/Error: it { is_expected.to be < 15 } expected: < 15 got: 18 """ And the output should contain: """ Failure/Error: it { is_expected.to be > 20 } expected: > 20 got: 18 """ And the output should contain: """ Failure/Error: it { is_expected.to be <= 17 } expected: <= 17 got: 18 """ And the output should contain: """ Failure/Error: it { is_expected.to be >= 19 } expected: >= 19 got: 18 """ And the output should contain: """ Failure/Error: it { is_expected.to be < 'a' } expected: < "a" got: 18 """ And the output should contain: """ Failure/Error: it { is_expected.to be < 18 } expected: < 18 got: "a" """ Scenario: String operator matchers Given a file named "string_operator_matchers_spec.rb" with: """ruby RSpec.describe "Strawberry" do it { is_expected.to be < "Tomato" } it { is_expected.to be > "Apple" } it { is_expected.to be <= "Turnip" } it { is_expected.to be >= "Banana" } # deliberate failures it { is_expected.to be < "Cranberry" } it { is_expected.to be > "Zuchini" } it { is_expected.to be <= "Potato" } it { is_expected.to be >= "Tomato" } end """ When I run `rspec string_operator_matchers_spec.rb` Then the output should contain "8 examples, 4 failures" And the output should contain: """ Failure/Error: it { is_expected.to be < "Cranberry" } expected: < "Cranberry" got: "Strawberry" """ And the output should contain: """ Failure/Error: it { is_expected.to be > "Zuchini" } expected: > "Zuchini" got: "Strawberry" """ And the output should contain: """ Failure/Error: it { is_expected.to be <= "Potato" } expected: <= "Potato" got: "Strawberry" """ And the output should contain: """ Failure/Error: it { is_expected.to be >= "Tomato" } expected: >= "Tomato" got: "Strawberry" """ rspec-expectations-3.13.0/features/built_in_matchers/contain_exactly.feature000066400000000000000000000046511455770000100274750ustar00rootroot00000000000000Feature: `contain_exactly` matcher The `contain_exactly` matcher provides a way to test arrays against each other in a way that disregards differences in the ordering between the actual and expected array. For example: ```ruby expect([1, 2, 3]).to contain_exactly(2, 3, 1) # pass expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail ``` This matcher is also available as `match_array`, which expects the expected array to be given as a single array argument rather than as individual splatted elements. The above could also be written as: ```ruby expect([1, 2, 3]).to match_array [2, 3, 1] # pass expect([:a, :c, :b]).to match_array [:a, :c] # fail ``` Scenario: Array is expected to contain every value Given a file named "contain_exactly_matcher_spec.rb" with: """ruby RSpec.describe [1, 2, 3] do it { is_expected.to contain_exactly(1, 2, 3) } it { is_expected.to contain_exactly(1, 3, 2) } it { is_expected.to contain_exactly(2, 1, 3) } it { is_expected.to contain_exactly(2, 3, 1) } it { is_expected.to contain_exactly(3, 1, 2) } it { is_expected.to contain_exactly(3, 2, 1) } # deliberate failures it { is_expected.to contain_exactly(1, 2, 1) } end """ When I run `rspec contain_exactly_matcher_spec.rb` Then the output should contain "7 examples, 1 failure" And the output should contain: """ Failure/Error: it { is_expected.to contain_exactly(1, 2, 1) } expected collection contained: [1, 1, 2] actual collection contained: [1, 2, 3] the missing elements were: [1] the extra elements were: [3] """ Scenario: Array is not expected to contain every value Given a file named "contain_exactly_matcher_spec.rb" with: """ruby RSpec.describe [1, 2, 3] do it { is_expected.to_not contain_exactly(1, 2, 3, 4) } it { is_expected.to_not contain_exactly(1, 2) } # deliberate failures it { is_expected.to_not contain_exactly(1, 3, 2) } end """ When I run `rspec contain_exactly_matcher_spec.rb` Then the output should contain "3 examples, 1 failure" And the output should contain: """ Failure/Error: it { is_expected.to_not contain_exactly(1, 3, 2) } expected [1, 2, 3] not to contain exactly 1, 3, and 2 """ rspec-expectations-3.13.0/features/built_in_matchers/cover.feature000066400000000000000000000032021455770000100254160ustar00rootroot00000000000000@ruby-1.9 Feature: `cover` matcher Use the `cover` matcher to specify that a range covers one or more expected objects. This works on any object that responds to `#cover?` (such as a `Range`): ```ruby expect(1..10).to cover(5) expect(1..10).to cover(4, 6) expect(1..10).not_to cover(11) ``` Scenario: Range usage Given a file named "range_cover_matcher_spec.rb" with: """ruby RSpec.describe (1..10) do it { is_expected.to cover(4) } it { is_expected.to cover(6) } it { is_expected.to cover(8) } it { is_expected.to cover(4, 6) } it { is_expected.to cover(4, 6, 8) } it { is_expected.not_to cover(11) } it { is_expected.not_to cover(11, 12) } # deliberate failures it { is_expected.to cover(11) } it { is_expected.not_to cover(4) } it { is_expected.not_to cover(6) } it { is_expected.not_to cover(8) } it { is_expected.not_to cover(4, 6, 8) } # both of these should fail since it covers 5 but not 11 it { is_expected.to cover(5, 11) } it { is_expected.not_to cover(5, 11) } end """ When I run `rspec range_cover_matcher_spec.rb` Then the output should contain all of these: | 14 examples, 7 failures | | expected 1..10 to cover 11 | | expected 1..10 not to cover 4 | | expected 1..10 not to cover 6 | | expected 1..10 not to cover 8 | | expected 1..10 not to cover 4, 6, and 8 | | expected 1..10 to cover 5 and 11 | | expected 1..10 not to cover 5 and 11 | rspec-expectations-3.13.0/features/built_in_matchers/end_with.feature000066400000000000000000000031441455770000100261060ustar00rootroot00000000000000Feature: `end_with` matcher Use the `end_with` matcher to specify that a string or array ends with the expected characters or elements. ```ruby expect("this string").to end_with "string" expect("this string").not_to end_with "stringy" expect([0, 1, 2]).to end_with 1, 2 ``` Scenario: String usage Given a file named "example_spec.rb" with: """ruby RSpec.describe "this string" do it { is_expected.to end_with "string" } it { is_expected.not_to end_with "stringy" } # deliberate failures it { is_expected.not_to end_with "string" } it { is_expected.to end_with "stringy" } end """ When I run `rspec example_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected "this string" not to end with "string" | | expected "this string" to end with "stringy" | Scenario: Array usage Given a file named "example_spec.rb" with: """ruby RSpec.describe [0, 1, 2, 3, 4] do it { is_expected.to end_with 4 } it { is_expected.to end_with 3, 4 } it { is_expected.not_to end_with 3 } it { is_expected.not_to end_with 0, 1, 2, 3, 4, 5 } # deliberate failures it { is_expected.not_to end_with 4 } it { is_expected.to end_with 3 } end """ When I run `rspec example_spec.rb` Then the output should contain all of these: | 6 examples, 2 failures | | expected [0, 1, 2, 3, 4] not to end with 4 | | expected [0, 1, 2, 3, 4] to end with 3 | rspec-expectations-3.13.0/features/built_in_matchers/equality.feature000066400000000000000000000101301455770000100261330ustar00rootroot00000000000000Feature: Equality matchers Ruby exposes several different methods for handling equality: a.equal?(b) # object identity - a and b refer to the same object a.eql?(b) # object equivalence - a and b have the same value a == b # object equivalence - a and b have the same value with type conversions Note that these descriptions are guidelines but are not forced by the language. Any object can implement any of these methods with its own semantics. rspec-expectations ships with matchers that align with each of these methods: ```ruby expect(a).to equal(b) # passes if a.equal?(b) expect(a).to eql(b) # passes if a.eql?(b) expect(a).to be == b # passes if a == b ``` It also ships with two matchers that have more of a DSL feel to them: ```ruby expect(a).to be(b) # passes if a.equal?(b) expect(a).to eq(b) # passes if a == b ``` Scenario: Compare using eq (==) Given a file named "compare_using_eq.rb" with: """ruby RSpec.describe "a string" do it "is equal to another string of the same value" do expect("this string").to eq("this string") end it "is not equal to another string of a different value" do expect("this string").not_to eq("a different string") end end RSpec.describe "an integer" do it "is equal to a float of the same value" do expect(5).to eq(5.0) end end """ When I run `rspec compare_using_eq.rb` Then the output should contain "3 examples, 0 failures" Scenario: Compare using == Given a file named "compare_using_==.rb" with: """ruby RSpec.describe "a string" do it "is equal to another string of the same value" do expect("this string").to be == "this string" end it "is not equal to another string of a different value" do expect("this string").not_to be == "a different string" end end RSpec.describe "an integer" do it "is equal to a float of the same value" do expect(5).to be == 5.0 end end """ When I run `rspec compare_using_==.rb` Then the output should contain "3 examples, 0 failures" Scenario: Compare using eql (eql?) Given a file named "compare_using_eql.rb" with: """ruby RSpec.describe "an integer" do it "is equal to another integer of the same value" do expect(5).to eql(5) end it "is not equal to another integer of a different value" do expect(5).not_to eql(6) end it "is not equal to a float of the same value" do expect(5).not_to eql(5.0) end end """ When I run `rspec compare_using_eql.rb` Then the output should contain "3 examples, 0 failures" Scenario: Compare using equal (equal?) Given a file named "compare_using_equal.rb" with: """ruby RSpec.describe "a string" do it "is equal to itself" do string = "this string" expect(string).to equal(string) end it "is not equal to another string of the same value" do expect("this string").not_to equal("this string") end it "is not equal to another string of a different value" do expect("this string").not_to equal("a different string") end end """ When I run `rspec compare_using_equal.rb` Then the output should contain "3 examples, 0 failures" Scenario: Compare using be (equal?) Given a file named "compare_using_be.rb" with: """ruby RSpec.describe "a string" do it "is equal to itself" do string = "this string" expect(string).to be(string) end it "is not equal to another string of the same value" do expect("this string").not_to be("this string") end it "is not equal to another string of a different value" do expect("this string").not_to be("a different string") end end """ When I run `rspec compare_using_be.rb` Then the output should contain "3 examples, 0 failures" rspec-expectations-3.13.0/features/built_in_matchers/exist.feature000066400000000000000000000024101455770000100254340ustar00rootroot00000000000000Feature: `exist` matcher The `exist` matcher is used to specify that something exists (as indicated by `#exist?` or `#exists?`): ```ruby expect(obj).to exist # passes if obj.exist? or obj.exists? ``` Scenario: Basic usage Given a file named "exist_matcher_spec.rb" with: """ruby class Planet attr_reader :name def initialize(name) @name = name end def inspect "" end def exist? # also works with exists? %w[Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune].include?(name) end end RSpec.describe "Earth" do let(:earth) { Planet.new("Earth") } specify { expect(earth).to exist } specify { expect(earth).not_to exist } # deliberate failure end RSpec.describe "Tatooine" do let(:tatooine) { Planet.new("Tatooine") } specify { expect(tatooine).to exist } # deliberate failure specify { expect(tatooine).not_to exist } end """ When I run `rspec exist_matcher_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected not to exist | | expected to exist | rspec-expectations-3.13.0/features/built_in_matchers/have_attributes.feature000066400000000000000000000037141455770000100275010ustar00rootroot00000000000000Feature: `have_attributes` matcher Use the have_attributes matcher to specify that an object's attributes match the expected attributes: ```ruby Person = Struct.new(:name, :age) person = Person.new("Jim", 32) expect(person).to have_attributes(:name => "Jim", :age => 32) expect(person).to have_attributes(:name => a_string_starting_with("J"), :age => (a_value > 30) ) ``` The matcher will fail if actual doesn't respond to any of the expected attributes: ```ruby expect(person).to have_attributes(:name => "Jim", :color => 'red') ``` Scenario: Basic usage Given a file named "basic_have_attributes_matcher_spec.rb" with: """ruby Person = Struct.new(:name, :age) RSpec.describe Person.new("Jim", 32) do it { is_expected.to have_attributes(:name => "Jim") } it { is_expected.to have_attributes(:name => a_string_starting_with("J") ) } it { is_expected.to have_attributes(:age => 32) } it { is_expected.to have_attributes(:age => (a_value > 30) ) } it { is_expected.to have_attributes(:name => "Jim", :age => 32) } it { is_expected.to have_attributes(:name => a_string_starting_with("J"), :age => (a_value > 30) ) } it { is_expected.not_to have_attributes(:name => "Bob") } it { is_expected.not_to have_attributes(:age => 10) } it { is_expected.not_to have_attributes(:age => (a_value < 30) ) } # deliberate failures it { is_expected.to have_attributes(:name => "Bob") } it { is_expected.to have_attributes(:age => 10) } # fails if any of the attributes don't match it { is_expected.to have_attributes(:name => "Bob", :age => 32) } it { is_expected.to have_attributes(:name => "Jim", :age => 10) } it { is_expected.to have_attributes(:name => "Bob", :age => 10) } end """ When I run `rspec basic_have_attributes_matcher_spec.rb` Then the output should contain "14 examples, 5 failures" rspec-expectations-3.13.0/features/built_in_matchers/include.feature000066400000000000000000000220111455770000100257220ustar00rootroot00000000000000Feature: `include` matcher Use the `include` matcher to specify that a collection includes one or more expected objects. It succeeds if any object of the given collection passes the specified matcher. This works on any object that responds to `#include?` (such as a string or array): ```ruby expect("a string").to include("a") expect("a string").to include(/a|str/).twice expect("a string").to include("str", "g") expect("a string").not_to include("foo") expect([1, 2]).to include(1) expect([1, 2]).to include(1, 2) expect([1, 2]).to include(a_kind_of(Integer)) expect([1, 2]).to include(be_odd.and be < 10 ) expect([1, 2]).to include(be_odd) expect([1, 2]).to include(be < 10).at_least(2).times expect([1, 2]).not_to include(17) ``` The matcher also provides flexible handling for hashes: ```ruby expect(:a => 1, :b => 2).to include(:a) expect(:a => 1, :b => 2).to include(:a, :b) expect(:a => 1, :b => 2).to include(:a => 1) expect(:a => 1, :b => 2).to include(:b => 2, :a => 1) expect(:a => 1, :b => 2).to include(match(/b/) => 2) expect(:a => 1, :b => 2).to include(match(/b/) => be_even) expect(:a => 1, :b => 2).not_to include(:c) expect(:a => 1, :b => 2).not_to include(:a => 2) expect(:a => 1, :b => 2).not_to include(:c => 3) ``` Scenario: Array usage Given a file named "array_include_matcher_spec.rb" with: """ruby RSpec.describe [1, 3, 7] do it { is_expected.to include(1) } it { is_expected.to include(3) } it { is_expected.to include(7) } it { is_expected.to include(1, 7) } it { is_expected.to include(1, 3, 7) } it { is_expected.to include(a_kind_of(Integer)) } it { is_expected.to include(be_odd.and be < 10) } it { is_expected.to include(be_odd).at_least(:twice) } it { is_expected.not_to include(be_even) } it { is_expected.not_to include(17) } it { is_expected.not_to include(43, 100) } # deliberate failures it { is_expected.to include(4) } it { is_expected.to include(be_even) } it { is_expected.to include(be_odd).at_most(2).times } it { is_expected.not_to include(1) } it { is_expected.not_to include(3) } it { is_expected.not_to include(7) } it { is_expected.not_to include(1, 3, 7) } # both of these should fail since it includes 1 but not 9 it { is_expected.to include(1, 9) } it { is_expected.not_to include(1, 9) } end """ When I run `rspec array_include_matcher_spec.rb` Then the output should contain all of these: | 20 examples, 9 failures | | expected [1, 3, 7] to include 4 | | expected [1, 3, 7] to include (be even) | | expected [1, 3, 7] to include (be odd) at most twice but it is included 3 times | | expected [1, 3, 7] not to include 1 | | expected [1, 3, 7] not to include 3 | | expected [1, 3, 7] not to include 7 | | expected [1, 3, 7] not to include 1, 3, and 7 | | expected [1, 3, 7] to include 9 | | expected [1, 3, 7] not to include 1 | Scenario: String usage Given a file named "string_include_matcher_spec.rb" with: """ruby RSpec.describe "a string" do it { is_expected.to include("str") } it { is_expected.to include("a", "str", "ng") } it { is_expected.to include(/a|str/).twice } it { is_expected.not_to include("foo") } it { is_expected.not_to include("foo", "bar") } # deliberate failures it { is_expected.to include("foo") } it { is_expected.not_to include("str") } it { is_expected.to include("str").at_least(:twice) } it { is_expected.to include("str", "foo") } it { is_expected.not_to include("str", "foo") } end """ When I run `rspec string_include_matcher_spec.rb` Then the output should contain all of these: | 10 examples, 5 failures | | expected "a string" to include "foo" | | expected "a string" not to include "str" | | expected "a string" to include "str" at least twice but it is included once | | expected "a string" to include "foo" | | expected "a string" not to include "str" | Scenario: Hash usage Given a file named "hash_include_matcher_spec.rb" with: """ruby RSpec.describe :a => 7, :b => 5 do it { is_expected.to include(:a) } it { is_expected.to include(:b, :a) } it { is_expected.to include(:a => 7) } it { is_expected.to include(:b => 5, :a => 7) } it { is_expected.not_to include(:c) } it { is_expected.not_to include(:c, :d) } it { is_expected.not_to include(:d => 2) } it { is_expected.not_to include(:a => 5) } it { is_expected.not_to include(:b => 7, :a => 5) } # deliberate failures it { is_expected.not_to include(:a) } it { is_expected.not_to include(:b, :a) } it { is_expected.not_to include(:a => 7) } it { is_expected.not_to include(:a => 7, :b => 5) } it { is_expected.to include(:c) } it { is_expected.to include(:c, :d) } it { is_expected.to include(:d => 2) } it { is_expected.to include(:a => 5) } it { is_expected.to include(:a => 5, :b => 7) } # Mixed cases--the hash includes one but not the other. # All 4 of these cases should fail. it { is_expected.to include(:a, :d) } it { is_expected.not_to include(:a, :d) } it { is_expected.to include(:a => 7, :d => 3) } it { is_expected.not_to include(:a => 7, :d => 3) } end """ When I run `rspec hash_include_matcher_spec.rb` Then the output should contain all of these: | 22 examples, 13 failures | | expected {:a => 7, :b => 5} not to include :a | | expected {:a => 7, :b => 5} not to include :b and :a | | expected {:a => 7, :b => 5} not to include {:a => 7} | | expected {:a => 7, :b => 5} not to include {:a => 7, :b => 5} | | expected {:a => 7, :b => 5} to include :c | | expected {:a => 7, :b => 5} to include :c and :d | | expected {:a => 7, :b => 5} to include {:d => 2} | | expected {:a => 7, :b => 5} to include {:a => 5} | | expected {:a => 7, :b => 5} to include {:a => 5, :b => 7} | | expected {:a => 7, :b => 5} to include :d | | expected {:a => 7, :b => 5} not to include :a | | expected {:a => 7, :b => 5} to include {:d => 3} | | expected {:a => 7, :b => 5} not to include {:a => 7} | Scenario: Counts usage Given a file named "include_matcher_with_counts_spec.rb" with: """ruby RSpec.describe [{:c => 7}, {:a => 1}, {:b => 2}, {:c => 1}, {:a => 3}, {:c => 7}] do it { is_expected.to include(:b => 2).exactly(1).times } it { is_expected.to include(:b => 2).once } it { is_expected.to include(have_key(:a)).twice } it { is_expected.to include(have_key(:c)).at_least(2).times } it { is_expected.to include(have_key(:a)).at_least(:once) } it { is_expected.to include(have_key(:c)).at_least(:twice) } it { is_expected.to include(have_key(:d)).at_most(:once) } it { is_expected.to include(have_key(:b)).at_most(:twice) } # deliberate failures it { is_expected.not_to include(have_key(:b)).once } it { is_expected.not_to include(have_key(:a)).twice } it { is_expected.not_to include(have_key(:c)).at_least(2).times } it { is_expected.not_to include(have_key(:d)).at_most(:once) } end """ When I run `rspec include_matcher_with_counts_spec.rb` Then the output should contain all of these: | 12 examples, 4 failures | | expected [{:c => 7}, {:a => 1}, {:b => 2}, {:c => 1}, {:a => 3}, {:c => 7}] not to include (have key :b) once | | expected [{:c => 7}, {:a => 1}, {:b => 2}, {:c => 1}, {:a => 3}, {:c => 7}] not to include (have key :a) twice | | expected [{:c => 7}, {:a => 1}, {:b => 2}, {:c => 1}, {:a => 3}, {:c => 7}] not to include (have key :c) at least twice | | expected [{:c => 7}, {:a => 1}, {:b => 2}, {:c => 1}, {:a => 3}, {:c => 7}] not to include (have key :d) at most once | rspec-expectations-3.13.0/features/built_in_matchers/match.feature000066400000000000000000000032411455770000100253770ustar00rootroot00000000000000Feature: `match` matcher The `match` matcher calls `#match` on the object, passing if `#match` returns a truthy (not `false` or `nil`) value. `Regexp` and `String` both provide a `#match` method. ```ruby expect("a string").to match(/str/) # passes expect("a string").to match(/foo/) # fails expect(/foo/).to match("food") # passes expect(/foo/).to match("drinks") # fails ``` You can also use this matcher to match nested data structures when composing matchers. Scenario: String usage Given a file named "string_match_spec.rb" with: """ruby RSpec.describe "a string" do it { is_expected.to match(/str/) } it { is_expected.not_to match(/foo/) } # deliberate failures it { is_expected.not_to match(/str/) } it { is_expected.to match(/foo/) } end """ When I run `rspec string_match_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected "a string" not to match /str/ | | expected "a string" to match /foo/ | Scenario: Regular expression usage Given a file named "regexp_match_spec.rb" with: """ruby RSpec.describe /foo/ do it { is_expected.to match("food") } it { is_expected.not_to match("drinks") } # deliberate failures it { is_expected.not_to match("food") } it { is_expected.to match("drinks") } end """ When I run `rspec regexp_match_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected /foo/ not to match "food" | | expected /foo/ to match "drinks" | rspec-expectations-3.13.0/features/built_in_matchers/output.feature000066400000000000000000000167651455770000100256620ustar00rootroot00000000000000Feature: `output` matcher The `output` matcher provides a way to assert that the block has emitted content to either `$stdout` or `$stderr`. With no arg, passes if the block outputs `to_stdout` or `to_stderr`. With a string, passes if the blocks outputs that specific string `to_stdout` or `to_stderr`. With a regexp or matcher, passes if the blocks outputs a string `to_stdout` or `to_stderr` that matches. Note: `to_stdout` and `to_stderr` work by temporarily replacing `$stdout` or `$stderr`, so they're not able to intercept stream output that explicitly uses `STDOUT`/`STDERR` or that uses a reference to `$stdout`/`$stderr` that was stored before the matcher is used. To capture output from any spawned subprocess as well, use `to_stdout_from_any_process` or `to_stderr_from_any_process`. Output from any process that inherits the main process's corresponding standard stream will be captured. Note: `to_stdout_from_any_process` and `to_stderr_from_any_process` use tempfiles to capture output, and are thus significantly (~30x) slower than `to_stdout` and `to_stderr`. Scenario: Using the `output_to_stdout` matcher Given a file named "output_to_stdout_spec.rb" with: """ruby RSpec.describe "output.to_stdout matcher" do specify { expect { print('foo') }.to output.to_stdout } specify { expect { print('foo') }.to output('foo').to_stdout } specify { expect { print('foo') }.to output(/foo/).to_stdout } specify { expect { }.to_not output.to_stdout } specify { expect { print('foo') }.to_not output('bar').to_stdout } specify { expect { print('foo') }.to_not output(/bar/).to_stdout } # deliberate failures specify { expect { }.to output.to_stdout } specify { expect { }.to output('foo').to_stdout } specify { expect { print('foo') }.to_not output.to_stdout } specify { expect { print('foo') }.to output('bar').to_stdout } specify { expect { print('foo') }.to output(/bar/).to_stdout } end """ When I run `rspec output_to_stdout_spec.rb` Then the output should contain all of these: | 11 examples, 5 failures | | expected block to output to stdout, but did not | | expected block to not output to stdout, but output "foo" | | expected block to output "bar" to stdout, but output "foo" | | expected block to output "foo" to stdout, but output nothing | | expected block to output /bar/ to stdout, but output "foo" | Scenario: Using the `output_to_stderr` matcher Given a file named "output_to_stderr.rb" with: """ruby RSpec.describe "output_to_stderr matcher" do specify { expect { warn('foo') }.to output.to_stderr } specify { expect { warn('foo') }.to output("foo\n").to_stderr } specify { expect { warn('foo') }.to output(/foo/).to_stderr } specify { expect { }.to_not output.to_stderr } specify { expect { warn('foo') }.to_not output('bar').to_stderr } specify { expect { warn('foo') }.to_not output(/bar/).to_stderr } # deliberate failures specify { expect { }.to output.to_stderr } specify { expect { }.to output('foo').to_stderr } specify { expect { warn('foo') }.to_not output.to_stderr } specify { expect { warn('foo') }.to output('bar').to_stderr } specify { expect { warn('foo') }.to output(/bar/).to_stderr } end """ When I run `rspec output_to_stderr.rb` Then the output should contain all of these: | 11 examples, 5 failures | | expected block to output to stderr, but did not | | expected block to not output to stderr, but output "foo | | expected block to output "bar" to stderr, but output "foo\n" | | expected block to output "foo" to stderr, but output nothing | | expected block to output /bar/ to stderr, but output "foo\n" | Scenario: Using the `output_to_stdout_from_any_process` matcher Given a file named "output_to_stdout_from_any_process_spec.rb" with: """ruby RSpec.describe "output.to_stdout_from_any_process matcher" do specify { expect { system('printf foo') }.to output.to_stdout_from_any_process } specify { expect { system('printf foo') }.to output("foo").to_stdout_from_any_process } specify { expect { system('printf foo') }.to output(/foo/).to_stdout_from_any_process } specify { expect { }.to_not output.to_stdout_from_any_process } specify { expect { system('printf foo') }.to_not output("bar").to_stdout_from_any_process } specify { expect { system('printf foo') }.to_not output(/bar/).to_stdout_from_any_process } # deliberate failures specify { expect { }.to output.to_stdout_from_any_process } specify { expect { }.to output('foo').to_stdout_from_any_process } specify { expect { system('printf foo') }.to_not output.to_stdout_from_any_process } specify { expect { system('printf foo') }.to output('bar').to_stdout_from_any_process } specify { expect { system('printf foo') }.to output(/bar/).to_stdout_from_any_process } end """ When I run `rspec output_to_stdout_from_any_process_spec.rb` Then the output should contain all of these: | 11 examples, 5 failures | | expected block to output to stdout, but did not | | expected block to not output to stdout, but output "foo" | | expected block to output "bar" to stdout, but output "foo" | | expected block to output "foo" to stdout, but output nothing | | expected block to output /bar/ to stdout, but output "foo" | Scenario: Using the `output_to_stderr_from_any_process` matcher Given a file named "output_to_stderr_from_any_process_spec.rb" with: """ruby RSpec.describe "output.to_stderr_from_any_process matcher" do specify { expect { system('printf foo 1>&2') }.to output.to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to output("foo").to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to output(/foo/).to_stderr_from_any_process } specify { expect { }.to_not output.to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to_not output("bar").to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to_not output(/bar/).to_stderr_from_any_process } # deliberate failures specify { expect { }.to output.to_stderr_from_any_process } specify { expect { }.to output('foo').to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to_not output.to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to output('bar').to_stderr_from_any_process } specify { expect { system('printf foo 1>&2') }.to output(/bar/).to_stderr_from_any_process } end """ When I run `rspec output_to_stderr_from_any_process_spec.rb` Then the output should contain all of these: | 11 examples, 5 failures | | expected block to output to stderr, but did not | | expected block to not output to stderr, but output "foo" | | expected block to output "bar" to stderr, but output "foo" | | expected block to output "foo" to stderr, but output nothing | | expected block to output /bar/ to stderr, but output "foo" | rspec-expectations-3.13.0/features/built_in_matchers/predicates.feature000066400000000000000000000162011455770000100264260ustar00rootroot00000000000000Feature: Predicate matchers Ruby objects commonly provide predicate methods: ```ruby 7.zero? # => false 0.zero? # => true [1].empty? # => false [].empty? # => true { :a => 5 }.has_key?(:b) # => false { :b => 5 }.has_key?(:b) # => true ``` You could use a basic equality matcher to set expectations on these: ```ruby expect(7.zero?).to eq true # fails with "expected true, got false (using ==)" ``` ...but RSpec provides dynamic predicate matchers that are more readable and provide better failure output. For any predicate method, RSpec gives you a corresponding matcher. Simply prefix the method with `be_` and remove the question mark. Examples: ```ruby expect(7).not_to be_zero # calls 7.zero? expect([]).to be_empty # calls [].empty? expect(x).to be_multiple_of(3) # calls x.multiple_of?(3) ``` Alternately, for a predicate method that begins with `has_` like `Hash#has_key?`, RSpec allows you to use an alternate form since `be_has_key` makes no sense. ```ruby expect(hash).to have_key(:foo) # calls hash.has_key?(:foo) expect(array).not_to have_odd_values # calls array.has_odd_values? ``` In either case, RSpec provides nice, clear error messages, such as: `expected zero? to be truthy, got false` Calling private methods will also fail: `expected private_method? to return true but it's a private method` Any arguments passed to the matcher will be passed on to the predicate method. Scenario: Expecting `subject` to `be_zero` (based on Integer#zero?) Given a file named "should_be_zero_spec.rb" with: """ruby RSpec.describe 0 do it { is_expected.to be_zero } end RSpec.describe 7 do it { is_expected.to be_zero } # deliberate failure end """ When I run `rspec should_be_zero_spec.rb` Then the output should contain "2 examples, 1 failure" And the output should contain "expected `7.zero?` to be truthy, got false" Scenario: Expecting `subject` to not `be_empty` (based on Array#empty?) Given a file named "should_not_be_empty_spec.rb" with: """ruby RSpec.describe [1, 2, 3] do it { is_expected.not_to be_empty } end RSpec.describe [] do it { is_expected.not_to be_empty } # deliberate failure end """ When I run `rspec should_not_be_empty_spec.rb` Then the output should contain "2 examples, 1 failure" And the output should contain "expected `[].empty?` to be falsey, got true" Scenario: Expecting `subject` to `have_key` (based on Hash#has_key?) Given a file named "should_have_key_spec.rb" with: """ruby RSpec.describe Hash do subject { { :foo => 7 } } it { is_expected.to have_key(:foo) } it { is_expected.to have_key(:bar) } # deliberate failure end """ When I run `rspec should_have_key_spec.rb` Then the output should contain "2 examples, 1 failure" And the output should contain "expected `{:foo=>7}.has_key?(:bar)` to be truthy, got false" Scenario: Expecting `subject` to have all decimals (based on custom `has_decimals?` method) Given a file named "should_not_have_all_string_keys_spec.rb" with: """ruby class Float def has_decimals? round != self end end RSpec.describe Float do context 'with decimals' do subject { 4.2 } it { is_expected.to have_decimals } end context 'with no decimals' do subject { 42.0 } it { is_expected.to have_decimals } # deliberate failure end end """ When I run `rspec should_not_have_all_string_keys_spec.rb` Then the output should contain "2 examples, 1 failure" And the output should contain "expected `42.0.has_decimals?` to be truthy, got false" Scenario: Matcher arguments are passed on to the predicate method Given a file named "predicate_matcher_argument_spec.rb" with: """ruby class Integer def multiple_of?(x) (self % x).zero? end end RSpec.describe 12 do it { is_expected.to be_multiple_of(3) } it { is_expected.not_to be_multiple_of(7) } # deliberate failures it { is_expected.not_to be_multiple_of(4) } it { is_expected.to be_multiple_of(5) } end """ When I run `rspec predicate_matcher_argument_spec.rb` Then the output should contain "4 examples, 2 failures" And the output should contain "expected `12.multiple_of?(4)` to be falsey, got true" And the output should contain "expected `12.multiple_of?(5)` to be truthy, got false" Scenario: The config `strict_predicate_matchers` impacts matching of results other than `true` and `false` Given a file named "strict_or_not.rb" with: """ruby class StrangeResult def has_strange_result? 42 end end RSpec.describe StrangeResult do subject { StrangeResult.new } before do RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.strict_predicate_matchers = strict end end end context 'with non-strict matchers (default)' do let(:strict) { false } it { is_expected.to have_strange_result } end context 'with strict matchers' do let(:strict) { true } # deliberate failure it { is_expected.to have_strange_result } end end """ When I run `rspec strict_or_not.rb` Then the output should contain "2 examples, 1 failure" And the output should contain "has_strange_result?` to return true, got 42" Scenario: Calling private method with be_predicate causes error Given a file named "attempting_to_match_private_method_spec.rb" with: """ruby class WithPrivateMethods def secret? true end private :secret? end RSpec.describe 'private methods' do subject { WithPrivateMethods.new } # deliberate failure it { is_expected.to be_secret } end """ When I run `rspec attempting_to_match_private_method_spec.rb` Then the output should contain "1 example, 1 failure" And the output should contain "`secret?` is a private method" Scenario: Calling private method with have_predicate causes error Given a file named "attempting_to_match_private_method_spec.rb" with: """ruby class WithPrivateMethods def has_secret? true end private :has_secret? end RSpec.describe 'private methods' do subject { WithPrivateMethods.new } # deliberate failure it { is_expected.to have_secret } end """ When I run `rspec attempting_to_match_private_method_spec.rb` Then the output should contain "1 example, 1 failure" And the output should contain "`has_secret?` is a private method" rspec-expectations-3.13.0/features/built_in_matchers/raise_error.feature000066400000000000000000000117041455770000100266220ustar00rootroot00000000000000Feature: `raise_error` matcher Use the `raise_error` matcher to specify that a block of code raises an error. The most basic form passes if any error is thrown: ```ruby expect { raise StandardError }.to raise_error ``` You can use `raise_exception` instead if you prefer that wording: ```ruby expect { 3 / 0 }.to raise_exception ``` `raise_error` and `raise_exception` are functionally interchangeable, so use the one that makes the most sense to you in any given context. In addition to the basic form, above, there are a number of ways to specify details of an error/exception: ```ruby expect { raise "oops" }.to raise_error expect { raise "oops" }.to raise_error(RuntimeError) expect { raise "oops" }.to raise_error("oops") expect { raise "oops" }.to raise_error(/op/) expect { raise "oops" }.to raise_error(RuntimeError, "oops") expect { raise "oops" }.to raise_error(RuntimeError, /op/) expect { raise "oops" }.to raise_error(an_instance_of(RuntimeError).and having_attributes(message: "oops")) ``` Scenario: Expecting any error Given a file named "example_spec" with: """ RSpec.describe "calling a missing method" do it "raises" do expect { Object.new.foo }.to raise_error end end """ When I run `rspec example_spec` Then the example should pass Scenario: Expecting a specific error Given a file named "example_spec" with: """ RSpec.describe "calling a missing method" do it "raises" do expect { Object.new.foo }.to raise_error(NameError) end end """ When I run `rspec example_spec` Then the example should pass Scenario: Matching a message with a string Given a file named "example_spec.rb" with: """ruby RSpec.describe "matching error message with string" do it "matches the error message" do expect { raise StandardError, 'this message exactly'}. to raise_error('this message exactly') end end """ When I run `rspec example_spec.rb` Then the example should pass Scenario: Matching a message with a regexp Given a file named "example_spec.rb" with: """ruby RSpec.describe "matching error message with regex" do it "matches the error message" do expect { raise StandardError, "my message" }. to raise_error(/my mess/) end end """ When I run `rspec example_spec.rb` Then the example should pass Scenario: Matching a message with `with_message` Given a file named "example_spec.rb" with: """ruby RSpec.describe "matching error message with regex" do it "matches the error message" do expect { raise StandardError, "my message" }. to raise_error.with_message(/my mess/) end end """ When I run `rspec example_spec.rb` Then the example should pass Scenario: Matching a class + message with string Given a file named "example_spec.rb" with: """ruby RSpec.describe "matching error message with string" do it "matches the error message" do expect { raise StandardError, 'this message exactly'}. to raise_error(StandardError, 'this message exactly') end end """ When I run `rspec example_spec.rb` Then the example should pass Scenario: Matching a class + message with regexp Given a file named "example_spec.rb" with: """ruby RSpec.describe "matching error message with regex" do it "matches the error message" do expect { raise StandardError, "my message" }. to raise_error(StandardError, /my mess/) end end """ When I run `rspec example_spec.rb` Then the example should pass Scenario: Setting expectations on error object passed to block Given a file named "example_spec" with: """ RSpec.describe "#foo" do it "raises NameError" do expect { Object.new.foo }.to raise_error { |error| expect(error).to be_a(NameError) } end end """ When I run `rspec example_spec` Then the example should pass Scenario: Setting expectations on an error object with chained matchers Given a file named "example_spec" with: """ RSpec.describe "composing matchers" do it "raises StandardError" do expect { raise StandardError, "my message" }. to raise_error(an_instance_of(StandardError).and having_attributes({"message" => "my message"})) end end """ When I run `rspec example_spec` Then the example should pass Scenario: Expecting no error at all Given a file named "example_spec" with: """ RSpec.describe "#to_s" do it "does not raise" do expect { Object.new.to_s }.not_to raise_error end end """ When I run `rspec example_spec` Then the example should pass rspec-expectations-3.13.0/features/built_in_matchers/respond_to.feature000066400000000000000000000274341455770000100264710ustar00rootroot00000000000000Feature: `respond_to` matcher Use the `respond_to` matcher to specify details of an object's interface. In its most basic form: ```ruby expect(obj).to respond_to(:foo) # pass if obj.respond_to?(:foo) ``` You can specify that an object responds to multiple messages in a single statement with multiple arguments passed to the matcher: ```ruby expect(obj).to respond_to(:foo, :bar) # passes if obj.respond_to?(:foo) && obj.respond_to?(:bar) ``` If the number of arguments accepted by the method is important to you, you can specify that as well: ```ruby expect(obj).to respond_to(:foo).with(1).argument expect(obj).to respond_to(:bar).with(2).arguments expect(obj).to respond_to(:baz).with(1..2).arguments expect(obj).to respond_to(:xyz).with_unlimited_arguments ``` If your Ruby version supports keyword arguments, you can specify a list of keywords accepted by the method. ```ruby expect(obj).to respond_to(:foo).with_keywords(:ichi, :ni) expect(obj).to respond_to(:bar).with(2).arguments.and_keywords(:san, :yon) expect(obj).to respond_to(:baz).with_arbitrary_keywords ``` Note that this matcher relies entirely upon `#respond_to?`. If an object dynamically responds to a message via `#method_missing`, but does not indicate this via `#respond_to?`, then this matcher will give you false results. Scenario: Basic usage Given a file named "respond_to_matcher_spec.rb" with: """ruby RSpec.describe "a string" do it { is_expected.to respond_to(:length) } it { is_expected.to respond_to(:hash, :class, :to_s) } it { is_expected.not_to respond_to(:to_model) } it { is_expected.not_to respond_to(:compact, :flatten) } # deliberate failures it { is_expected.to respond_to(:to_model) } it { is_expected.to respond_to(:compact, :flatten) } it { is_expected.not_to respond_to(:length) } it { is_expected.not_to respond_to(:hash, :class, :to_s) } # mixed examples--String responds to :length but not :flatten # both specs should fail it { is_expected.to respond_to(:length, :flatten) } it { is_expected.not_to respond_to(:length, :flatten) } end """ When I run `rspec respond_to_matcher_spec.rb` Then the output should contain all of these: | 10 examples, 6 failures | | expected "a string" to respond to :to_model | | expected "a string" to respond to :compact, :flatten | | expected "a string" not to respond to :length | | expected "a string" not to respond to :hash, :class, :to_s | | expected "a string" to respond to :flatten | | expected "a string" not to respond to :length | Scenario: Specify arguments Given a file named "respond_to_matcher_argument_checking_spec.rb" with: """ruby RSpec.describe 7 do it { is_expected.to respond_to(:zero?).with(0).arguments } it { is_expected.not_to respond_to(:zero?).with(1).argument } it { is_expected.to respond_to(:between?).with(2).arguments } it { is_expected.not_to respond_to(:between?).with(7).arguments } # deliberate failures it { is_expected.to respond_to(:zero?).with(1).argument } it { is_expected.not_to respond_to(:zero?).with(0).arguments } it { is_expected.to respond_to(:between?).with(7).arguments } it { is_expected.not_to respond_to(:between?).with(2).arguments } end """ When I run `rspec respond_to_matcher_argument_checking_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected 7 to respond to :zero? with 1 argument | | expected 7 not to respond to :zero? with 0 arguments | | expected 7 to respond to :between? with 7 arguments | | expected 7 not to respond to :between? with 2 arguments | @skip-when-splat-args-unsupported Scenario: Specify arguments range Given a file named "respond_to_matcher_argument_range_checking_spec.rb" with: """ruby class MyClass def build(name, options = {}) end def inspect 'my_object' end end RSpec.describe MyClass do it { is_expected.to respond_to(:build).with(1..2).arguments } it { is_expected.not_to respond_to(:build).with(0..1).arguments } it { is_expected.not_to respond_to(:build).with(2..3).arguments } it { is_expected.not_to respond_to(:build).with(0..3).arguments } # deliberate failures it { is_expected.not_to respond_to(:build).with(1..2).arguments } it { is_expected.to respond_to(:build).with(0..1).arguments } it { is_expected.to respond_to(:build).with(2..3).arguments } it { is_expected.to respond_to(:build).with(0..3).arguments } end """ When I run `rspec respond_to_matcher_argument_range_checking_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected my_object not to respond to :build with 1..2 arguments | | expected my_object to respond to :build with 0..1 arguments | | expected my_object to respond to :build with 2..3 arguments | | expected my_object to respond to :build with 0..3 arguments | @skip-when-splat-args-unsupported Scenario: Specify unlimited arguments Given a file named "respond_to_matcher_unlimited_argument_checking_spec.rb" with: """ruby class MyClass def greet(message = 'Hello', *people) end def hail(person) end def inspect 'my_object' end end RSpec.describe MyClass do it { is_expected.to respond_to(:greet).with_unlimited_arguments } it { is_expected.to respond_to(:greet).with(1).argument.and_unlimited_arguments } it { is_expected.not_to respond_to(:hail).with_unlimited_arguments } it { is_expected.not_to respond_to(:hail).with(1).argument.and_unlimited_arguments } # deliberate failures it { is_expected.not_to respond_to(:greet).with_unlimited_arguments } it { is_expected.not_to respond_to(:greet).with(1).argument.and_unlimited_arguments } it { is_expected.to respond_to(:hail).with_unlimited_arguments } it { is_expected.to respond_to(:hail).with(1).argument.and_unlimited_arguments } end """ When I run `rspec respond_to_matcher_unlimited_argument_checking_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected my_object not to respond to :greet with unlimited arguments | | expected my_object not to respond to :greet with 1 argument and unlimited arguments | | expected my_object to respond to :hail with unlimited arguments | | expected my_object to respond to :hail with 1 argument and unlimited arguments | @skip-when-keyword-args-unsupported Scenario: Specify keywords Given a file named "respond_to_matcher_keyword_checking_spec.rb" with: """ruby class MyClass def find(name = 'id', limit: 1_000, offset: 0) [] end def inspect 'my_object' end end RSpec.describe MyClass do it { is_expected.to respond_to(:find).with_keywords(:limit, :offset) } it { is_expected.to respond_to(:find).with(1).argument.and_keywords(:limit, :offset) } it { is_expected.not_to respond_to(:find).with_keywords(:limit, :offset, :page) } it { is_expected.not_to respond_to(:find).with(1).argument.and_keywords(:limit, :offset, :page) } # deliberate failures it { is_expected.to respond_to(:find).with_keywords(:limit, :offset, :page) } it { is_expected.to respond_to(:find).with(1).argument.and_keywords(:limit, :offset, :page) } it { is_expected.not_to respond_to(:find).with_keywords(:limit, :offset) } it { is_expected.not_to respond_to(:find).with(1).argument.and_keywords(:limit, :offset) } end """ When I run `rspec respond_to_matcher_keyword_checking_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected my_object to respond to :find with keywords :limit, :offset, and :page | | expected my_object to respond to :find with 1 argument and keywords :limit, :offset, and :page | | expected my_object not to respond to :find with keywords :limit and :offset | | expected my_object not to respond to :find with 1 argument and keywords :limit and :offset | @skip-when-keyword-args-unsupported Scenario: Specify any keywords Given a file named "respond_to_matcher_any_keywords_checking_spec.rb" with: """ruby class MyClass def build(name: 'object', **opts) end def create(name: 'object', type: String) end def inspect 'my_object' end end RSpec.describe MyClass do it { is_expected.to respond_to(:build).with_any_keywords } it { is_expected.to respond_to(:build).with_keywords(:name).and_any_keywords } it { is_expected.not_to respond_to(:create).with_any_keywords } it { is_expected.not_to respond_to(:create).with_keywords(:name).and_any_keywords } # deliberate failures it { is_expected.not_to respond_to(:build).with_any_keywords } it { is_expected.not_to respond_to(:build).with_keywords(:name).and_any_keywords } it { is_expected.to respond_to(:create).with_any_keywords } it { is_expected.to respond_to(:create).with_keywords(:name).and_any_keywords } end """ When I run `rspec respond_to_matcher_any_keywords_checking_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected my_object not to respond to :build with any keywords | | expected my_object not to respond to :build with keyword :name and any keywords | | expected my_object to respond to :create with any keywords | | expected my_object to respond to :create with keyword :name and any keywords | @skip-when-required-keyword-args-unsupported Scenario: Specify required keywords Given a file named "respond_to_matcher_required_keyword_checking_spec.rb" with: """ruby class MyClass def plant(seed:, fertilizer: nil, water: 'daily') [] end def inspect 'my_object' end end RSpec.describe MyClass do it { is_expected.to respond_to(:plant).with_keywords(:seed) } it { is_expected.to respond_to(:plant).with_keywords(:seed, :fertilizer, :water) } it { is_expected.not_to respond_to(:plant).with_keywords(:fertilizer, :water) } # deliberate failures it { is_expected.not_to respond_to(:plant).with_keywords(:seed) } it { is_expected.not_to respond_to(:plant).with_keywords(:seed, :fertilizer, :water) } it { is_expected.to respond_to(:plant).with_keywords(:fertilizer, :water) } end """ When I run `rspec respond_to_matcher_required_keyword_checking_spec.rb` Then the output should contain all of these: | 6 examples, 3 failures | | expected my_object not to respond to :plant with keyword :seed | | expected my_object not to respond to :plant with keywords :seed, :fertilizer, and :water | | expected my_object to respond to :plant with keywords :fertilizer and :water | rspec-expectations-3.13.0/features/built_in_matchers/satisfy.feature000066400000000000000000000027551455770000100257760ustar00rootroot00000000000000Feature: `satisfy` matcher The `satisfy` matcher is extremely flexible and can handle almost anything you want to specify. It passes if the block you provide returns true: ```ruby expect(10).to satisfy { |v| v % 5 == 0 } expect(7).not_to satisfy { |v| v % 5 == 0 } ``` The default failure message ("expected [actual] to satisfy block") is not very descriptive or helpful. To add clarification, you can provide your own description as an argument: ```ruby expect(10).to satisfy("be a multiple of 5") do |v| v % 5 == 0 end ``` @skip-when-ripper-unsupported Scenario: Basic usage Given a file named "satisfy_matcher_spec.rb" with: """ruby RSpec.describe 10 do it { is_expected.to satisfy { |v| v > 5 } } it { is_expected.not_to satisfy { |v| v > 15 } } # deliberate failures it { is_expected.not_to satisfy { |v| v > 5 } } it { is_expected.to satisfy { |v| v > 15 } } it { is_expected.to_not satisfy("be greater than 5") { |v| v > 5 } } it { is_expected.to satisfy("be greater than 15") { |v| v > 15 } } end """ When I run `rspec satisfy_matcher_spec.rb` Then the output should contain all of these: | 6 examples, 4 failures | | expected 10 not to satisfy expression `v > 5` | | expected 10 to satisfy expression `v > 15` | | expected 10 not to be greater than 5 | | expected 10 to be greater than 15 | rspec-expectations-3.13.0/features/built_in_matchers/start_with.feature000066400000000000000000000032011455770000100264670ustar00rootroot00000000000000Feature: `start_with` matcher Use the `start_with` matcher to specify that a string or array starts with the expected characters or elements. ```ruby expect("this string").to start_with("this") expect("this string").not_to start_with("that") expect([0,1,2]).to start_with(0, 1) ``` Scenario: With a string Given a file named "example_spec.rb" with: """ruby RSpec.describe "this string" do it { is_expected.to start_with "this" } it { is_expected.not_to start_with "that" } # deliberate failures it { is_expected.not_to start_with "this" } it { is_expected.to start_with "that" } end """ When I run `rspec example_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected "this string" not to start with "this" | | expected "this string" to start with "that" | Scenario: With an array Given a file named "example_spec.rb" with: """ruby RSpec.describe [0, 1, 2, 3, 4] do it { is_expected.to start_with 0 } it { is_expected.to start_with(0, 1)} it { is_expected.not_to start_with(2) } it { is_expected.not_to start_with(0, 1, 2, 3, 4, 5) } # deliberate failures it { is_expected.not_to start_with 0 } it { is_expected.to start_with 3 } end """ When I run `rspec example_spec.rb` Then the output should contain all of these: | 6 examples, 2 failures | | expected [0, 1, 2, 3, 4] not to start with 0 | | expected [0, 1, 2, 3, 4] to start with 3 | rspec-expectations-3.13.0/features/built_in_matchers/throw_symbol.feature000066400000000000000000000074331455770000100270420ustar00rootroot00000000000000Feature: `throw_symbol` matcher The `throw_symbol` matcher is used to specify that a block of code throws a symbol. The most basic form passes if any symbol is thrown: ```ruby expect { throw :foo }.to throw_symbol ``` You'll often want to specify that a particular symbol is thrown: ```ruby expect { throw :foo }.to throw_symbol(:foo) ``` If you care about the additional argument given to throw, you can specify that as well: ```ruby expect { throw :foo, 7 }.to throw_symbol(:foo, 7) ``` Scenario: Basic usage Given a file named "throw_symbol_matcher_spec.rb" with: """ruby RSpec.describe "throw" do specify { expect { throw :foo }.to throw_symbol } specify { expect { throw :bar, 7 }.to throw_symbol } specify { expect { 5 + 5 }.not_to throw_symbol } # deliberate failures specify { expect { throw :foo }.not_to throw_symbol } specify { expect { throw :bar, 7 }.not_to throw_symbol } specify { expect { 5 + 5 }.to throw_symbol } end """ When I run `rspec throw_symbol_matcher_spec.rb` Then the output should contain all of these: | 6 examples, 3 failures | | expected no Symbol to be thrown, got :foo | | expected no Symbol to be thrown, got :bar | | expected a Symbol to be thrown, got nothing | Scenario: Specify thrown symbol Given a file named "throw_symbol_matcher_spec.rb" with: """ruby RSpec.describe "throw symbol" do specify { expect { throw :foo }.to throw_symbol(:foo) } specify { expect { throw :foo, 7 }.to throw_symbol(:foo) } specify { expect { 5 + 5 }.not_to throw_symbol(:foo) } specify { expect { throw :bar }.not_to throw_symbol(:foo) } # deliberate failures specify { expect { throw :foo }.not_to throw_symbol(:foo) } specify { expect { throw :foo, 7 }.not_to throw_symbol(:foo) } specify { expect { 5 + 5 }.to throw_symbol(:foo) } specify { expect { throw :bar }.to throw_symbol(:foo) } end """ When I run `rspec throw_symbol_matcher_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected :foo not to be thrown, got :foo | | expected :foo not to be thrown, got :foo with 7 | | expected :foo to be thrown, got nothing | | expected :foo to be thrown, got :bar | Scenario: Specify thrown symbol and argument Given a file named "throw_symbol_argument_matcher_spec.rb" with: """ruby RSpec.describe "throw symbol with argument" do specify { expect { throw :foo, 7 }.to throw_symbol(:foo, 7) } specify { expect { throw :foo, 8 }.not_to throw_symbol(:foo, 7) } specify { expect { throw :bar, 7 }.not_to throw_symbol(:foo, 7) } specify { expect { throw :foo }.not_to throw_symbol(:foo, 7) } # deliberate failures specify { expect { throw :foo, 7 }.not_to throw_symbol(:foo, 7) } specify { expect { throw :foo, 8 }.to throw_symbol(:foo, 7) } specify { expect { throw :bar, 7 }.to throw_symbol(:foo, 7) } specify { expect { throw :foo }.to throw_symbol(:foo, 7) } end """ When I run `rspec throw_symbol_argument_matcher_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected :foo with 7 not to be thrown, got :foo with 7 | | expected :foo with 7 to be thrown, got :foo with 8 | | expected :foo with 7 to be thrown, got :bar | | expected :foo with 7 to be thrown, got :foo with no argument | rspec-expectations-3.13.0/features/built_in_matchers/types.feature000066400000000000000000000106761455770000100254610ustar00rootroot00000000000000Feature: Type matchers rspec-expectations includes two matchers to specify types of objects: * `expect(obj).to be_kind_of(type)`: calls `obj.kind_of?(type)`, which returns true if type is in obj's class hierarchy or is a module and is included in a class in obj's class hierarchy. * `expect(obj).to be_instance_of(type)`: calls `obj.instance_of?(type)`, which returns true if and only if type if obj's class. Both of these matchers have aliases: ```ruby expect(obj).to be_a_kind_of(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_a(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_an(type) # same as expect(obj).to be_kind_of(type) expect(obj).to be_an_instance_of(type) # same as expect(obj).to be_instance_of(type) ``` Scenario: With `be_(a_)kind_of` matcher Given a file named "be_kind_of_matcher_spec.rb" with: """ruby module MyModule; end class Float include MyModule end RSpec.describe 17.0 do # the actual class it { is_expected.to be_kind_of(Float) } it { is_expected.to be_a_kind_of(Float) } it { is_expected.to be_a(Float) } # the superclass it { is_expected.to be_kind_of(Numeric) } it { is_expected.to be_a_kind_of(Numeric) } it { is_expected.to be_an(Numeric) } # an included module it { is_expected.to be_kind_of(MyModule) } it { is_expected.to be_a_kind_of(MyModule) } it { is_expected.to be_a(MyModule) } # negative passing case it { is_expected.not_to be_kind_of(String) } it { is_expected.not_to be_a_kind_of(String) } it { is_expected.not_to be_a(String) } # deliberate failures it { is_expected.not_to be_kind_of(Float) } it { is_expected.not_to be_a_kind_of(Float) } it { is_expected.not_to be_a(Float) } it { is_expected.not_to be_kind_of(Numeric) } it { is_expected.not_to be_a_kind_of(Numeric) } it { is_expected.not_to be_an(Numeric) } it { is_expected.not_to be_kind_of(MyModule) } it { is_expected.not_to be_a_kind_of(MyModule) } it { is_expected.not_to be_a(MyModule) } it { is_expected.to be_kind_of(String) } it { is_expected.to be_a_kind_of(String) } it { is_expected.to be_a(String) } end """ When I run `rspec be_kind_of_matcher_spec.rb` Then the output should contain all of these: | 24 examples, 12 failures | | expected 17.0 not to be a kind of Float | | expected 17.0 not to be a kind of Numeric | | expected 17.0 not to be a kind of MyModule | | expected 17.0 to be a kind of String | Scenario: With `be_(an_)instance_of` matcher Given a file named "be_instance_of_matcher_spec.rb" with: """ruby module MyModule; end class Float include MyModule end RSpec.describe 17.0 do # the actual class it { is_expected.to be_instance_of(Float) } it { is_expected.to be_an_instance_of(Float) } # the superclass it { is_expected.not_to be_instance_of(Numeric) } it { is_expected.not_to be_an_instance_of(Numeric) } # an included module it { is_expected.not_to be_instance_of(MyModule) } it { is_expected.not_to be_an_instance_of(MyModule) } # another class with no relation to the subject's hierarchy it { is_expected.not_to be_instance_of(String) } it { is_expected.not_to be_an_instance_of(String) } # deliberate failures it { is_expected.not_to be_instance_of(Float) } it { is_expected.not_to be_an_instance_of(Float) } it { is_expected.to be_instance_of(Numeric) } it { is_expected.to be_an_instance_of(Numeric) } it { is_expected.to be_instance_of(MyModule) } it { is_expected.to be_an_instance_of(MyModule) } it { is_expected.to be_instance_of(String) } it { is_expected.to be_an_instance_of(String) } end """ When I run `rspec be_instance_of_matcher_spec.rb` Then the output should contain all of these: | 16 examples, 8 failures | | expected 17.0 not to be an instance of Float | | expected 17.0 to be an instance of Numeric | | expected 17.0 to be an instance of MyModule | | expected 17.0 to be an instance of String | rspec-expectations-3.13.0/features/built_in_matchers/yield.feature000066400000000000000000000202401455770000100254070ustar00rootroot00000000000000Feature: `yield` matchers There are four related matchers that allow you to specify whether or not a method yields, how many times it yields, whether or not it yields with arguments, and what those arguments are. * `yield_control` matches if the method-under-test yields, regardless of whether or not arguments are yielded. * `yield_with_args` matches if the method-under-test yields with arguments. If arguments are provided to this matcher, it will only pass if the actual yielded arguments match the expected ones using `===` or `==`. * `yield_with_no_args` matches if the method-under-test yields with no arguments. * `yield_successive_args` is designed for iterators, and will match if the method-under-test yields the same number of times as arguments passed to this matcher, and all actual yielded arguments match the expected ones using `===` or `==`. Note: your expect block _must_ accept an argument that is then passed on to the method-under-test as a block. This acts as a "probe" that allows the matcher to detect whether or not your method yields, and, if so, how many times and what the yielded arguments are. Background: Given a file named "my_class.rb" with: """ruby class MyClass def self.yield_once_with(*args) yield *args end def self.yield_twice_with(*args) 2.times { yield *args } end def self.raw_yield yield end def self.dont_yield end end """ Scenario: The `yield_control` matcher Given a file named "yield_control_spec.rb" with: """ruby require './my_class' RSpec.describe "yield_control matcher" do specify { expect { |b| MyClass.yield_once_with(1, &b) }.to yield_control } specify { expect { |b| MyClass.dont_yield(&b) }.not_to yield_control } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.twice } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.exactly(2).times } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.at_least(1) } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.at_most(3).times } # deliberate failures specify { expect { |b| MyClass.yield_once_with(1, &b) }.not_to yield_control } specify { expect { |b| MyClass.dont_yield(&b) }.to yield_control } specify { expect { |b| MyClass.yield_once_with(1, &b) }.to yield_control.at_least(2).times } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.not_to yield_control.twice } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.not_to yield_control.at_least(2).times } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.not_to yield_control.at_least(1) } specify { expect { |b| MyClass.yield_twice_with(1, &b) }.not_to yield_control.at_most(3).times } end """ When I run `rspec yield_control_spec.rb` Then the output should contain all of these: | 13 examples, 7 failures | | expected given block to yield control | | expected given block not to yield control | | expected given block not to yield control at least twice | | expected given block not to yield control at most 3 times | Scenario: The `yield_with_args` matcher Given a file named "yield_with_args_spec.rb" with: """ruby require './my_class' RSpec.describe "yield_with_args matcher" do specify { expect { |b| MyClass.yield_once_with("foo", &b) }.to yield_with_args } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.to yield_with_args("foo") } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.to yield_with_args(String) } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.to yield_with_args(/oo/) } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.to yield_with_args("foo", "bar") } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.to yield_with_args(String, String) } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.to yield_with_args(/fo/, /ar/) } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.not_to yield_with_args(17, "baz") } # deliberate failures specify { expect { |b| MyClass.yield_once_with("foo", &b) }.not_to yield_with_args } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.not_to yield_with_args("foo") } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.not_to yield_with_args(String) } specify { expect { |b| MyClass.yield_once_with("foo", &b) }.not_to yield_with_args(/oo/) } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.not_to yield_with_args("foo", "bar") } specify { expect { |b| MyClass.yield_once_with("foo", "bar", &b) }.to yield_with_args(17, "baz") } end """ When I run `rspec yield_with_args_spec.rb` Then the output should contain all of these: | 14 examples, 6 failures | | expected given block not to yield with arguments, but did | | expected given block not to yield with arguments, but yielded with expected arguments | | expected given block to yield with arguments, but yielded with unexpected arguments | Scenario: The `yield_with_no_args` matcher Given a file named "yield_with_no_args_spec.rb" with: """ruby require './my_class' RSpec.describe "yield_with_no_args matcher" do specify { expect { |b| MyClass.raw_yield(&b) }.to yield_with_no_args } specify { expect { |b| MyClass.dont_yield(&b) }.not_to yield_with_no_args } specify { expect { |b| MyClass.yield_once_with("a", &b) }.not_to yield_with_no_args } # deliberate failures specify { expect { |b| MyClass.raw_yield(&b) }.not_to yield_with_no_args } specify { expect { |b| MyClass.dont_yield(&b) }.to yield_with_no_args } specify { expect { |b| MyClass.yield_once_with("a", &b) }.to yield_with_no_args } end """ When I run `rspec yield_with_no_args_spec.rb` Then the output should contain all of these: | 6 examples, 3 failures | | expected given block not to yield with no arguments, but did | | expected given block to yield with no arguments, but did not yield | | expected given block to yield with no arguments, but yielded with arguments: ["a"] | Scenario: The `yield_successive_args` matcher Given a file named "yield_successive_args_spec.rb" with: """ruby def array [1, 2, 3] end def array_of_tuples [[:a, :b], [:c, :d]] end RSpec.describe "yield_successive_args matcher" do specify { expect { |b| array.each(&b) }.to yield_successive_args(1, 2, 3) } specify { expect { |b| array_of_tuples.each(&b) }.to yield_successive_args([:a, :b], [:c, :d]) } specify { expect { |b| array.each(&b) }.to yield_successive_args(Integer, Integer, Integer) } specify { expect { |b| array.each(&b) }.not_to yield_successive_args(1, 2) } # deliberate failures specify { expect { |b| array.each(&b) }.not_to yield_successive_args(1, 2, 3) } specify { expect { |b| array_of_tuples.each(&b) }.not_to yield_successive_args([:a, :b], [:c, :d]) } specify { expect { |b| array.each(&b) }.not_to yield_successive_args(Integer, Integer, Integer) } specify { expect { |b| array.each(&b) }.to yield_successive_args(1, 2) } end """ When I run `rspec yield_successive_args_spec.rb` Then the output should contain all of these: | 8 examples, 4 failures | | expected given block not to yield successively with arguments, but yielded with expected arguments | | expected given block to yield successively with arguments, but yielded with unexpected arguments | rspec-expectations-3.13.0/features/composing_matchers.feature000066400000000000000000000211451455770000100244770ustar00rootroot00000000000000Feature: Composing Matchers RSpec's matchers are designed to be composable so that you can combine them to express the exact details of what you expect but nothing more. This can help you avoid writing over-specified brittle specs, by using a matcher in place of an exact value to specify only the essential aspects of what you expect. The following matchers accept matchers as arguments: * `change { }.by(matcher)` * `change { }.from(matcher).to(matcher)` * `contain_exactly(matcher, matcher, matcher)` * `end_with(matcher, matcher)` * `include(matcher, matcher)` * `include(:key => matcher, :other => matcher)` * `match(arbitrary_nested_structure_with_matchers)` * `output(matcher).to_stdout` * `output(matcher).to_stderr` * `raise_error(ErrorClass, matcher)` * `start_with(matcher, matcher)` * `throw_symbol(:sym, matcher)` * `yield_with_args(matcher, matcher)` * `yield_successive_args(matcher, matcher)` Note that many built-in matchers do not accept matcher arguments because they have precise semantics that do not allow for a matcher argument. For example, `equal(some_object)` is designed to pass only if the actual and expected arguments are references to the same object. It would not make sense to support a matcher argument here. All of RSpec's built-in matchers have one or more aliases that allow you to use a noun-phrase rather than verb form since they read better as composed arguments. They also provide customized failure output so that the failure message reads better as well. A full list of these aliases is out of scope here, but here are some of the aliases used below: * `be < 2` => `a_value < 2` * `be > 2` => `a_value > 2` * `be_an_instance_of` => `an_instance_of` * `be_within` => `a_value_within` * `contain_exactly` => `a_collection_containing_exactly` * `end_with` => `a_string_ending_with`, `ending_with` * `match` => `a_string_matching` * `start_with` => `a_string_starting_with` For a full list, see the API docs for the `RSpec::Matchers` module. Scenario: Composing matchers with `change` Given a file named "change_spec.rb" with: """ruby RSpec.describe "Passing matchers to `change`" do specify "you can pass a matcher to `by`" do k = 0 expect { k += 1.05 }.to change { k }. by( a_value_within(0.1).of(1.0) ) end specify "you can pass matchers to `from` and `to`" do s = "food" expect { s = "barn" }.to change { s }. from( a_string_matching(/foo/) ). to( a_string_matching(/bar/) ) end end """ When I run `rspec change_spec.rb` Then the examples should all pass Scenario: Composing matchers with `contain_exactly` Given a file named "contain_exactly_spec.rb" with: """ruby RSpec.describe "Passing matchers to `contain_exactly`" do specify "you can pass matchers in place of exact values" do expect(["barn", 2.45]).to contain_exactly( a_value_within(0.1).of(2.5), a_string_starting_with("bar") ) end end """ When I run `rspec contain_exactly_spec.rb` Then the examples should all pass Scenario: Composing matchers with `end_with` Given a file named "end_with_spec.rb" with: """ruby RSpec.describe "Passing matchers to `end_with`" do specify "you can pass matchers in place of exact values" do expect(["barn", "food", 2.45]).to end_with( a_string_matching("foo"), a_value > 2 ) end end """ When I run `rspec end_with_spec.rb` Then the examples should all pass Scenario: Composing matchers with `include` Given a file named "include_spec.rb" with: """ruby RSpec.describe "Passing matchers to `include`" do specify "you can use matchers in place of array values" do expect(["barn", 2.45]).to include( a_string_starting_with("bar") ) end specify "you can use matchers in place of hash values" do expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/)) end specify "you can use matchers in place of hash keys" do expect("food" => "is good").to include( a_string_matching(/foo/) ) end end """ When I run `rspec include_spec.rb` Then the examples should all pass Scenario: Composing matchers with `match`: Given a file named "match_spec.rb" with: """ruby RSpec.describe "Passing matchers to `match`" do specify "you can match nested data structures against matchers" do hash = { :a => { :b => ["foo", 5.0], :c => { :d => 2.05 } } } expect(hash).to match( :a => { :b => a_collection_containing_exactly( a_string_starting_with("f"), an_instance_of(Float) ), :c => { :d => (a_value < 3) } } ) end end """ When I run `rspec match_spec.rb` Then the examples should all pass Scenario: Composing matchers with `output` Given a file named "output_spec.rb" with: """ruby RSpec.describe "Passing matchers to `output`" do specify "you can pass a matcher in place of the output (to_stdout)" do expect { print 'foo' }.to output(a_string_starting_with('f')).to_stdout end specify "you can pass a matcher in place of the output (to_stderr)" do expect { warn 'foo' }.to output(a_string_starting_with('f')).to_stderr end end """ When I run `rspec output_spec.rb` Then the examples should all pass Scenario: Composing matchers with `raise_error` Given a file named "raise_error_spec.rb" with: """ruby RSpec.describe "Passing matchers to `raise_error`" do specify "you can pass a matcher in place of the message" do expect { raise RuntimeError, "this goes boom" }.to raise_error(RuntimeError, a_string_ending_with("boom")) end end """ When I run `rspec raise_error_spec.rb` Then the examples should all pass Scenario: Composing matchers with `start_with` Given a file named "start_with_spec.rb" with: """ruby RSpec.describe "Passing matchers to `start_with`" do specify "you can pass matchers in place of exact values" do expect(["barn", "food", 2.45]).to start_with( a_string_matching("bar"), a_string_matching("foo") ) end end """ When I run `rspec start_with_spec.rb` Then the examples should all pass Scenario: Composing matchers with `throw_symbol` Given a file named "throw_symbol_spec.rb" with: """ruby RSpec.describe "Passing matchers to `throw_symbol`" do specify "you can pass a matcher in place of a throw arg" do expect { throw :pi, Math::PI }.to throw_symbol(:pi, a_value_within(0.01).of(3.14)) end end """ When I run `rspec throw_symbol_spec.rb` Then the examples should all pass Scenario: Composing matchers with `yield_with_args` Given a file named "yield_with_args_spec.rb" with: """ruby RSpec.describe "Passing matchers to `yield_with_args`" do specify "you can pass matchers in place of the args" do expect { |probe| "food".tap(&probe) }.to yield_with_args(a_string_matching(/foo/)) end end """ When I run `rspec yield_with_args_spec.rb` Then the examples should all pass Scenario: Composing matchers with `yield_successive_args` Given a file named "yield_successive_args_spec.rb" with: """ruby RSpec.describe "Passing matchers to `yield_successive_args`" do specify "you can pass matchers in place of the args" do expect { |probe| [1, 2, 3].each(&probe) }.to yield_successive_args(a_value < 2, 2, a_value > 2) end end """ When I run `rspec yield_successive_args_spec.rb` Then the examples should all pass Scenario: Composing matchers using a compound `and` expression Given a file named "include_spec.rb" with: """ruby RSpec.describe "Passing a compound matcher expression to `include`" do example do expect(["food", "drink"]).to include( a_string_starting_with("f").and ending_with("d")) end end """ When I run `rspec include_spec.rb` Then the examples should all pass rspec-expectations-3.13.0/features/compound_expectations.feature000066400000000000000000000031351455770000100252240ustar00rootroot00000000000000Feature: Compound Expectations Matchers can be composed using `and` or `or` to make compound expectations. Scenario: Use `and` to chain expectations Given a file named "compound_and_matcher_spec.rb" with: """ruby RSpec.describe "A compound `and` matcher" do let(:string) { "foo bar bazz" } it "passes when both are true" do expect(string).to start_with("foo").and end_with("bazz") end it "passes when using boolean AND `&` alias" do expect(string).to start_with("foo") & end_with("bazz") end it "fails when the first matcher fails" do expect(string).to start_with("bar").and end_with("bazz") end it "fails when the second matcher fails" do expect(string).to start_with("foo").and end_with("bar") end end """ When I run `rspec compound_and_matcher_spec.rb` Then the output should contain "4 examples, 2 failures" Scenario: Use `or` to chain expectations Given a file named "stoplight_spec.rb" with: """ruby class StopLight def color %w[ green yellow red ].shuffle.first end end RSpec.describe StopLight, "#color" do let(:light) { StopLight.new } it "is green, yellow or red" do expect(light.color).to eq("green").or eq("yellow").or eq("red") end it "passes when using boolean OR `|` alias" do expect(light.color).to eq("green") | eq("yellow") | eq("red") end end """ When I run `rspec stoplight_spec.rb` Then the example should pass rspec-expectations-3.13.0/features/custom_matchers/000077500000000000000000000000001455770000100224335ustar00rootroot00000000000000rspec-expectations-3.13.0/features/custom_matchers/access_running_example.feature000066400000000000000000000026431455770000100305310ustar00rootroot00000000000000Feature: Access the running example In the context of a custom matcher, you can call helper methods that are available from the current example's example group. This is used, for example, by rspec-rails in order to wrap rails' built-in assertions (which depend on helper methods available in the test context). Scenario: Call method defined on example from matcher Given a file named "example_spec.rb" with: """ruby RSpec::Matchers.define :bar do match do |_| foo == "foo" end end RSpec.describe "something" do def foo "foo" end it "does something" do expect("foo").to bar end end """ When I run `rspec ./example_spec.rb` Then the output should contain "1 example, 0 failures" Scenario: Call method _not_ defined on example from matcher Given a file named "example_spec.rb" with: """ruby RSpec::Matchers.define :bar do match do |_| foo == "foo" end end RSpec.describe "something" do it "does something" do expect("foo").to bar end end """ When I run `rspec ./example_spec.rb` Then the output should contain "1 example, 1 failure" And the output should match /undefined.*method/ And the output should contain "RSpec::Matchers::DSL::Matcher" And the output should not contain "ExampleGroup" rspec-expectations-3.13.0/features/custom_matchers/define_block_matcher.feature000066400000000000000000000043071455770000100301230ustar00rootroot00000000000000Feature: Defining a matcher supporting block expectations When you wish to support block expectations (e.g. `expect { ... }.to matcher`) with your custom matchers you must specify this. You can do this manually (or determinately based on some logic) by defining a `supports_block_expectation?` method or by using the DSL's `supports_block_expectations` shortcut method. Scenario: Define a block matcher manually Given a file named "block_matcher_spec.rb" with: """ruby RSpec::Matchers.define :support_blocks do match do |actual| actual.is_a? Proc end def supports_block_expectations? true # or some logic end end RSpec.describe "a custom block matcher" do specify { expect { }.to support_blocks } end """ When I run `rspec ./block_matcher_spec.rb` Then the example should pass Scenario: Define a block matcher using shortcut Given a file named "block_matcher_spec.rb" with: """ruby RSpec::Matchers.define :support_blocks do match do |actual| actual.is_a? Proc end supports_block_expectations end RSpec.describe "a custom block matcher" do specify { expect { }.to support_blocks } end """ When I run `rspec ./block_matcher_spec.rb` Then the example should pass Scenario: Define a block matcher using shortcut Given a file named "block_matcher_spec.rb" with: """ruby RSpec::Matchers.define :support_blocks_with_errors do match(:notify_expectation_failures => true) do |actual| actual.call true end supports_block_expectations end RSpec.describe "a custom block matcher" do specify do expect { expect(true).to eq false }.to support_blocks_with_errors end end """ When I run `rspec ./block_matcher_spec.rb` Then it should fail with: """ Failures: 1) a custom block matcher is expected to support blocks with errors Failure/Error: expect(true).to eq false expected: false got: true (compared using ==) """ rspec-expectations-3.13.0/features/custom_matchers/define_diffable_matcher.feature000066400000000000000000000072501455770000100305650ustar00rootroot00000000000000Feature: Defining a diffable matcher When a matcher is defined as diffable, the output will include a diff of the submitted objects when the objects are more than simple primitives. @skip-when-diff-lcs-1.3 Scenario: Define a diffable matcher (with diff-lcs 1.4) Given a file named "diffable_matcher_spec.rb" with: """ruby RSpec::Matchers.define :be_just_like do |expected| match do |actual| actual == expected end diffable end RSpec.describe "two\nlines" do it { is_expected.to be_just_like("three\nlines") } end """ When I run `rspec ./diffable_matcher_spec.rb` Then it should fail with: """ Diff: @@ -1 +1 @@ -three +two """ @skip-when-diff-lcs-1.4 Scenario: Define a diffable matcher (with diff-lcs 1.3) Given a file named "diffable_matcher_spec.rb" with: """ruby RSpec::Matchers.define :be_just_like do |expected| match do |actual| actual == expected end diffable end RSpec.describe "two\nlines" do it { is_expected.to be_just_like("three\nlines") } end """ When I run `rspec ./diffable_matcher_spec.rb` Then it should fail with: """ Diff: @@ -1,3 +1,3 @@ -three +two lines """ @skip-when-diff-lcs-1.3 @skip-when-diff-lcs-1.4.3 Scenario: Redefine actual (with diff-lcs 1.4.4) Sometimes is necessary to overwrite actual to make diffing work, e.g. if `actual` is a name of a file you want to read from. For this to work you need to overwrite `@actual` in your matcher. Given a file named "redefine_actual_matcher_spec.rb" with: """ruby RSpec::Matchers.define :have_content do |expected| match do |actual| @actual = File.read(actual).chomp values_match? expected, @actual end diffable end RSpec.describe 'Compare files' do context 'when content is equal' do it { expect('data.txt').to have_content 'Data' } end context 'when files are different' do it { expect('data.txt').to have_content "No\nData\nhere" } end end """ And a file named "data.txt" with: """ Data """ When I run `rspec ./redefine_actual_matcher_spec.rb --format documentation` Then the exit status should not be 0 And the output should contain: """ 2 examples, 1 failure """ And the output should contain: """ @@ -1,4 +1,2 @@ -No Data -here """ @skip-when-diff-lcs-1.4 Scenario: Redefine actual (with diff-lcs 1.3) Given a file named "redefine_actual_matcher_spec.rb" with: """ruby RSpec::Matchers.define :have_content do |expected| match do |actual| @actual = File.read(actual).chomp values_match? expected, @actual end diffable end RSpec.describe 'Compare files' do context 'when content is equal' do it { expect('data.txt').to have_content 'Data' } end context 'when files are different' do it { expect('data.txt').to have_content "No\nData\nhere" } end end """ And a file named "data.txt" with: """ Data """ When I run `rspec ./redefine_actual_matcher_spec.rb --format documentation` Then the exit status should not be 0 And the output should contain: """ 2 examples, 1 failure """ And the output should contain: """ @@ -1,4 +1,2 @@ -No Data -here """ rspec-expectations-3.13.0/features/custom_matchers/define_matcher.feature000066400000000000000000000377671455770000100267710ustar00rootroot00000000000000Feature: Defining a custom matcher rspec-expectations provides a DSL for defining custom matchers. These are often useful for expressing expectations in the domain of your application. Behind the scenes `RSpec::Matchers.define` evaluates the `define` block in the context of a singleton class. If you need to write a more complex matcher and would like to use the `Class`-approach yourself, please head over to our `API`-documentation and read [the docs](http://rspec.info/documentation/latest/rspec-expectations/RSpec/Matchers/MatcherProtocol.html) about the `MatcherProtocol`. Scenario: Define a matcher with default messages Given a file named "matcher_with_default_message_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end end RSpec.describe 9 do it { is_expected.to be_a_multiple_of(3) } end RSpec.describe 9 do it { is_expected.not_to be_a_multiple_of(4) } end # fail intentionally to generate expected output RSpec.describe 9 do it { is_expected.to be_a_multiple_of(4) } end # fail intentionally to generate expected output RSpec.describe 9 do it { is_expected.not_to be_a_multiple_of(3) } end """ When I run `rspec ./matcher_with_default_message_spec.rb --format documentation` Then the exit status should not be 0 And the output should contain "is expected to be a multiple of 3" And the output should contain "is expected not to be a multiple of 4" And the output should contain "Failure/Error: it { is_expected.to be_a_multiple_of(4) }" And the output should contain "Failure/Error: it { is_expected.not_to be_a_multiple_of(3) }" And the output should contain "4 examples, 2 failures" And the output should contain "expected 9 to be a multiple of 4" And the output should contain "expected 9 not to be a multiple of 3" Scenario: Overriding the failure_message Given a file named "matcher_with_failure_message_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end failure_message do |actual| "expected that #{actual} would be a multiple of #{expected}" end end # fail intentionally to generate expected output RSpec.describe 9 do it { is_expected.to be_a_multiple_of(4) } end """ When I run `rspec ./matcher_with_failure_message_spec.rb` Then the exit status should not be 0 And the stdout should contain "1 example, 1 failure" And the stdout should contain "expected that 9 would be a multiple of 4" Scenario: Overriding the failure_message_when_negated Given a file named "matcher_with_failure_for_message_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end failure_message_when_negated do |actual| "expected that #{actual} would not be a multiple of #{expected}" end end # fail intentionally to generate expected output RSpec.describe 9 do it { is_expected.not_to be_a_multiple_of(3) } end """ When I run `rspec ./matcher_with_failure_for_message_spec.rb` Then the exit status should not be 0 And the stdout should contain "1 example, 1 failure" And the stdout should contain "expected that 9 would not be a multiple of 3" Scenario: Overriding the description Given a file named "matcher_overriding_description_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end description do "be multiple of #{expected}" end end RSpec.describe 9 do it { is_expected.to be_a_multiple_of(3) } end RSpec.describe 9 do it { is_expected.not_to be_a_multiple_of(4) } end """ When I run `rspec ./matcher_overriding_description_spec.rb --format documentation` Then the exit status should be 0 And the stdout should contain "2 examples, 0 failures" And the stdout should contain "is expected to be multiple of 3" And the stdout should contain "is expected not to be multiple of 4" Scenario: With no args Given a file named "matcher_with_no_args_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :have_7_fingers do match do |thing| thing.fingers.length == 7 end end class Thing def fingers; (1..7).collect {"finger"}; end end RSpec.describe Thing do it { is_expected.to have_7_fingers } end """ When I run `rspec ./matcher_with_no_args_spec.rb --format documentation` Then the exit status should be 0 And the stdout should contain "1 example, 0 failures" And the stdout should contain "is expected to have 7 fingers" Scenario: With multiple args Given a file named "matcher_with_multiple_args_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_the_sum_of do |a,b,c,d| match do |sum| a + b + c + d == sum end end RSpec.describe 10 do it { is_expected.to be_the_sum_of(1,2,3,4) } end """ When I run `rspec ./matcher_with_multiple_args_spec.rb --format documentation` Then the exit status should be 0 And the stdout should contain "1 example, 0 failures" And the stdout should contain "is expected to be the sum of 1, 2, 3, and 4" Scenario: With a block arg Given a file named "matcher_with_block_arg_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :be_lazily_equal_to do match do |obj| obj == block_arg.call end description { "be lazily equal to #{block_arg.call}" } end RSpec.describe 10 do it { is_expected.to be_lazily_equal_to { 10 } } end """ When I run `rspec ./matcher_with_block_arg_spec.rb --format documentation` Then the exit status should be 0 And the stdout should contain "1 example, 0 failures" And the stdout should contain "is expected to be lazily equal to 10" Scenario: With helper methods Given a file named "matcher_with_internal_helper_spec.rb" with: """ruby require 'rspec/expectations' RSpec::Matchers.define :have_same_elements_as do |sample| match do |actual| similar?(sample, actual) end def similar?(a, b) a.sort == b.sort end end RSpec.describe "these two arrays" do specify "should be similar" do expect([1,2,3]).to have_same_elements_as([2,3,1]) end end """ When I run `rspec ./matcher_with_internal_helper_spec.rb` Then the exit status should be 0 And the stdout should contain "1 example, 0 failures" Scenario: Scoped in a module Given a file named "scoped_matcher_spec.rb" with: """ruby require 'rspec/expectations' module MyHelpers extend RSpec::Matchers::DSL matcher :be_just_like do |expected| match {|actual| actual == expected} end end RSpec.describe "group with MyHelpers" do include MyHelpers it "has access to the defined matcher" do expect(5).to be_just_like(5) end end RSpec.describe "group without MyHelpers" do it "does not have access to the defined matcher" do expect do expect(5).to be_just_like(5) end.to raise_exception end end """ When I run `rspec ./scoped_matcher_spec.rb` Then the stdout should contain "2 examples, 0 failures" Scenario: Scoped in an example group Given a file named "scoped_matcher_spec.rb" with: """ruby require 'rspec/expectations' RSpec.describe "group with matcher" do matcher :be_just_like do |expected| match {|actual| actual == expected} end it "has access to the defined matcher" do expect(5).to be_just_like(5) end describe "nested group" do it "has access to the defined matcher" do expect(5).to be_just_like(5) end end end RSpec.describe "group without matcher" do it "does not have access to the defined matcher" do expect do expect(5).to be_just_like(5) end.to raise_exception end end """ When I run `rspec scoped_matcher_spec.rb` Then the output should contain "3 examples, 0 failures" Scenario: Matcher with separate logic for expect().to and expect().not_to Given a file named "matcher_with_separate_should_not_logic_spec.rb" with: """ruby RSpec::Matchers.define :contain do |*expected| match do |actual| expected.all? { |e| actual.include?(e) } end match_when_negated do |actual| expected.none? { |e| actual.include?(e) } end end RSpec.describe [1, 2, 3] do it { is_expected.to contain(1, 2) } it { is_expected.not_to contain(4, 5, 6) } # deliberate failures it { is_expected.to contain(1, 4) } it { is_expected.not_to contain(1, 4) } end """ When I run `rspec matcher_with_separate_should_not_logic_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected [1, 2, 3] to contain 1 and 4 | | expected [1, 2, 3] not to contain 1 and 4 | Scenario: Use define_method to create a helper method with access to matcher params Given a file named "define_method_spec.rb" with: """ruby RSpec::Matchers.define :be_a_multiple_of do |expected| define_method :is_multiple? do |actual| actual % expected == 0 end match { |actual| is_multiple?(actual) } end RSpec.describe 9 do it { is_expected.to be_a_multiple_of(3) } it { is_expected.not_to be_a_multiple_of(4) } # deliberate failures it { is_expected.to be_a_multiple_of(2) } it { is_expected.not_to be_a_multiple_of(3) } end """ When I run `rspec define_method_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected 9 to be a multiple of 2 | | expected 9 not to be a multiple of 3 | Scenario: Include a module with helper methods in the matcher Given a file named "include_module_spec.rb" with: """ruby module MatcherHelpers def is_multiple?(actual, expected) actual % expected == 0 end end RSpec::Matchers.define :be_a_multiple_of do |expected| include MatcherHelpers match { |actual| is_multiple?(actual, expected) } end RSpec.describe 9 do it { is_expected.to be_a_multiple_of(3) } it { is_expected.not_to be_a_multiple_of(4) } # deliberate failures it { is_expected.to be_a_multiple_of(2) } it { is_expected.not_to be_a_multiple_of(3) } end """ When I run `rspec include_module_spec.rb` Then the output should contain all of these: | 4 examples, 2 failures | | expected 9 to be a multiple of 2 | | expected 9 not to be a multiple of 3 | Scenario: Using values_match? to compare values and/or compound matchers. Given a file named "compare_values_spec.rb" with: """ruby RSpec::Matchers.define :have_content do |expected| match do |actual| # The order of arguments is important for `values_match?`, e.g. # especially if your matcher should handle `Regexp`-objects # (`/regex/`): First comes the `expected` value, second the `actual` # one. values_match? expected, actual end end RSpec.describe 'a' do it { is_expected.to have_content 'a' } end RSpec.describe 'a' do it { is_expected.to have_content /a/ } end RSpec.describe 'a' do it { is_expected.to have_content a_string_starting_with('a') } end """ When I run `rspec ./compare_values_spec.rb --format documentation` Then the exit status should be 0 Scenario: Error handling Make sure your matcher returns either `true` or `false`. Take care to handle exceptions appropriately in your matcher, e.g. most cases you might want your matcher to return `false` if an exception - e.g. ArgumentError - occurs, but there might be edge cases where you want to pass the exception to the user. You should handle each `StandardError` with care! Do not handle them all in one. ```ruby match do |actual| begin '[...] Some code' rescue ArgumentError false end end ``` Given a file named "error_handling_spec.rb" with: """ruby class CustomClass; end RSpec::Matchers.define :is_lower_than do |expected| match do |actual| begin actual < expected rescue ArgumentError false end end end RSpec.describe 1 do it { is_expected.to is_lower_than 2 } end RSpec.describe 1 do it { is_expected.not_to is_lower_than 'a' } end RSpec.describe CustomClass do it { expect { is_expected.not_to is_lower_than 2 }.to raise_error NoMethodError } end """ When I run `rspec ./error_handling_spec.rb --format documentation` Then the exit status should be 0 Scenario: Define aliases for your matcher If you want your matcher to be readable in different contexts, you can use the `.alias_matcher`-method to provide an alias for your matcher. Given a file named "alias_spec.rb" with: """ruby RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end end RSpec::Matchers.alias_matcher :be_n_of , :be_a_multiple_of RSpec.describe 9 do it { is_expected.to be_n_of(3) } end """ When I run `rspec ./alias_spec.rb --format documentation` Then the exit status should be 0 Scenario: With expectation errors that bubble up By default the match block will swallow expectation errors (e.g. caused by using an expectation such as `expect(1).to eq 2`), if you wish to allow these to bubble up, pass in the option `:notify_expectation_failures => true`. Given a file named "bubbling_expectation_errors_spec.rb" with: """ruby RSpec::Matchers.define :be_a_palindrome do match(:notify_expectation_failures => true) do |actual| expect(actual).to be_a(String) expect(actual.reverse).to eq(actual) end end RSpec.describe "a custom matcher that bubbles up expectation errors" do it "bubbles expectation errors" do expect("carriage").to be_a_palindrome end end """ When I run `rspec bubbling_expectation_errors_spec.rb` Then the output should contain all of these: | Failures: | | 1) a custom matcher that bubbles up expectation errors bubbles expectation errors | | Failure/Error: expect(actual.reverse).to eq(actual) | | expected: "carriage" | | got: "egairrac" | | (compared using ==) | | # ./bubbling_expectation_errors_spec.rb:4 | | # ./bubbling_expectation_errors_spec.rb:10 | rspec-expectations-3.13.0/features/custom_matchers/define_matcher_outside_rspec.feature000066400000000000000000000017141455770000100317000ustar00rootroot00000000000000Feature: Defining a matcher outside rspec You can define custom matchers when using rspec-expectations outside of rspec-core. Scenario: Define a matcher with default messages Given a file named "test_multiples.rb" with: """ruby require "minitest/autorun" require "rspec/expectations/minitest_integration" RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 end end class TestMultiples < Minitest::Test def test_9_should_be_a_multiple_of_3 expect(9).to be_a_multiple_of(3) end def test_9_should_be_a_multiple_of_4 expect(9).to be_a_multiple_of(4) end end """ When I run `ruby test_multiples.rb` Then the exit status should not be 0 And the output should contain "expected 9 to be a multiple of 4" And the output should contain "2 runs, 2 assertions, 1 failures, 0 errors" rspec-expectations-3.13.0/features/custom_matchers/define_matcher_with_fluent_interface.feature000066400000000000000000000044151455770000100334010ustar00rootroot00000000000000Feature: Defining a matcher with fluent interface Use the `chain` method to define matchers with a fluent interface. Scenario: Chained method with argument Given a file named "between_spec.rb" with: """ruby RSpec::Matchers.define :be_bigger_than do |first| match do |actual| (actual > first) && (actual < @second) end chain :and_smaller_than do |second| @second = second end end RSpec.describe 5 do it { is_expected.to be_bigger_than(4).and_smaller_than(6) } end """ When I run `rspec between_spec.rb --format documentation` Then the output should contain "1 example, 0 failures" And the output should contain "is expected to be bigger than 4" Scenario: Chained setter Given a file named "between_spec.rb" with: """ruby RSpec::Matchers.define :be_bigger_than do |first| match do |actual| (actual > first) && (actual < second) end chain :and_smaller_than, :second end RSpec.describe 5 do it { is_expected.to be_bigger_than(4).and_smaller_than(6) } end """ When I run `rspec between_spec.rb --format documentation` Then the output should contain "1 example, 0 failures" And the output should contain "is expected to be bigger than 4" Scenario: With `include_chain_clauses_in_custom_matcher_descriptions` configured to true, and chained method with argument Given a file named "between_spec.rb" with: """ruby RSpec.configure do |config| config.expect_with :rspec do |c| c.include_chain_clauses_in_custom_matcher_descriptions = true end end RSpec::Matchers.define :be_bigger_than do |first| match do |actual| (actual > first) && (actual < @second) end chain :and_smaller_than do |second| @second = second end end RSpec.describe 5 do it { is_expected.to be_bigger_than(4).and_smaller_than(6) } end """ When I run `rspec between_spec.rb --format documentation` Then the output should contain "1 example, 0 failures" And the output should contain "is expected to be bigger than 4 and smaller than 6" rspec-expectations-3.13.0/features/customized_message.feature000066400000000000000000000025751455770000100245130ustar00rootroot00000000000000Feature: Customized message RSpec tries to provide useful failure messages, but for cases in which you want more specific information, you can define your own message right in the example.This works for any matcher _other than the operator matchers_. Scenario: Customize failure message Given a file named "example_spec.rb" with: """ruby RSpec.describe Array do context "when created with `new`" do it "is empty" do array = Array.new array << 1 # trigger a failure to demonstrate the message expect(array).to be_empty, "expected empty array, got #{array.inspect}" end end end """ When I run `rspec example_spec.rb --format documentation` Then the output should contain "expected empty array, got [1]" Scenario: Customize failure message with a proc Given a file named "example_spec.rb" with: """ruby RSpec.describe Array do context "when created with `new`" do it "is empty" do array = Array.new array << 1 # trigger a failure to demonstrate the message expect(array).to be_empty, lambda { "expected empty array, got #{array.inspect}" } end end end """ When I run `rspec example_spec.rb --format documentation` Then the output should contain "expected empty array, got [1]" rspec-expectations-3.13.0/features/define_negated_matcher.feature000066400000000000000000000026501455770000100252370ustar00rootroot00000000000000Feature: Define negated matcher You can use `RSpec::Matchers.define_negated_matcher` to define a negated version of an existing matcher. This is particularly useful in composed matcher expressions. @skip-when-ripper-unsupported Scenario: Composed negated matcher expression Given a file named "composed_negated_expression_spec.rb" with: """ruby RSpec::Matchers.define_negated_matcher :an_array_excluding, :include RSpec.describe "A negated matcher" do let(:list) { 1.upto(10).to_a } it "can be used in a composed matcher expression" do expect { list.delete(5) }.to change { list }.to(an_array_excluding 5) end it "provides a good failure message based on the name" do # deliberate failure expect { list.delete(1) }.to change { list }.to(an_array_excluding 5) end end """ When I run `rspec composed_negated_expression_spec.rb` Then the output should contain all of these: | 2 examples, 1 failure | | 1) A negated matcher provides a good failure message based on the name | | Failure/Error: expect { list.delete(1) }.to change { list }.to(an_array_excluding 5) | | expected `list` to have changed to an array excluding 5, but is now [2, 3, 4, 5, 6, 7, 8, 9, 10] | rspec-expectations-3.13.0/features/diffing.feature000066400000000000000000000055111455770000100222200ustar00rootroot00000000000000Feature: Diffing When appropriate, failure messages will automatically include a diff. Scenario: Diff for a multiline string Given a file named "example_spec.rb" with: """ruby RSpec.describe "a multiline string" do it "is like another string" do expected = <<-EXPECTED this is the expected string EXPECTED actual = <<-ACTUAL this is the actual string ACTUAL expect(actual).to eq(expected) end end """ When I run `rspec example_spec.rb` Then the output should contain: """ Diff: @@ -1,4 +1,4 @@ this is the - expected + actual string """ @skip-when-diff-lcs-1.3 Scenario: Diff for a multiline string and a regexp on diff-lcs 1.4 Given a file named "example_spec.rb" with: """ruby RSpec.describe "a multiline string" do it "is like another string" do expected = /expected/m actual = <<-ACTUAL this is the actual string ACTUAL expect(actual).to match expected end end """ When I run `rspec example_spec.rb` Then the output should contain: """ Diff: @@ -1,3 +1,5 @@ -/expected/m +this is the + actual + string """ @skip-when-diff-lcs-1.4 Scenario: Diff for a multiline string and a regexp on diff-lcs 1.3 Given a file named "example_spec.rb" with: """ruby RSpec.describe "a multiline string" do it "is like another string" do expected = /expected/m actual = <<-ACTUAL this is the actual string ACTUAL expect(actual).to match expected end end """ When I run `rspec example_spec.rb` Then the output should contain: """ Diff: @@ -1,2 +1,4 @@ -/expected/m +this is the + actual + string """ Scenario: No diff for a single line strings Given a file named "example_spec.rb" with: """ruby RSpec.describe "a single line string" do it "is like another string" do expected = "this string" actual = "that string" expect(actual).to eq(expected) end end """ When I run `rspec example_spec.rb` Then the output should not contain "Diff:" Scenario: No diff for numbers Given a file named "example_spec.rb" with: """ruby RSpec.describe "a number" do it "is like another number" do expect(1).to eq(2) end end """ When I run `rspec example_spec.rb` Then the output should not contain "Diff:" rspec-expectations-3.13.0/features/implicit_docstrings.feature000066400000000000000000000042561455770000100246700ustar00rootroot00000000000000Feature: Implicit docstrings When you use rspec-expectations with rspec-core, RSpec is able to auto-generate the docstrings for examples for you based on the last expectation in the example. This can be handy when the matcher expresses exactly what you would write in your example docstring, but it can also be easily abused. We find that the freeform nature of the docstring provides a lot of value when used well (e.g. to document the "why" of a particular behavior), and you lose that kind of flexibility when you rely on the matcher to generate the docstring for you. In general, we recommend only using this feature when the matcher aligns _exactly_ with the docstring you would write. Even then, many users prefer the explicitness of the full docstring, so use this feature with care (if at all). Scenario: Run passing examples Given a file named "implicit_docstrings_spec.rb" with: """ruby RSpec.describe "Examples with no docstrings generate their own:" do specify { expect(3).to be < 5 } specify { expect([1,2,3]).to include(2) } specify { expect([1,2,3]).to respond_to(:size) } end """ When I run `rspec ./implicit_docstrings_spec.rb -fdoc` Then the output should contain "is expected to be < 5" And the output should contain "is expected to include 2" And the output should contain "is expected to respond to #size" Scenario: Run failing examples Given a file named "failing_implicit_docstrings_spec.rb" with: """ruby RSpec.describe "Failing examples with no descriptions" do # description is auto-generated per the last executed expectation specify do expect(3).to equal(2) expect(5).to equal(5) end specify { expect(3).to be > 5 } specify { expect([1,2,3]).to include(4) } specify { expect([1,2,3]).not_to respond_to(:size) } end """ When I run `rspec ./failing_implicit_docstrings_spec.rb -fdoc` Then the output should contain "is expected to equal 2" And the output should contain "is expected to be > 5" And the output should contain "is expected to include 4" And the output should contain "is expected not to respond to #size" rspec-expectations-3.13.0/features/step_definitions/000077500000000000000000000000001455770000100226015ustar00rootroot00000000000000rspec-expectations-3.13.0/features/step_definitions/additional_cli_steps.rb000066400000000000000000000016211455770000100273030ustar00rootroot00000000000000# Useful for when the output is slightly different on different versions of ruby Then /^the output should contain "([^"]*)" or "([^"]*)"$/ do |string1, string2| unless [string1, string2].any? { |s| all_output.include?(s) } fail %(Neither "#{string1}" or "#{string2}" were found in:\n#{all_output}) end end Then /^the output should contain all of these:$/ do |table| table.raw.flatten.each do |string| if RUBY_VERSION == '1.8.7' && string =~ /\{.+=>.+\}/ warn "Skipping checking #{string} on 1.8.7 because hash ordering is not consistent" else expect(all_output).to include_output_string string end end end Then /^the example(?:s)? should(?: all)? pass$/ do step 'the output should contain "0 failures"' step 'the exit status should be 0' end Then /^the example should fail$/ do step 'the output should contain "1 failure"' step 'the exit status should not be 0' end rspec-expectations-3.13.0/features/support/000077500000000000000000000000001455770000100207475ustar00rootroot00000000000000rspec-expectations-3.13.0/features/support/diff_lcs_versions.rb000066400000000000000000000012431455770000100247750ustar00rootroot00000000000000require 'diff-lcs' Around "@skip-when-diff-lcs-1.4" do |scenario, block| if Diff::LCS::VERSION >= '1.4' skip_this_scenario "Skipping scenario #{scenario.name} on `diff-lcs` v#{Diff::LCS::VERSION}" else block.call end end Around "@skip-when-diff-lcs-1.4.3" do |scenario, block| if Diff::LCS::VERSION =~ /1\.4\.3/ skip_this_scenario "Skipping scenario #{scenario.name} on `diff-lcs` v#{Diff::LCS::VERSION}" else block.call end end Around "@skip-when-diff-lcs-1.3" do |scenario, block| if Diff::LCS::VERSION < '1.4' skip_this_scenario "Skipping scenario #{scenario.name} on `diff-lcs` v#{Diff::LCS::VERSION}" else block.call end end rspec-expectations-3.13.0/features/support/disallow_certain_apis.rb000066400000000000000000000016101455770000100256310ustar00rootroot00000000000000# This file is designed to prevent the use of certain APIs that # we don't want used from our cukes, since they function as documentation. if defined?(Cucumber) require 'shellwords' tag = !defined?(::RUBY_ENGINE_VERSION) || (::RUBY_ENGINE_VERSION < '2.0.0') ? '~@allow-disallowed-api': 'not @allow-disallowed-api' Before(tag) do set_environment_variable('SPEC_OPTS', "-r#{Shellwords.escape(__FILE__)}") end else module DisallowOneLinerShould def should(*) raise "one-liner should is not allowed" end def should_not(*) raise "one-liner should_not is not allowed" end end RSpec.configure do |rspec| rspec.expose_dsl_globally = false rspec.mock_with :rspec do |mocks| mocks.syntax = :expect end rspec.expect_with :rspec do |expectations| expectations.syntax = :expect end rspec.include DisallowOneLinerShould end end rspec-expectations-3.13.0/features/support/env.rb000066400000000000000000000010111455770000100220550ustar00rootroot00000000000000require 'aruba/cucumber' Aruba.configure do |config| if RUBY_PLATFORM =~ /java/ || defined?(Rubinius) config.exit_timeout = 60 else config.exit_timeout = 10 end end Before do if RUBY_PLATFORM == 'java' # disable JIT since these processes are so short lived set_environment_variable('JRUBY_OPTS', "-X-C #{ENV['JRUBY_OPTS']}") end if defined?(Rubinius) # disable JIT since these processes are so short lived set_environment_variable('RBXOPT', "-Xint=true #{ENV['RBXOPT']}") end end rspec-expectations-3.13.0/features/support/rubinius.rb000066400000000000000000000003421455770000100231330ustar00rootroot00000000000000# Required until https://github.com/rubinius/rubinius/issues/2430 is resolved ENV['RBXOPT'] = "#{ENV["RBXOPT"]} -Xcompiler.no_rbc" Around "@unsupported-on-rbx" do |_scenario, block| block.call unless defined?(Rubinius) end rspec-expectations-3.13.0/features/support/ruby_features.rb000066400000000000000000000022771455770000100241630ustar00rootroot00000000000000Around "@skip-when-splat-args-unsupported" do |scenario, block| require 'rspec/support/ruby_features' if ::RSpec::Support::RubyFeatures.optional_and_splat_args_supported? block.call else skip_this_scenario "Skipping scenario #{scenario.name} because splat arguments are not supported" end end Around "@skip-when-keyword-args-unsupported" do |scenario, block| require 'rspec/support/ruby_features' if ::RSpec::Support::RubyFeatures.kw_args_supported? block.call else skip_this_scenario "Skipping scenario #{scenario.name} because keyword arguments are not supported" end end Around "@skip-when-required-keyword-args-unsupported" do |scenario, block| require 'rspec/support/ruby_features' if ::RSpec::Support::RubyFeatures.required_kw_args_supported? block.call else skip_this_scenario "Skipping scenario #{scenario.name} because required keyword arguments are not supported" end end Around "@skip-when-ripper-unsupported" do |scenario, block| require 'rspec/support/ruby_features' if ::RSpec::Support::RubyFeatures.ripper_supported? block.call else skip_this_scenario "Skipping scenario #{scenario.name} because Ripper is not supported" end end rspec-expectations-3.13.0/features/syntax_configuration.feature000066400000000000000000000064761455770000100251020ustar00rootroot00000000000000@allow-disallowed-api Feature: Syntax Configuration The primary syntax provided by rspec-expectations is based on the `expect` method, which explicitly wraps an object or block of code in order to set an expectation on it. There's also an older `should`-based syntax, which relies upon `should` being monkey-patched onto every object in the system. However, this syntax can at times lead to some surprising failures, since RSpec does not own every object in the system and cannot guarantee that it will always work consistently. We recommend you use the `expect` syntax unless you have a specific reason you prefer the `should` syntax. We have no plans to ever completely remove the `should` syntax but starting in RSpec 3, a deprecation warning will be issued if you do not explicitly enable it, with the plan to disable it by default in RSpec 4 (and potentially move it into an external gem). If you have an old `should`-based project that you would like to upgrade to the `expect`, check out [transpec](http://yujinakayama.me/transpec/), which can perform the conversion automatically for you. Background: Given a file named "spec/syntaxes_spec.rb" with: """ruby require 'spec_helper' RSpec.describe "using the should syntax" do specify { 3.should eq(3) } specify { 3.should_not eq(4) } specify { lambda { raise "boom" }.should raise_error("boom") } specify { lambda { }.should_not raise_error } end RSpec.describe "using the expect syntax" do specify { expect(3).to eq(3) } specify { expect(3).not_to eq(4) } specify { expect { raise "boom" }.to raise_error("boom") } specify { expect { }.not_to raise_error } end """ Scenario: Both syntaxes are available by default Given a file named "spec/spec_helper.rb" with: """ruby """ When I run `rspec` Then the examples should all pass And the output should contain "Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated" Scenario: Disable should syntax Given a file named "spec/spec_helper.rb" with: """ruby RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.syntax = :expect end end """ When I run `rspec` Then the output should contain all of these: | 8 examples, 4 failures | | undefined method `should' | Scenario: Disable expect syntax Given a file named "spec/spec_helper.rb" with: """ruby RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.syntax = :should end config.mock_with :rspec do |mocks| mocks.syntax = :should end end """ When I run `rspec` Then the output should contain all of these: | 8 examples, 4 failures | | undefined method `expect' | Scenario: Explicitly enable both syntaxes Given a file named "spec/spec_helper.rb" with: """ruby RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.syntax = [:should, :expect] end end """ When I run `rspec` Then the examples should all pass And the output should not contain "deprecated" rspec-expectations-3.13.0/features/test_frameworks/000077500000000000000000000000001455770000100224525ustar00rootroot00000000000000rspec-expectations-3.13.0/features/test_frameworks/minitest.feature000066400000000000000000000072701455770000100256710ustar00rootroot00000000000000Feature: Minitest integration rspec-expectations is a stand-alone gem that can be used without the rest of RSpec. If you like minitest as your test runner, but prefer RSpec's approach to expressing expectations, you can have both. To integrate rspec-expectations with minitest, require `rspec/expectations/minitest_integration`. Scenario: Use rspec/expectations with minitest Given a file named "rspec_expectations_test.rb" with: """ruby require 'minitest/autorun' require 'rspec/expectations/minitest_integration' class RSpecExpectationsTest < Minitest::Test RSpec::Matchers.define :be_an_integer do match { |actual| Integer === actual } end def be_an_int # This is actually an internal rspec-expectations API, but is used # here to demonstrate that deprecation warnings from within # rspec-expectations work correctly without depending on rspec-core RSpec.deprecate(:be_an_int, :replacement => :be_an_integer) be_an_integer end def test_passing_expectation expect(1 + 3).to eq 4 end def test_failing_expectation expect([1, 2]).to be_empty end def test_custom_matcher_with_deprecation_warning expect(1).to be_an_int end def test_using_aggregate_failures aggregate_failures do expect(1).to be_even expect(2).to be_odd end end end """ When I run `ruby rspec_expectations_test.rb` Then the output should contain "4 runs, 5 assertions, 2 failures, 0 errors" And the output should contain "expected `[1, 2].empty?` to be truthy, got false" And the output should contain "be_an_int is deprecated" And the output should contain "Got 2 failures from failure aggregation block" Scenario: Use rspec/expectations with minitest/spec Given a file named "rspec_expectations_spec.rb" with: """ruby require 'minitest/autorun' require 'minitest/spec' require 'rspec/expectations/minitest_integration' describe "Using RSpec::Expectations with Minitest::Spec" do RSpec::Matchers.define :be_an_integer do match { |actual| Integer === actual } end it 'passes an expectation' do expect(1 + 3).to eq 4 end it 'fails an expectation' do expect([1, 2]).to be_empty end it 'passes a block expectation' do expect { 1 / 0 }.to raise_error(ZeroDivisionError) end it 'fails a block expectation' do expect { 1 / 1 }.to raise_error(ZeroDivisionError) end it 'passes a negative expectation (using `not_to`)' do expect(1).not_to eq 2 end it 'fails a negative expectation (using `to_not`)' do expect(1).to_not eq 1 end it 'fails multiple expectations' do aggregate_failures do expect(1).to be_even expect(2).to be_odd end end it 'passes a minitest expectation' do expect(1 + 3).must_equal 4 end it 'fails a minitest expectation' do expect([1, 2]).must_be :empty? end end """ When I run `ruby rspec_expectations_spec.rb` Then the output should contain "9 runs, 10 assertions, 5 failures, 0 errors" And the output should contain "expected `[1, 2].empty?` to be truthy, got false" And the output should contain "expected ZeroDivisionError but nothing was raised" And the output should contain "Got 2 failures from failure aggregation block" And the output should contain "Expected [1, 2] to be empty?" rspec-expectations-3.13.0/lib/000077500000000000000000000000001455770000100161635ustar00rootroot00000000000000rspec-expectations-3.13.0/lib/rspec/000077500000000000000000000000001455770000100172775ustar00rootroot00000000000000rspec-expectations-3.13.0/lib/rspec/expectations.rb000066400000000000000000000063011455770000100223320ustar00rootroot00000000000000require 'rspec/support' RSpec::Support.require_rspec_support "caller_filter" RSpec::Support.require_rspec_support "warnings" RSpec::Support.require_rspec_support "object_formatter" require 'rspec/matchers' RSpec::Support.define_optimized_require_for_rspec(:expectations) { |f| require_relative(f) } %w[ expectation_target configuration fail_with handler version ].each { |file| RSpec::Support.require_rspec_expectations(file) } module RSpec # RSpec::Expectations provides a simple, readable API to express # the expected outcomes in a code example. To express an expected # outcome, wrap an object or block in `expect`, call `to` or `to_not` # (aliased as `not_to`) and pass it a matcher object: # # expect(order.total).to eq(Money.new(5.55, :USD)) # expect(list).to include(user) # expect(message).not_to match(/foo/) # expect { do_something }.to raise_error # # The last form (the block form) is needed to match against ruby constructs # that are not objects, but can only be observed when executing a block # of code. This includes raising errors, throwing symbols, yielding, # and changing values. # # When `expect(...).to` is invoked with a matcher, it turns around # and calls `matcher.matches?()`. For example, # in the expression: # # expect(order.total).to eq(Money.new(5.55, :USD)) # # ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results # in the equivalent of `eq.matches?(order.total)`. If `matches?` returns # `true`, the expectation is met and execution continues. If `false`, then # the spec fails with the message returned by `eq.failure_message`. # # Given the expression: # # expect(order.entries).not_to include(entry) # # ...the `not_to` method (also available as `to_not`) invokes the equivalent of # `include.matches?(order.entries)`, but it interprets `false` as success, and # `true` as a failure, using the message generated by # `include.failure_message_when_negated`. # # rspec-expectations ships with a standard set of useful matchers, and writing # your own matchers is quite simple. # # See [RSpec::Matchers](../RSpec/Matchers) for more information about the # built-in matchers that ship with rspec-expectations, and how to write your # own custom matchers. module Expectations # Exception raised when an expectation fails. # # @note We subclass Exception so that in a stub implementation if # the user sets an expectation, it can't be caught in their # code by a bare `rescue`. # @api public class ExpectationNotMetError < Exception end # Exception raised from `aggregate_failures` when multiple expectations fail. # # @note The constant is defined here but the extensive logic of this class # is lazily defined when `FailureAggregator` is autoloaded, since we do # not need to waste time defining that functionality unless # `aggregate_failures` is used. class MultipleExpectationsNotMetError < ExpectationNotMetError end autoload :BlockSnippetExtractor, "rspec/expectations/block_snippet_extractor" autoload :FailureAggregator, "rspec/expectations/failure_aggregator" end end rspec-expectations-3.13.0/lib/rspec/expectations/000077500000000000000000000000001455770000100220055ustar00rootroot00000000000000rspec-expectations-3.13.0/lib/rspec/expectations/block_snippet_extractor.rb000066400000000000000000000162471455770000100272730ustar00rootroot00000000000000module RSpec module Expectations # @private class BlockSnippetExtractor # rubocop:disable Metrics/ClassLength # rubocop should properly handle `Struct.new {}` as an inner class definition. attr_reader :proc, :method_name def self.try_extracting_single_line_body_of(proc, method_name) lines = new(proc, method_name).body_content_lines return nil unless lines.count == 1 lines.first rescue Error nil end def initialize(proc, method_name) @proc = proc @method_name = method_name.to_s.freeze end # Ideally we should properly handle indentations of multiline snippet, # but it's not implemented yet since because we use result of this method only when it's a # single line and implementing the logic introduces additional complexity. def body_content_lines raw_body_lines.map(&:strip).reject(&:empty?) end private def raw_body_lines raw_body_snippet.split("\n") end def raw_body_snippet block_token_extractor.body_tokens.map(&:string).join end def block_token_extractor @block_token_extractor ||= BlockTokenExtractor.new(method_name, source, beginning_line_number) end if RSpec.respond_to?(:world) def source raise TargetNotFoundError unless File.exist?(file_path) RSpec.world.source_from_file(file_path) end else RSpec::Support.require_rspec_support 'source' def source raise TargetNotFoundError unless File.exist?(file_path) @source ||= RSpec::Support::Source.from_file(file_path) end end def file_path source_location.first end def beginning_line_number source_location.last end def source_location proc.source_location || raise(TargetNotFoundError) end Error = Class.new(StandardError) TargetNotFoundError = Class.new(Error) AmbiguousTargetError = Class.new(Error) # @private # Performs extraction of block body snippet using tokens, # which cannot be done with node information. BlockTokenExtractor = Struct.new(:method_name, :source, :beginning_line_number) do attr_reader :state, :body_tokens def initialize(*) super parse! end private def parse! @state = :initial catch(:finish) do source.tokens.each do |token| invoke_state_handler(token) end end end def finish! throw :finish end def invoke_state_handler(token) __send__("#{state}_state", token) end def initial_state(token) @state = :after_method_call if token.location == block_locator.method_call_location end def after_method_call_state(token) @state = :after_opener if handle_opener_token(token) end def after_opener_state(token) if handle_closer_token(token) finish_or_find_next_block_if_incorrect! elsif pipe_token?(token) finalize_pending_tokens! @state = :after_beginning_of_args else pending_tokens << token handle_opener_token(token) @state = :after_beginning_of_body unless token.type == :on_sp end end def after_beginning_of_args_state(token) @state = :after_beginning_of_body if pipe_token?(token) end def after_beginning_of_body_state(token) if handle_closer_token(token) finish_or_find_next_block_if_incorrect! else pending_tokens << token handle_opener_token(token) end end def pending_tokens @pending_tokens ||= [] end def finalize_pending_tokens! pending_tokens.freeze.tap do @pending_tokens = nil end end def finish_or_find_next_block_if_incorrect! body_tokens = finalize_pending_tokens! if correct_block?(body_tokens) @body_tokens = body_tokens finish! else @state = :after_method_call end end def handle_opener_token(token) opener_token?(token).tap do |boolean| opener_token_stack.push(token) if boolean end end def opener_token?(token) token.type == :on_lbrace || (token.type == :on_kw && token.string == 'do') end def handle_closer_token(token) if opener_token_stack.last.closed_by?(token) opener_token_stack.pop opener_token_stack.empty? else false end end def opener_token_stack @opener_token_stack ||= [] end def pipe_token?(token) token.type == :on_op && token.string == '|' end def correct_block?(body_tokens) return true if block_locator.body_content_locations.empty? content_location = block_locator.body_content_locations.first content_location.between?(body_tokens.first.location, body_tokens.last.location) end def block_locator @block_locator ||= BlockLocator.new(method_name, source, beginning_line_number) end end # @private # Locates target block with node information (semantics), which tokens don't have. BlockLocator = Struct.new(:method_name, :source, :beginning_line_number) do def method_call_location @method_call_location ||= method_ident_node.location end def body_content_locations @body_content_locations ||= block_body_node.map(&:location).compact end private def method_ident_node method_call_node = block_wrapper_node.children.first method_call_node.find do |node| method_ident_node?(node) end end def block_body_node block_node = block_wrapper_node.children[1] block_node.children.last end def block_wrapper_node case candidate_block_wrapper_nodes.size when 1 candidate_block_wrapper_nodes.first when 0 raise TargetNotFoundError else raise AmbiguousTargetError end end def candidate_block_wrapper_nodes @candidate_block_wrapper_nodes ||= candidate_method_ident_nodes.map do |method_ident_node| block_wrapper_node = method_ident_node.each_ancestor.find { |node| node.type == :method_add_block } next nil unless block_wrapper_node method_call_node = block_wrapper_node.children.first method_call_node.include?(method_ident_node) ? block_wrapper_node : nil end.compact end def candidate_method_ident_nodes source.nodes_by_line_number[beginning_line_number].select do |node| method_ident_node?(node) end end def method_ident_node?(node) node.type == :@ident && node.args.first == method_name end end end end end rspec-expectations-3.13.0/lib/rspec/expectations/configuration.rb000066400000000000000000000200621455770000100252010ustar00rootroot00000000000000RSpec::Support.require_rspec_expectations "syntax" module RSpec module Expectations # Provides configuration options for rspec-expectations. # If you are using rspec-core, you can access this via a # block passed to `RSpec::Core::Configuration#expect_with`. # Otherwise, you can access it via RSpec::Expectations.configuration. # # @example # RSpec.configure do |rspec| # rspec.expect_with :rspec do |c| # # c is the config object # end # end # # # or # # RSpec::Expectations.configuration class Configuration # @private FALSE_POSITIVE_BEHAVIOURS = { :warn => lambda { |message| RSpec.warning message }, :raise => lambda { |message| raise ArgumentError, message }, :nothing => lambda { |_| true }, } def initialize @on_potential_false_positives = :warn @strict_predicate_matchers = false end # Configures the supported syntax. # @param [Array, Symbol] values the syntaxes to enable # @example # RSpec.configure do |rspec| # rspec.expect_with :rspec do |c| # c.syntax = :should # # or # c.syntax = :expect # # or # c.syntax = [:should, :expect] # end # end def syntax=(values) if Array(values).include?(:expect) Expectations::Syntax.enable_expect else Expectations::Syntax.disable_expect end if Array(values).include?(:should) Expectations::Syntax.enable_should else Expectations::Syntax.disable_should end end # Configures the maximum character length that RSpec will print while # formatting an object. You can set length to nil to prevent RSpec from # doing truncation. # @param [Fixnum] length the number of characters to limit the formatted output to. # @example # RSpec.configure do |rspec| # rspec.expect_with :rspec do |c| # c.max_formatted_output_length = 200 # end # end def max_formatted_output_length=(length) RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = length end # The list of configured syntaxes. # @return [Array] the list of configured syntaxes. # @example # unless RSpec::Matchers.configuration.syntax.include?(:expect) # raise "this RSpec extension gem requires the rspec-expectations `:expect` syntax" # end def syntax syntaxes = [] syntaxes << :should if Expectations::Syntax.should_enabled? syntaxes << :expect if Expectations::Syntax.expect_enabled? syntaxes end if ::RSpec.respond_to?(:configuration) def color? ::RSpec.configuration.color_enabled? end else # Indicates whether or not diffs should be colored. # Delegates to rspec-core's color option if rspec-core # is loaded; otherwise you can set it here. attr_writer :color # Indicates whether or not diffs should be colored. # Delegates to rspec-core's color option if rspec-core # is loaded; otherwise you can set it here. def color? defined?(@color) && @color end end # Adds `should` and `should_not` to the given classes # or modules. This can be used to ensure `should` works # properly on things like proxy objects (particular # `Delegator`-subclassed objects on 1.8). # # @param [Array] modules the list of classes or modules # to add `should` and `should_not` to. def add_should_and_should_not_to(*modules) modules.each do |mod| Expectations::Syntax.enable_should(mod) end end # Sets or gets the backtrace formatter. The backtrace formatter should # implement `#format_backtrace(Array)`. This is used # to format backtraces of errors handled by the `raise_error` # matcher. # # If you are using rspec-core, rspec-core's backtrace formatting # will be used (including respecting the presence or absence of # the `--backtrace` option). # # @!attribute [rw] backtrace_formatter attr_writer :backtrace_formatter def backtrace_formatter @backtrace_formatter ||= if defined?(::RSpec.configuration.backtrace_formatter) ::RSpec.configuration.backtrace_formatter else NullBacktraceFormatter end end # Sets if custom matcher descriptions and failure messages # should include clauses from methods defined using `chain`. # @param value [Boolean] attr_writer :include_chain_clauses_in_custom_matcher_descriptions # Indicates whether or not custom matcher descriptions and failure messages # should include clauses from methods defined using `chain`. It is # false by default for backwards compatibility. def include_chain_clauses_in_custom_matcher_descriptions? @include_chain_clauses_in_custom_matcher_descriptions ||= false end # @private def reset_syntaxes_to_default self.syntax = [:should, :expect] RSpec::Expectations::Syntax.warn_about_should! end # @api private # Null implementation of a backtrace formatter used by default # when rspec-core is not loaded. Does no filtering. NullBacktraceFormatter = Module.new do def self.format_backtrace(backtrace) backtrace end end # Configures whether RSpec will warn about matcher use which will # potentially cause false positives in tests. # # @param [Boolean] boolean def warn_about_potential_false_positives=(boolean) if boolean self.on_potential_false_positives = :warn elsif warn_about_potential_false_positives? self.on_potential_false_positives = :nothing else # no-op, handler is something else end end # # Configures what RSpec will do about matcher use which will # potentially cause false positives in tests. # # @param [Symbol] behavior can be set to :warn, :raise or :nothing def on_potential_false_positives=(behavior) unless FALSE_POSITIVE_BEHAVIOURS.key?(behavior) raise ArgumentError, "Supported values are: #{FALSE_POSITIVE_BEHAVIOURS.keys}" end @on_potential_false_positives = behavior end # Configures RSpec to check predicate matchers to `be(true)` / `be(false)` (strict), # or `be_truthy` / `be_falsey` (not strict). # Historically, the default was `false`, but `true` is recommended. def strict_predicate_matchers=(flag) raise ArgumentError, "Pass `true` or `false`" unless flag == true || flag == false @strict_predicate_matchers = flag end attr_reader :strict_predicate_matchers def strict_predicate_matchers? @strict_predicate_matchers end # Indicates what RSpec will do about matcher use which will # potentially cause false positives in tests, generally you want to # avoid such scenarios so this defaults to `true`. attr_reader :on_potential_false_positives # Indicates whether RSpec will warn about matcher use which will # potentially cause false positives in tests, generally you want to # avoid such scenarios so this defaults to `true`. def warn_about_potential_false_positives? on_potential_false_positives == :warn end # @private def false_positives_handler FALSE_POSITIVE_BEHAVIOURS.fetch(@on_potential_false_positives) end end # The configuration object. # @return [RSpec::Expectations::Configuration] the configuration object def self.configuration @configuration ||= Configuration.new end # set default syntax configuration.reset_syntaxes_to_default end end rspec-expectations-3.13.0/lib/rspec/expectations/expectation_target.rb000066400000000000000000000136061455770000100262310ustar00rootroot00000000000000module RSpec module Expectations # Wraps the target of an expectation. # # @example # expect(something) # => ExpectationTarget wrapping something # expect { do_something } # => ExpectationTarget wrapping the block # # # used with `to` # expect(actual).to eq(3) # # # with `not_to` # expect(actual).not_to eq(3) # # @note `ExpectationTarget` is not intended to be instantiated # directly by users. Use `expect` instead. class ExpectationTarget # @private # Used as a sentinel value to be able to tell when the user # did not pass an argument. We can't use `nil` for that because # `nil` is a valid value to pass. UndefinedValue = Module.new # @note this name aligns with `Minitest::Expectation` so that our # {InstanceMethods} module can be included in that class when # used in a Minitest context. # @return [Object] the target of the expectation attr_reader :target # @api private def initialize(value) @target = value end # @private def self.for(value, block) if UndefinedValue.equal?(value) unless block raise ArgumentError, "You must pass either an argument or a block to `expect`." end BlockExpectationTarget.new(block) elsif block raise ArgumentError, "You cannot pass both an argument and a block to `expect`." else ValueExpectationTarget.new(value) end end # Defines instance {ExpectationTarget} instance methods. These are defined # in a module so we can include it in `Minitest::Expectation` when # `rspec/expectations/minitest_integration` is loaded in order to # support usage with Minitest. module InstanceMethods # Runs the given expectation, passing if `matcher` returns true. # @example # expect(value).to eq(5) # expect { perform }.to raise_error # @param [Matcher] # matcher # @param [String, Proc] message optional message to display when the expectation fails # @return [Boolean] true if the expectation succeeds (else raises) # @see RSpec::Matchers def to(matcher=nil, message=nil, &block) prevent_operator_matchers(:to) unless matcher RSpec::Expectations::PositiveExpectationHandler.handle_matcher(target, matcher, message, &block) end # Runs the given expectation, passing if `matcher` returns false. # @example # expect(value).not_to eq(5) # @param [Matcher] # matcher # @param [String, Proc] message optional message to display when the expectation fails # @return [Boolean] false if the negative expectation succeeds (else raises) # @see RSpec::Matchers def not_to(matcher=nil, message=nil, &block) prevent_operator_matchers(:not_to) unless matcher RSpec::Expectations::NegativeExpectationHandler.handle_matcher(target, matcher, message, &block) end alias to_not not_to private def prevent_operator_matchers(verb) raise ArgumentError, "The expect syntax does not support operator matchers, " \ "so you must pass a matcher to `##{verb}`." end end include InstanceMethods end # @private # Validates the provided matcher to ensure it supports block # expectations, in order to avoid user confusion when they # use a block thinking the expectation will be on the return # value of the block rather than the block itself. class ValueExpectationTarget < ExpectationTarget def to(matcher=nil, message=nil, &block) enforce_value_expectation(matcher) super end def not_to(matcher=nil, message=nil, &block) enforce_value_expectation(matcher) super end private def enforce_value_expectation(matcher) return if supports_value_expectations?(matcher) RSpec.deprecate( "expect(value).to #{RSpec::Support::ObjectFormatter.format(matcher)}", :message => "The implicit block expectation syntax is deprecated, you should pass " \ "a block rather than an argument to `expect` to use the provided " \ "block expectation matcher or the matcher must implement " \ "`supports_value_expectations?`. e.g `expect { value }.to " \ "#{RSpec::Support::ObjectFormatter.format(matcher)}` not " \ "`expect(value).to #{RSpec::Support::ObjectFormatter.format(matcher)}`" ) end def supports_value_expectations?(matcher) !matcher.respond_to?(:supports_value_expectations?) || matcher.supports_value_expectations? end end # @private # Validates the provided matcher to ensure it supports block # expectations, in order to avoid user confusion when they # use a block thinking the expectation will be on the return # value of the block rather than the block itself. class BlockExpectationTarget < ExpectationTarget def to(matcher, message=nil, &block) enforce_block_expectation(matcher) super end def not_to(matcher, message=nil, &block) enforce_block_expectation(matcher) super end alias to_not not_to private def enforce_block_expectation(matcher) return if supports_block_expectations?(matcher) raise ExpectationNotMetError, "You must pass an argument rather than a block to `expect` to use the provided " \ "matcher (#{RSpec::Support::ObjectFormatter.format(matcher)}), or the matcher must implement " \ "`supports_block_expectations?`." end def supports_block_expectations?(matcher) matcher.respond_to?(:supports_block_expectations?) && matcher.supports_block_expectations? end end end end rspec-expectations-3.13.0/lib/rspec/expectations/fail_with.rb000066400000000000000000000023361455770000100243040ustar00rootroot00000000000000module RSpec module Expectations class << self # @private class Differ # @private OBJECT_PREPARER = lambda do |object| RSpec::Matchers::Composable.surface_descriptions_in(object) end end # @private def differ RSpec::Support::Differ.new( :object_preparer => Differ::OBJECT_PREPARER, :color => RSpec::Matchers.configuration.color? ) end # Raises an RSpec::Expectations::ExpectationNotMetError with message. # @param [String] message # @param [Object] expected # @param [Object] actual # # Adds a diff to the failure message when `expected` and `actual` are # both present. def fail_with(message, expected=nil, actual=nil) unless message raise ArgumentError, "Failure message is nil. Does your matcher define the " \ "appropriate failure_message[_when_negated] method to return a string?" end message = ::RSpec::Matchers::MultiMatcherDiff.from(expected, actual).message_with_diff(message, differ) RSpec::Support.notify_failure(RSpec::Expectations::ExpectationNotMetError.new message) end end end end rspec-expectations-3.13.0/lib/rspec/expectations/failure_aggregator.rb000066400000000000000000000177621455770000100262000ustar00rootroot00000000000000module RSpec module Expectations # @private class FailureAggregator attr_reader :block_label, :metadata # @private class AggregatedFailure # @private MESSAGE = 'AggregatedFailure: This method caused a failure which has been ' \ 'suppressed to be aggregated into our failure report by returning ' \ 'this value, further errors can be ignored.' def inspect MESSAGE end end AGGREGATED_FAILURE = AggregatedFailure.new def aggregate RSpec::Support.with_failure_notifier(self) do begin yield rescue ExpectationNotMetError => e # Normally, expectation failures will be notified via the `call` method, below, # but since the failure notifier uses a thread local variable, failing expectations # in another thread will still raise. We handle that here and categorize it as part # of `failures` rather than letting it fall through and be categorized as part of # `other_errors`. failures << e rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e # While it is normally a bad practice to rescue `Exception`, it's important we do # so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception, # or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's # essential that the user is notified of expectation failures that may have already # occurred in the `aggregate_failures` block. Those expectation failures may provide # important diagnostics for understanding why this exception occurred, and if we simply # allowed this exception to be raised as-is, it would (wrongly) suggest to the user # that the expectation passed when it did not, which would be quite confusing. other_errors << e end end notify_aggregated_failures end def failures @failures ||= [] end def other_errors @other_errors ||= [] end # This method is defined to satisfy the callable interface # expected by `RSpec::Support.with_failure_notifier`. def call(failure, options) source_id = options[:source_id] return if source_id && @seen_source_ids.key?(source_id) @seen_source_ids[source_id] = true assign_backtrace(failure) unless failure.backtrace failures << failure AGGREGATED_FAILURE end private if RSpec::Support::Ruby.jruby? && RSpec::Support::Ruby.jruby_version < '9.2.0.0' # On JRuby 9.1.x.x and before, `caller` and `raise` produce different backtraces with # regards to `.java` stack frames. It's important that we use `raise` for JRuby to produce # a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`, # so that rspec-core's truncation logic can work properly on it to list the backtrace # relative to the `aggregate_failures` block. def assign_backtrace(failure) raise failure rescue failure.class => e failure.set_backtrace(e.backtrace) end else # Using `caller` performs better (and is simpler) than `raise` on most Rubies. def assign_backtrace(failure) failure.set_backtrace(caller) end end def initialize(block_label, metadata) @block_label = block_label @metadata = metadata @seen_source_ids = {} # don't want to load stdlib set end def notify_aggregated_failures all_errors = failures + other_errors case all_errors.size when 0 then return true when 1 then RSpec::Support.notify_failure all_errors.first else RSpec::Support.notify_failure MultipleExpectationsNotMetError.new(self) end end end # Exception raised from `aggregate_failures` when multiple expectations fail. class MultipleExpectationsNotMetError # @return [String] The fully formatted exception message. def message @message ||= (["#{summary}:"] + enumerated_failures + enumerated_errors).join("\n\n") end # @return [Array] The list of expectation failures. def failures @failure_aggregator.failures end # @return [Array] The list of other exceptions. def other_errors @failure_aggregator.other_errors end # @return [Array] The list of expectation failures and other exceptions, combined. attr_reader :all_exceptions # @return [String] The user-assigned label for the aggregation block. def aggregation_block_label @failure_aggregator.block_label end # @return [Hash] The metadata hash passed to `aggregate_failures`. def aggregation_metadata @failure_aggregator.metadata end # @return [String] A summary of the failure, including the block label and a count of failures. def summary "Got #{exception_count_description} from failure aggregation " \ "block#{block_description}" end # return [String] A description of the failure/error counts. def exception_count_description failure_count = pluralize("failure", failures.size) return failure_count if other_errors.empty? error_count = pluralize("other error", other_errors.size) "#{failure_count} and #{error_count}" end private def initialize(failure_aggregator) @failure_aggregator = failure_aggregator @all_exceptions = failures + other_errors end def block_description return "" unless aggregation_block_label " #{aggregation_block_label.inspect}" end def pluralize(noun, count) "#{count} #{noun}#{'s' unless count == 1}" end def enumerated(exceptions, index_offset) exceptions.each_with_index.map do |exception, index| index += index_offset formatted_message = "#{yield exception}\n#{format_backtrace(exception.backtrace).first}" "#{index_label index}#{indented formatted_message, index}" end end def exclusion_patterns patterns = %w[/lib\d*/ruby/ bin/ exe/rspec /lib/bundler/ /exe/bundle:] patterns << "org/jruby/" if RSpec::Support::Ruby.jruby? patterns.map! { |s| Regexp.new(s.gsub('/', File::SEPARATOR)) } end def format_backtrace(backtrace) backtrace.map { |l| backtrace_line(l) }.compact.tap { |filtered| filtered.concat backtrace if filtered.empty? } end def backtrace_line(line) return if [Regexp.union(RSpec::CallerFilter::IGNORE_REGEX, *exclusion_patterns)].any? { |p| line =~ p } # It changes the current path that is relative to # system root to be relative to the project root. line.sub(/(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/, '\\1.\\2'.freeze).sub(/\A([^:]+:\d+)$/, '\\1'.freeze) end def enumerated_failures enumerated(failures, 0, &:message) end def enumerated_errors enumerated(other_errors, failures.size) do |error| "#{error.class}: #{error.message}" end end def indented(failure_message, index) line_1, *rest = failure_message.strip.lines.to_a first_line_indentation = ' ' * (longest_index_label_width - width_of_label(index)) first_line_indentation + line_1 + rest.map do |line| line =~ /\S/ ? indentation + line : line end.join end def indentation @indentation ||= ' ' * longest_index_label_width end def longest_index_label_width @longest_index_label_width ||= width_of_label(failures.size) end def width_of_label(index) index_label(index).chars.count end def index_label(index) " #{index + 1}) " end end end end rspec-expectations-3.13.0/lib/rspec/expectations/handler.rb000066400000000000000000000135711455770000100237560ustar00rootroot00000000000000module RSpec module Expectations # @private module ExpectationHelper def self.check_message(msg) unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call) ::Kernel.warn [ "WARNING: ignoring the provided expectation message argument (", msg.inspect, ") since it is not a string or a proc." ].join end end # Returns an RSpec-3+ compatible matcher, wrapping a legacy one # in an adapter if necessary. # # @private def self.modern_matcher_from(matcher) LegacyMatcherAdapter::RSpec2.wrap(matcher) || LegacyMatcherAdapter::RSpec1.wrap(matcher) || matcher end def self.with_matcher(handler, matcher, message) check_message(message) matcher = modern_matcher_from(matcher) yield matcher ensure ::RSpec::Matchers.last_expectation_handler = handler ::RSpec::Matchers.last_matcher = matcher end def self.handle_failure(matcher, message, failure_message_method) message = message.call if message.respond_to?(:call) message ||= matcher.__send__(failure_message_method) if matcher.respond_to?(:diffable?) && matcher.diffable? ::RSpec::Expectations.fail_with message, matcher.expected, matcher.actual else ::RSpec::Expectations.fail_with message end end end # @private class PositiveExpectationHandler def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block) ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher| return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher match_result = matcher.matches?(actual, &block) if custom_message && match_result.respond_to?(:error_generator) match_result.error_generator.opts[:message] = custom_message end match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message) end end def self.verb 'is expected to' end def self.should_method :should end def self.opposite_should_method :should_not end end # @private class NegativeExpectationHandler def self.handle_matcher(actual, initial_matcher, custom_message=nil, &block) ExpectationHelper.with_matcher(self, initial_matcher, custom_message) do |matcher| return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher negated_match_result = does_not_match?(matcher, actual, &block) if custom_message && negated_match_result.respond_to?(:error_generator) negated_match_result.error_generator.opts[:message] = custom_message end negated_match_result || ExpectationHelper.handle_failure(matcher, custom_message, :failure_message_when_negated) end end def self.does_not_match?(matcher, actual, &block) if matcher.respond_to?(:does_not_match?) matcher.does_not_match?(actual, &block) else !matcher.matches?(actual, &block) end end def self.verb 'is expected not to' end def self.should_method :should_not end def self.opposite_should_method :should end end # Wraps a matcher written against one of the legacy protocols in # order to present the current protocol. # # @private class LegacyMatcherAdapter < Matchers::MatcherDelegator def initialize(matcher) super ::RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''), :type => "legacy_matcher") |#{matcher.class.name || matcher.inspect} implements a legacy RSpec matcher |protocol. For the current protocol you should expose the failure messages |via the `failure_message` and `failure_message_when_negated` methods. |(Used from #{CallerFilter.first_non_rspec_line}) EOS end def self.wrap(matcher) new(matcher) if interface_matches?(matcher) end # Starting in RSpec 1.2 (and continuing through all 2.x releases), # the failure message protocol was: # * `failure_message_for_should` # * `failure_message_for_should_not` # @private class RSpec2 < self def failure_message base_matcher.failure_message_for_should end def failure_message_when_negated base_matcher.failure_message_for_should_not end def self.interface_matches?(matcher) ( !matcher.respond_to?(:failure_message) && matcher.respond_to?(:failure_message_for_should) ) || ( !matcher.respond_to?(:failure_message_when_negated) && matcher.respond_to?(:failure_message_for_should_not) ) end end # Before RSpec 1.2, the failure message protocol was: # * `failure_message` # * `negative_failure_message` # @private class RSpec1 < self def failure_message base_matcher.failure_message end def failure_message_when_negated base_matcher.negative_failure_message end # Note: `failure_message` is part of the RSpec 3 protocol # (paired with `failure_message_when_negated`), so we don't check # for `failure_message` here. def self.interface_matches?(matcher) !matcher.respond_to?(:failure_message_when_negated) && matcher.respond_to?(:negative_failure_message) end end end # RSpec 3.0 was released with the class name misspelled. For SemVer compatibility, # we will provide this misspelled alias until 4.0. # @deprecated Use LegacyMatcherAdapter instead. # @private LegacyMacherAdapter = LegacyMatcherAdapter end end rspec-expectations-3.13.0/lib/rspec/expectations/minitest_integration.rb000066400000000000000000000032431455770000100265730ustar00rootroot00000000000000require 'rspec/expectations' Minitest::Test.class_eval do include ::RSpec::Matchers # This `expect` will only be called if the user is using Minitest < 5.6 # or if they are _not_ using Minitest::Spec on 5.6+. Minitest::Spec on 5.6+ # defines its own `expect` and will have the assertions incremented via our # definitions of `to`/`not_to`/`to_not` below. def expect(*a, &b) self.assertions += 1 super end # Convert a `MultipleExpectationsNotMetError` to a `Minitest::Assertion` error so # it gets counted in minitest's summary stats as a failure rather than an error. # It would be nice to make `MultipleExpectationsNotMetError` subclass # `Minitest::Assertion`, but Minitest's implementation does not treat subclasses # the same, so this is the best we can do. def aggregate_failures(*args, &block) super rescue RSpec::Expectations::MultipleExpectationsNotMetError => e assertion_failed = Minitest::Assertion.new(e.message) assertion_failed.set_backtrace e.backtrace raise assertion_failed end end # Older versions of Minitest (e.g. before 5.6) do not define # `Minitest::Expectation`. if defined?(::Minitest::Expectation) Minitest::Expectation.class_eval do include RSpec::Expectations::ExpectationTarget::InstanceMethods def to(*args) ctx.assertions += 1 super end def not_to(*args) ctx.assertions += 1 super end def to_not(*args) ctx.assertions += 1 super end end end module RSpec module Expectations remove_const :ExpectationNotMetError # Exception raised when an expectation fails. const_set :ExpectationNotMetError, ::Minitest::Assertion end end rspec-expectations-3.13.0/lib/rspec/expectations/syntax.rb000066400000000000000000000112111455770000100236540ustar00rootroot00000000000000module RSpec module Expectations # @api private # Provides methods for enabling and disabling the available # syntaxes provided by rspec-expectations. module Syntax module_function # @api private # Determines where we add `should` and `should_not`. def default_should_host @default_should_host ||= ::Object.ancestors.last end # @api private # Instructs rspec-expectations to warn on first usage of `should` or `should_not`. # Enabled by default. This is largely here to facilitate testing. def warn_about_should! @warn_about_should = true end # @api private # Generates a deprecation warning for the given method if no warning # has already been issued. def warn_about_should_unless_configured(method_name) return unless @warn_about_should RSpec.deprecate( "Using `#{method_name}` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax", :replacement => "the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }`" ) @warn_about_should = false end # @api private # Enables the `should` syntax. def enable_should(syntax_host=default_should_host) @warn_about_should = false if syntax_host == default_should_host return if should_enabled?(syntax_host) syntax_host.module_exec do def should(matcher=nil, message=nil, &block) ::RSpec::Expectations::Syntax.warn_about_should_unless_configured(::Kernel.__method__) ::RSpec::Expectations::PositiveExpectationHandler.handle_matcher(self, matcher, message, &block) end def should_not(matcher=nil, message=nil, &block) ::RSpec::Expectations::Syntax.warn_about_should_unless_configured(::Kernel.__method__) ::RSpec::Expectations::NegativeExpectationHandler.handle_matcher(self, matcher, message, &block) end end end # @api private # Disables the `should` syntax. def disable_should(syntax_host=default_should_host) return unless should_enabled?(syntax_host) syntax_host.module_exec do undef should undef should_not end end # @api private # Enables the `expect` syntax. def enable_expect(syntax_host=::RSpec::Matchers) return if expect_enabled?(syntax_host) syntax_host.module_exec do def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block) ::RSpec::Expectations::ExpectationTarget.for(value, block) end end end # @api private # Disables the `expect` syntax. def disable_expect(syntax_host=::RSpec::Matchers) return unless expect_enabled?(syntax_host) syntax_host.module_exec do undef expect end end # @api private # Indicates whether or not the `should` syntax is enabled. def should_enabled?(syntax_host=default_should_host) syntax_host.method_defined?(:should) end # @api private # Indicates whether or not the `expect` syntax is enabled. def expect_enabled?(syntax_host=::RSpec::Matchers) syntax_host.method_defined?(:expect) end end end end if defined?(BasicObject) # The legacy `:should` syntax adds the following methods directly to # `BasicObject` so that they are available off of any object. Note, however, # that this syntax does not always play nice with delegate/proxy objects. # We recommend you use the non-monkeypatching `:expect` syntax instead. class BasicObject # @method should(matcher, message) # Passes if `matcher` returns true. Available on every `Object`. # @example # actual.should eq expected # actual.should match /expression/ # @param [Matcher] # matcher # @param [String] message optional message to display when the expectation fails # @return [Boolean] true if the expectation succeeds (else raises) # @note This is only available when you have enabled the `:should` syntax. # @see RSpec::Matchers # @method should_not(matcher, message) # Passes if `matcher` returns false. Available on every `Object`. # @example # actual.should_not eq expected # @param [Matcher] # matcher # @param [String] message optional message to display when the expectation fails # @return [Boolean] false if the negative expectation succeeds (else raises) # @note This is only available when you have enabled the `:should` syntax. # @see RSpec::Matchers end end rspec-expectations-3.13.0/lib/rspec/expectations/version.rb000066400000000000000000000001571455770000100240220ustar00rootroot00000000000000module RSpec module Expectations # @private module Version STRING = '3.13.0' end end end rspec-expectations-3.13.0/lib/rspec/matchers.rb000066400000000000000000001163131455770000100214370ustar00rootroot00000000000000require 'rspec/support' RSpec::Support.require_rspec_support 'matcher_definition' RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relative(f) } %w[ english_phrasing composable built_in generated_descriptions dsl matcher_delegator aliased_matcher multi_matcher_diff ].each { |file| RSpec::Support.require_rspec_matchers(file) } # RSpec's top level namespace. All of rspec-expectations is contained # in the `RSpec::Expectations` and `RSpec::Matchers` namespaces. module RSpec # RSpec::Matchers provides a number of useful matchers we use to define # expectations. Any object that implements the [matcher protocol](Matchers/MatcherProtocol) # can be used as a matcher. # # ## Predicates # # In addition to matchers that are defined explicitly, RSpec will create # custom matchers on the fly for any arbitrary predicate, giving your specs a # much more natural language feel. # # A Ruby predicate is a method that ends with a "?" and returns true or false. # Common examples are `empty?`, `nil?`, and `instance_of?`. # # All you need to do is write `expect(..).to be_` followed by the predicate # without the question mark, and RSpec will figure it out from there. # For example: # # expect([]).to be_empty # => [].empty?() | passes # expect([]).not_to be_empty # => [].empty?() | fails # # In addition to prefixing the predicate matchers with "be_", you can also use "be_a_" # and "be_an_", making your specs read much more naturally: # # expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes # # expect(3).to be_a_kind_of(Integer) # => 3.kind_of?(Numeric) | passes # expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes # expect(3).to be_an_instance_of(Integer) # => 3.instance_of?(Integer) | passes # expect(3).not_to be_an_instance_of(Numeric) # => 3.instance_of?(Numeric) | fails # # RSpec will also create custom matchers for predicates like `has_key?`. To # use this feature, just state that the object should have_key(:key) and RSpec will # call has_key?(:key) on the target. For example: # # expect(:a => "A").to have_key(:a) # expect(:a => "A").to have_key(:b) # fails # # You can use this feature to invoke any predicate that begins with "has_", whether it is # part of the Ruby libraries (like `Hash#has_key?`) or a method you wrote on your own class. # # Note that RSpec does not provide composable aliases for these dynamic predicate # matchers. You can easily define your own aliases, though: # # RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin # expect(user_list).to include(a_user_who_is_an_admin) # # ## Alias Matchers # # With {RSpec::Matchers.alias_matcher}, you can easily create an # alternate name for a given matcher. # # The description will also change according to the new name: # # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to # sum_to(3).description # => "sum to 3" # a_list_that_sums_to(3).description # => "a list that sums to 3" # # or you can specify a custom description like this: # # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description| # description.sub("be sorted by", "a list sorted by") # end # # be_sorted_by(:age).description # => "be sorted by age" # a_list_sorted_by(:age).description # => "a list sorted by age" # # ## Custom Matchers # # When you find that none of the stock matchers provide a natural feeling # expectation, you can very easily write your own using RSpec's matcher DSL # or writing one from scratch. # # ### Matcher DSL # # Imagine that you are writing a game in which players can be in various # zones on a virtual board. To specify that bob should be in zone 4, you # could say: # # expect(bob.current_zone).to eql(Zone.new("4")) # # But you might find it more expressive to say: # # expect(bob).to be_in_zone("4") # # and/or # # expect(bob).not_to be_in_zone("3") # # You can create such a matcher like so: # # RSpec::Matchers.define :be_in_zone do |zone| # match do |player| # player.in_zone?(zone) # end # end # # This will generate a be_in_zone method that returns a matcher # with logical default messages for failures. You can override the failure # messages and the generated description as follows: # # RSpec::Matchers.define :be_in_zone do |zone| # match do |player| # player.in_zone?(zone) # end # # failure_message do |player| # # generate and return the appropriate string. # end # # failure_message_when_negated do |player| # # generate and return the appropriate string. # end # # description do # # generate and return the appropriate string. # end # end # # Each of the message-generation methods has access to the block arguments # passed to the create method (in this case, zone). The # failure message methods (failure_message and # failure_message_when_negated) are passed the actual value (the # receiver of expect(..) or expect(..).not_to). # # ### Custom Matcher from scratch # # You could also write a custom matcher from scratch, as follows: # # class BeInZone # def initialize(expected) # @expected = expected # end # # def matches?(target) # @target = target # @target.current_zone.eql?(Zone.new(@expected)) # end # # def failure_message # "expected #{@target.inspect} to be in Zone #{@expected}" # end # # def failure_message_when_negated # "expected #{@target.inspect} not to be in Zone #{@expected}" # end # end # # ... and a method like this: # # def be_in_zone(expected) # BeInZone.new(expected) # end # # And then expose the method to your specs. This is normally done # by including the method and the class in a module, which is then # included in your spec: # # module CustomGameMatchers # class BeInZone # # ... # end # # def be_in_zone(expected) # # ... # end # end # # describe "Player behaviour" do # include CustomGameMatchers # # ... # end # # or you can include in globally in a spec_helper.rb file required # from your spec file(s): # # RSpec::configure do |config| # config.include(CustomGameMatchers) # end # # ### Making custom matchers composable # # RSpec's built-in matchers are designed to be composed, in expressions like: # # expect(["barn", 2.45]).to contain_exactly( # a_value_within(0.1).of(2.5), # a_string_starting_with("bar") # ) # # Custom matchers can easily participate in composed matcher expressions like these. # Include {RSpec::Matchers::Composable} in your custom matcher to make it support # being composed (matchers defined using the DSL have this included automatically). # Within your matcher's `matches?` method (or the `match` block, if using the DSL), # use `values_match?(expected, actual)` rather than `expected == actual`. # Under the covers, `values_match?` is able to match arbitrary # nested data structures containing a mix of both matchers and non-matcher objects. # It uses `===` and `==` to perform the matching, considering the values to # match if either returns `true`. The `Composable` mixin also provides some helper # methods for surfacing the matcher descriptions within your matcher's description # or failure messages. # # RSpec's built-in matchers each have a number of aliases that rephrase the matcher # from a verb phrase (such as `be_within`) to a noun phrase (such as `a_value_within`), # which reads better when the matcher is passed as an argument in a composed matcher # expressions, and also uses the noun-phrase wording in the matcher's `description`, # for readable failure messages. You can alias your custom matchers in similar fashion # using {RSpec::Matchers.alias_matcher}. # # ## Negated Matchers # # Sometimes if you want to test for the opposite using a more descriptive name # instead of using `not_to`, you can use {RSpec::Matchers.define_negated_matcher}: # # RSpec::Matchers.define_negated_matcher :exclude, :include # include(1, 2).description # => "include 1 and 2" # exclude(1, 2).description # => "exclude 1 and 2" # # While the most obvious negated form may be to add a `not_` prefix, # the failure messages you get with that form can be confusing (e.g. # "expected [actual] to not [verb], but did not"). We've found it works # best to find a more positive name for the negated form, such as # `avoid_changing` rather than `not_change`. # module Matchers # rubocop:disable Metrics/ModuleLength extend ::RSpec::Matchers::DSL # @!macro [attach] alias_matcher # @!parse # alias $1 $2 # @!visibility private # We define this override here so we can attach a YARD macro to it. # It ensures that our docs list all the matcher aliases. def self.alias_matcher(*args, &block) super(*args, &block) end # @!method self.alias_matcher(new_name, old_name, options={}, &description_override) # Extended from {RSpec::Matchers::DSL#alias_matcher}. # @!method self.define(name, &declarations) # Extended from {RSpec::Matchers::DSL#define}. # @!method self.define_negated_matcher(negated_name, base_name, &description_override) # Extended from {RSpec::Matchers::DSL#define_negated_matcher}. # @method expect # Supports `expect(actual).to matcher` syntax by wrapping `actual` in an # `ExpectationTarget`. # @example # expect(actual).to eq(expected) # expect(actual).not_to eq(expected) # @return [Expectations::ExpectationTarget] # @see Expectations::ExpectationTarget#to # @see Expectations::ExpectationTarget#not_to # Allows multiple expectations in the provided block to fail, and then # aggregates them into a single exception, rather than aborting on the # first expectation failure like normal. This allows you to see all # failures from an entire set of expectations without splitting each # off into its own example (which may slow things down if the example # setup is expensive). # # @param label [String] label for this aggregation block, which will be # included in the aggregated exception message. # @param metadata [Hash] additional metadata about this failure aggregation # block. If multiple expectations fail, it will be exposed from the # {Expectations::MultipleExpectationsNotMetError} exception. Mostly # intended for internal RSpec use but you can use it as well. # @yield Block containing as many expectation as you want. The block is # simply yielded to, so you can trust that anything that works outside # the block should work within it. # @raise [Expectations::MultipleExpectationsNotMetError] raised when # multiple expectations fail. # @raise [Expectations::ExpectationNotMetError] raised when a single # expectation fails. # @raise [Exception] other sorts of exceptions will be raised as normal. # # @example # aggregate_failures("verifying response") do # expect(response.status).to eq(200) # expect(response.headers).to include("Content-Type" => "text/plain") # expect(response.body).to include("Success") # end # # @note The implementation of this feature uses a thread-local variable, # which means that if you have an expectation failure in another thread, # it'll abort like normal. def aggregate_failures(label=nil, metadata={}, &block) Expectations::FailureAggregator.new(label, metadata).aggregate(&block) end # Passes if actual is truthy (anything but false or nil) def be_truthy BuiltIn::BeTruthy.new end alias_matcher :a_truthy_value, :be_truthy # Passes if actual is falsey (false or nil) def be_falsey BuiltIn::BeFalsey.new end alias_matcher :be_falsy, :be_falsey alias_matcher :a_falsey_value, :be_falsey alias_matcher :a_falsy_value, :be_falsey # Passes if actual is nil def be_nil BuiltIn::BeNil.new end alias_matcher :a_nil_value, :be_nil # @example # expect(actual).to be_truthy # expect(actual).to be_falsey # expect(actual).to be_nil # expect(actual).to be_[arbitrary_predicate](*args) # expect(actual).not_to be_nil # expect(actual).not_to be_[arbitrary_predicate](*args) # # Given true, false, or nil, will pass if actual value is true, false or # nil (respectively). Given no args means the caller should satisfy an if # condition (to be or not to be). # # Predicates are any Ruby method that ends in a "?" and returns true or # false. Given be_ followed by arbitrary_predicate (without the "?"), # RSpec will match convert that into a query against the target object. # # The arbitrary_predicate feature will handle any predicate prefixed with # "be_an_" (e.g. be_an_instance_of), "be_a_" (e.g. be_a_kind_of) or "be_" # (e.g. be_empty), letting you choose the prefix that best suits the # predicate. def be(*args) args.empty? ? Matchers::BuiltIn::Be.new : equal(*args) end alias_matcher :a_value, :be, :klass => AliasedMatcherWithOperatorSupport # passes if target.kind_of?(klass) def be_a(klass) be_a_kind_of(klass) end alias_method :be_an, :be_a # Passes if actual.instance_of?(expected) # # @example # expect(5).to be_an_instance_of(Integer) # expect(5).not_to be_an_instance_of(Numeric) # expect(5).not_to be_an_instance_of(Float) def be_an_instance_of(expected) BuiltIn::BeAnInstanceOf.new(expected) end alias_method :be_instance_of, :be_an_instance_of alias_matcher :an_instance_of, :be_an_instance_of # Passes if actual.kind_of?(expected) # # @example # expect(5).to be_a_kind_of(Integer) # expect(5).to be_a_kind_of(Numeric) # expect(5).not_to be_a_kind_of(Float) def be_a_kind_of(expected) BuiltIn::BeAKindOf.new(expected) end alias_method :be_kind_of, :be_a_kind_of alias_matcher :a_kind_of, :be_a_kind_of # Passes if actual.between?(min, max). Works with any Comparable object, # including String, Symbol, Time, or Numeric (Fixnum, Bignum, Integer, # Float, Complex, and Rational). # # By default, `be_between` is inclusive (i.e. passes when given either the max or min value), # but you can make it `exclusive` by chaining that off the matcher. # # @example # expect(5).to be_between(1, 10) # expect(11).not_to be_between(1, 10) # expect(10).not_to be_between(1, 10).exclusive def be_between(min, max) BuiltIn::BeBetween.new(min, max) end alias_matcher :a_value_between, :be_between # Passes if actual == expected +/- delta # # @example # expect(result).to be_within(0.5).of(3.0) # expect(result).not_to be_within(0.5).of(3.0) def be_within(delta) BuiltIn::BeWithin.new(delta) end alias_matcher :a_value_within, :be_within alias_matcher :within, :be_within # Applied to a proc, specifies that its execution will cause some value to # change. # # @param [Object] receiver # @param [Symbol] message the message to send the receiver # # You can either pass receiver and message, or a block, # but not both. # # When passing a block, it must use the `{ ... }` format, not # do/end, as `{ ... }` binds to the `change` method, whereas do/end # would errantly bind to the `expect(..).to` or `expect(...).not_to` method. # # You can chain any of the following off of the end to specify details # about the change: # # * `from` # * `to` # # or any one of: # # * `by` # * `by_at_least` # * `by_at_most` # # @example # expect { # team.add_player(player) # }.to change(roster, :count) # # expect { # team.add_player(player) # }.to change(roster, :count).by(1) # # expect { # team.add_player(player) # }.to change(roster, :count).by_at_least(1) # # expect { # team.add_player(player) # }.to change(roster, :count).by_at_most(1) # # string = "string" # expect { # string.reverse! # }.to change { string }.from("string").to("gnirts") # # string = "string" # expect { # string # }.not_to change { string }.from("string") # # expect { # person.happy_birthday # }.to change(person, :birthday).from(32).to(33) # # expect { # employee.develop_great_new_social_networking_app # }.to change(employee, :title).from("Mail Clerk").to("CEO") # # expect { # doctor.leave_office # }.to change(doctor, :sign).from(/is in/).to(/is out/) # # user = User.new(:type => "admin") # expect { # user.symbolize_type # }.to change(user, :type).from(String).to(Symbol) # # == Notes # # Evaluates `receiver.message` or `block` before and after it # evaluates the block passed to `expect`. If the value is the same # object, its before/after `hash` value is used to see if it has changed. # Therefore, your object needs to properly implement `hash` to work correctly # with this matcher. # # `expect( ... ).not_to change` supports the form that specifies `from` # (which specifies what you expect the starting, unchanged value to be) # but does not support forms with subsequent calls to `by`, `by_at_least`, # `by_at_most` or `to`. def change(receiver=nil, message=nil, &block) BuiltIn::Change.new(receiver, message, &block) end alias_matcher :a_block_changing, :change alias_matcher :changing, :change # Passes if actual contains all of the expected regardless of order. # This works for collections. Pass in multiple args and it will only # pass if all args are found in collection. # # @note This is also available using the `=~` operator with `should`, # but `=~` is not supported with `expect`. # # @example # expect([1, 2, 3]).to contain_exactly(1, 2, 3) # expect([1, 2, 3]).to contain_exactly(1, 3, 2) # # @see #match_array def contain_exactly(*items) BuiltIn::ContainExactly.new(items) end alias_matcher :a_collection_containing_exactly, :contain_exactly alias_matcher :containing_exactly, :contain_exactly # Passes if actual covers expected. This works for # Ranges. You can also pass in multiple args # and it will only pass if all args are found in Range. # # @example # expect(1..10).to cover(5) # expect(1..10).to cover(4, 6) # expect(1..10).to cover(4, 6, 11) # fails # expect(1..10).not_to cover(11) # expect(1..10).not_to cover(5) # fails # # ### Warning:: Ruby >= 1.9 only def cover(*values) BuiltIn::Cover.new(*values) end alias_matcher :a_range_covering, :cover alias_matcher :covering, :cover # Matches if the actual value ends with the expected value(s). In the case # of a string, matches against the last `expected.length` characters of the # actual string. In the case of an array, matches against the last # `expected.length` elements of the actual array. # # @example # expect("this string").to end_with "string" # expect([0, 1, 2, 3, 4]).to end_with 4 # expect([0, 2, 3, 4, 4]).to end_with 3, 4 def end_with(*expected) BuiltIn::EndWith.new(*expected) end alias_matcher :a_collection_ending_with, :end_with alias_matcher :a_string_ending_with, :end_with alias_matcher :ending_with, :end_with # Passes if actual == expected. # # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more # information about equality in Ruby. # # @example # expect(5).to eq(5) # expect(5).not_to eq(3) def eq(expected) BuiltIn::Eq.new(expected) end alias_matcher :an_object_eq_to, :eq alias_matcher :eq_to, :eq # Passes if `actual.eql?(expected)` # # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more # information about equality in Ruby. # # @example # expect(5).to eql(5) # expect(5).not_to eql(3) def eql(expected) BuiltIn::Eql.new(expected) end alias_matcher :an_object_eql_to, :eql alias_matcher :eql_to, :eql # Passes if actual.equal?(expected) (object identity). # # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more # information about equality in Ruby. # # @example # expect(5).to equal(5) # Integers are equal # expect("5").not_to equal("5") # Strings that look the same are not the same object def equal(expected) BuiltIn::Equal.new(expected) end alias_matcher :an_object_equal_to, :equal alias_matcher :equal_to, :equal # Passes if `actual.exist?` or `actual.exists?` # # @example # expect(File).to exist("path/to/file") def exist(*args) BuiltIn::Exist.new(*args) end alias_matcher :an_object_existing, :exist alias_matcher :existing, :exist # Passes if actual's attribute values match the expected attributes hash. # This works no matter how you define your attribute readers. # # @example # Person = Struct.new(:name, :age) # person = Person.new("Bob", 32) # # expect(person).to have_attributes(:name => "Bob", :age => 32) # expect(person).to have_attributes(:name => a_string_starting_with("B"), :age => (a_value > 30) ) # # @note It will fail if actual doesn't respond to any of the expected attributes. # # @example # expect(person).to have_attributes(:color => "red") def have_attributes(expected) BuiltIn::HaveAttributes.new(expected) end alias_matcher :an_object_having_attributes, :have_attributes alias_matcher :having_attributes, :have_attributes # Passes if actual includes expected. This works for # collections and Strings. You can also pass in multiple args # and it will only pass if all args are found in collection. # # @example # expect([1,2,3]).to include(3) # expect([1,2,3]).to include(2,3) # expect([1,2,3]).to include(2,3,4) # fails # expect([1,2,3]).not_to include(4) # expect("spread").to include("read") # expect("spread").not_to include("red") # expect(:a => 1, :b => 2).to include(:a) # expect(:a => 1, :b => 2).to include(:a, :b) # expect(:a => 1, :b => 2).to include(:a => 1) # expect(:a => 1, :b => 2).to include(:b => 2, :a => 1) # expect(:a => 1, :b => 2).to include(:c) # fails # expect(:a => 1, :b => 2).not_to include(:a => 2) def include(*expected) BuiltIn::Include.new(*expected) end alias_matcher :a_collection_including, :include alias_matcher :a_string_including, :include alias_matcher :a_hash_including, :include alias_matcher :including, :include # Passes if the provided matcher passes when checked against all # elements of the collection. # # @example # expect([1, 3, 5]).to all be_odd # expect([1, 3, 6]).to all be_odd # fails # # @note The negative form `not_to all` is not supported. Instead # use `not_to include` or pass a negative form of a matcher # as the argument (e.g. `all exclude(:foo)`). # # @note You can also use this with compound matchers as well. # # @example # expect([1, 3, 5]).to all( be_odd.and be_an(Integer) ) def all(expected) BuiltIn::All.new(expected) end # Given a `Regexp` or `String`, passes if `actual.match(pattern)` # Given an arbitrary nested data structure (e.g. arrays and hashes), # matches if `expected === actual` || `actual == expected` for each # pair of elements. # # @example # expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) # expect(email).to match("@example.com") # # @example # hash = { # :a => { # :b => ["foo", 5], # :c => { :d => 2.05 } # } # } # # expect(hash).to match( # :a => { # :b => a_collection_containing_exactly( # a_string_starting_with("f"), # an_instance_of(Integer) # ), # :c => { :d => (a_value < 3) } # } # ) # # @note The `match_regex` alias is deprecated and is not recommended for use. # It was added in 2.12.1 to facilitate its use from within custom # matchers (due to how the custom matcher DSL was evaluated in 2.x, # `match` could not be used there), but is no longer needed in 3.x. def match(expected) BuiltIn::Match.new(expected) end alias_matcher :match_regex, :match alias_matcher :an_object_matching, :match alias_matcher :a_string_matching, :match alias_matcher :matching, :match # An alternate form of `contain_exactly` that accepts # the expected contents as a single array arg rather # than splatted out as individual items. # # @example # expect(results).to contain_exactly(1, 2) # # is identical to: # expect(results).to match_array([1, 2]) # # @see #contain_exactly def match_array(items) contain_exactly(*items) end alias_matcher :an_array_matching, :match_array do |desc| desc.sub("contain exactly", "an array containing exactly") end # With no arg, passes if the block outputs `to_stdout` or `to_stderr`. # With a string, passes if the block outputs that specific string `to_stdout` or `to_stderr`. # With a regexp or matcher, passes if the block outputs a string `to_stdout` or `to_stderr` that matches. # # To capture output from any spawned subprocess as well, use `to_stdout_from_any_process` or # `to_stderr_from_any_process`. Output from any process that inherits the main process's corresponding # standard stream will be captured. # # @example # expect { print 'foo' }.to output.to_stdout # expect { print 'foo' }.to output('foo').to_stdout # expect { print 'foo' }.to output(/foo/).to_stdout # # expect { do_something }.to_not output.to_stdout # # expect { warn('foo') }.to output.to_stderr # expect { warn('foo') }.to output('foo').to_stderr # expect { warn('foo') }.to output(/foo/).to_stderr # # expect { do_something }.to_not output.to_stderr # # expect { system('echo foo') }.to output("foo\n").to_stdout_from_any_process # expect { system('echo foo', out: :err) }.to output("foo\n").to_stderr_from_any_process # # @note `to_stdout` and `to_stderr` work by temporarily replacing `$stdout` or `$stderr`, # so they're not able to intercept stream output that explicitly uses `STDOUT`/`STDERR` # or that uses a reference to `$stdout`/`$stderr` that was stored before the # matcher was used. # @note `to_stdout_from_any_process` and `to_stderr_from_any_process` use Tempfiles, and # are thus significantly (~30x) slower than `to_stdout` and `to_stderr`. def output(expected=nil) BuiltIn::Output.new(expected) end alias_matcher :a_block_outputting, :output # With no args, matches if any error is raised. # With a named error, matches only if that specific error is raised. # With a named error and message specified as a String, matches only if both match. # With a named error and message specified as a Regexp, matches only if both match. # Pass an optional block to perform extra verifications on the exception matched # # @example # expect { do_something_risky }.to raise_error # expect { do_something_risky }.to raise_error(PoorRiskDecisionError) # expect { do_something_risky }.to raise_error(PoorRiskDecisionError) { |error| expect(error.data).to eq 42 } # expect { do_something_risky }.to raise_error { |error| expect(error.data).to eq 42 } # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, "that was too risky") # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/) # expect { do_something_risky }.to raise_error("that was too risky") # # expect { do_something_risky }.not_to raise_error def raise_error(error=BuiltIn::RaiseError::UndefinedValue, message=nil, &block) BuiltIn::RaiseError.new(error, message, &block) end alias_method :raise_exception, :raise_error alias_matcher :a_block_raising, :raise_error do |desc| desc.sub("raise", "a block raising") end alias_matcher :raising, :raise_error do |desc| desc.sub("raise", "raising") end # Matches if the target object responds to all of the names # provided. Names can be Strings or Symbols. # # @example # expect("string").to respond_to(:length) # def respond_to(*names) BuiltIn::RespondTo.new(*names) end alias_matcher :an_object_responding_to, :respond_to alias_matcher :responding_to, :respond_to # Passes if the submitted block returns true. Yields target to the # block. # # Generally speaking, this should be thought of as a last resort when # you can't find any other way to specify the behaviour you wish to # specify. # # If you do find yourself in such a situation, you could always write # a custom matcher, which would likely make your specs more expressive. # # @param description [String] optional description to be used for this matcher. # # @example # expect(5).to satisfy { |n| n > 3 } # expect(5).to satisfy("be greater than 3") { |n| n > 3 } def satisfy(description=nil, &block) BuiltIn::Satisfy.new(description, &block) end alias_matcher :an_object_satisfying, :satisfy alias_matcher :satisfying, :satisfy # Matches if the actual value starts with the expected value(s). In the # case of a string, matches against the first `expected.length` characters # of the actual string. In the case of an array, matches against the first # `expected.length` elements of the actual array. # # @example # expect("this string").to start_with "this s" # expect([0, 1, 2, 3, 4]).to start_with 0 # expect([0, 2, 3, 4, 4]).to start_with 0, 1 def start_with(*expected) BuiltIn::StartWith.new(*expected) end alias_matcher :a_collection_starting_with, :start_with alias_matcher :a_string_starting_with, :start_with alias_matcher :starting_with, :start_with # Given no argument, matches if a proc throws any Symbol. # # Given a Symbol, matches if the given proc throws the specified Symbol. # # Given a Symbol and an arg, matches if the given proc throws the # specified Symbol with the specified arg. # # @example # expect { do_something_risky }.to throw_symbol # expect { do_something_risky }.to throw_symbol(:that_was_risky) # expect { do_something_risky }.to throw_symbol(:that_was_risky, 'culprit') # # expect { do_something_risky }.not_to throw_symbol # expect { do_something_risky }.not_to throw_symbol(:that_was_risky) # expect { do_something_risky }.not_to throw_symbol(:that_was_risky, 'culprit') def throw_symbol(expected_symbol=nil, expected_arg=nil) BuiltIn::ThrowSymbol.new(expected_symbol, expected_arg) end alias_matcher :a_block_throwing, :throw_symbol do |desc| desc.sub("throw", "a block throwing") end alias_matcher :throwing, :throw_symbol do |desc| desc.sub("throw", "throwing") end # Passes if the method called in the expect block yields, regardless # of whether or not arguments are yielded. # # @example # expect { |b| 5.tap(&b) }.to yield_control # expect { |b| "a".to_sym(&b) }.not_to yield_control # # @note Your expect block must accept a parameter and pass it on to # the method-under-test as a block. def yield_control BuiltIn::YieldControl.new end alias_matcher :a_block_yielding_control, :yield_control alias_matcher :yielding_control, :yield_control # Passes if the method called in the expect block yields with # no arguments. Fails if it does not yield, or yields with arguments. # # @example # expect { |b| User.transaction(&b) }.to yield_with_no_args # expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5` # expect { |b| "a".to_sym(&b) }.not_to yield_with_no_args # because it does not yield # # @note Your expect block must accept a parameter and pass it on to # the method-under-test as a block. # @note This matcher is not designed for use with methods that yield # multiple times. def yield_with_no_args BuiltIn::YieldWithNoArgs.new end alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args alias_matcher :yielding_with_no_args, :yield_with_no_args # Given no arguments, matches if the method called in the expect # block yields with arguments (regardless of what they are or how # many there are). # # Given arguments, matches if the method called in the expect block # yields with arguments that match the given arguments. # # Argument matching is done using `===` (the case match operator) # and `==`. If the expected and actual arguments match with either # operator, the matcher will pass. # # @example # expect { |b| 5.tap(&b) }.to yield_with_args # because #tap yields an arg # expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5 # expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5 # expect { |b| File.open("f.txt", &b) }.to yield_with_args(/txt/) # because /txt/ === "f.txt" # # expect { |b| User.transaction(&b) }.not_to yield_with_args # because it yields no args # expect { |b| 5.tap(&b) }.not_to yield_with_args(1, 2, 3) # # @note Your expect block must accept a parameter and pass it on to # the method-under-test as a block. # @note This matcher is not designed for use with methods that yield # multiple times. def yield_with_args(*args) BuiltIn::YieldWithArgs.new(*args) end alias_matcher :a_block_yielding_with_args, :yield_with_args alias_matcher :yielding_with_args, :yield_with_args # Designed for use with methods that repeatedly yield (such as # iterators). Passes if the method called in the expect block yields # multiple times with arguments matching those given. # # Argument matching is done using `===` (the case match operator) # and `==`. If the expected and actual arguments match with either # operator, the matcher will pass. # # @example # expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) # expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) # expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2) # # @note Your expect block must accept a parameter and pass it on to # the method-under-test as a block. def yield_successive_args(*args) BuiltIn::YieldSuccessiveArgs.new(*args) end alias_matcher :a_block_yielding_successive_args, :yield_successive_args alias_matcher :yielding_successive_args, :yield_successive_args # Delegates to {RSpec::Expectations.configuration}. # This is here because rspec-core's `expect_with` option # looks for a `configuration` method on the mixin # (`RSpec::Matchers`) to yield to a block. # @return [RSpec::Expectations::Configuration] the configuration object def self.configuration Expectations.configuration end private BE_PREDICATE_REGEX = /^(?:be_(?:an?_)?)(.*)/ HAS_REGEX = /^(?:have_)(.*)/ DYNAMIC_MATCHER_REGEX = Regexp.union(BE_PREDICATE_REGEX, HAS_REGEX) def method_missing(method, *args, &block) case method.to_s when BE_PREDICATE_REGEX BuiltIn::BePredicate.new(method, *args, &block) when HAS_REGEX BuiltIn::Has.new(method, *args, &block) else super end end ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true) if RUBY_VERSION.to_f >= 1.9 def respond_to_missing?(method, *) method =~ DYNAMIC_MATCHER_REGEX || super end else # for 1.8.7 # :nocov: def respond_to?(method, *) method = method.to_s method =~ DYNAMIC_MATCHER_REGEX || super end public :respond_to? # :nocov: end # @api private def self.is_a_matcher?(obj) return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj begin return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher) rescue NoMethodError # Some objects, like BasicObject, don't implemented standard # reflection methods. return false end return false unless obj.respond_to?(:matches?) obj.respond_to?(:failure_message) || obj.respond_to?(:failure_message_for_should) # support legacy matchers end ::RSpec::Support.register_matcher_definition do |obj| is_a_matcher?(obj) end # @api private def self.is_a_describable_matcher?(obj) is_a_matcher?(obj) && obj.respond_to?(:description) end class << self private if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9' # Note that `included` doesn't work for this because it is triggered # _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather # than _before_, like `append_features`. It's important we check this before # in order to find the cases where it was already previously included. # @api private def append_features(mod) return super if mod < self # `mod < self` indicates a re-inclusion. subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self } return super unless subclasses.any? subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor. subclasses = subclasses.map { |s| "`#{s}`" }.join(", ") RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \ "after previously being included in subclasses (#{subclasses}), " \ "which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \ "(https://redmine.ruby-lang.org/issues/3351). To work around this, " \ "either upgrade to MRI 2.0+, include a dup of the module (e.g. " \ "`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \ "before it is included in subclasses (#{subclasses}). See " \ "https://github.com/rspec/rspec-expectations/issues/814 for more info" super end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/000077500000000000000000000000001455770000100211055ustar00rootroot00000000000000rspec-expectations-3.13.0/lib/rspec/matchers/aliased_matcher.rb000066400000000000000000000102571455770000100245440ustar00rootroot00000000000000module RSpec module Matchers # Decorator that wraps a matcher and overrides `description` # using the provided block in order to support an alias # of a matcher. This is intended for use when composing # matchers, so that you can use an expression like # `include( a_value_within(0.1).of(3) )` rather than # `include( be_within(0.1).of(3) )`, and have the corresponding # description read naturally. # # @api private class AliasedMatcher < MatcherDelegator def initialize(base_matcher, description_block) @description_block = description_block super(base_matcher) end # Forward messages on to the wrapped matcher. # Since many matchers provide a fluent interface # (e.g. `a_value_within(0.1).of(3)`), we need to wrap # the returned value if it responds to `description`, # so that our override can be applied when it is eventually # used. def method_missing(*) return_val = super return return_val unless RSpec::Matchers.is_a_matcher?(return_val) self.class.new(return_val, @description_block) end # Provides the description of the aliased matcher. Aliased matchers # are designed to behave identically to the original matcher except # for the description and failure messages. The description is different # to reflect the aliased name. # # @api private def description @description_block.call(super) end # Provides the failure_message of the aliased matcher. Aliased matchers # are designed to behave identically to the original matcher except # for the description and failure messages. The failure_message is different # to reflect the aliased name. # # @api private def failure_message @description_block.call(super) end # Provides the failure_message_when_negated of the aliased matcher. Aliased matchers # are designed to behave identically to the original matcher except # for the description and failure messages. The failure_message_when_negated is different # to reflect the aliased name. # # @api private def failure_message_when_negated @description_block.call(super) end end # Decorator used for matchers that have special implementations of # operators like `==` and `===`. # @private class AliasedMatcherWithOperatorSupport < AliasedMatcher # We undef these so that they get delegated via `method_missing`. undef == undef === end # @private class AliasedNegatedMatcher < AliasedMatcher def matches?(*args, &block) if @base_matcher.respond_to?(:does_not_match?) @base_matcher.does_not_match?(*args, &block) else !super end end def does_not_match?(*args, &block) @base_matcher.matches?(*args, &block) end def failure_message optimal_failure_message(__method__, :failure_message_when_negated) end def failure_message_when_negated optimal_failure_message(__method__, :failure_message) end private DefaultFailureMessages = BuiltIn::BaseMatcher::DefaultFailureMessages # For a matcher that uses the default failure messages, we prefer to # use the override provided by the `description_block`, because it # includes the phrasing that the user has expressed a preference for # by going through the effort of defining a negated matcher. # # However, if the override didn't actually change anything, then we # should return the opposite failure message instead -- the overridden # message is going to be confusing if we return it as-is, as it represents # the non-negated failure message for a negated match (or vice versa). def optimal_failure_message(same, inverted) if DefaultFailureMessages.has_default_failure_messages?(@base_matcher) base_message = @base_matcher.__send__(same) overridden = @description_block.call(base_message) return overridden if overridden != base_message end @base_matcher.__send__(inverted) end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in.rb000066400000000000000000000065151455770000100232460ustar00rootroot00000000000000RSpec::Support.require_rspec_matchers "built_in/base_matcher" module RSpec module Matchers # Container module for all built-in matchers. The matcher classes are here # (rather than directly under `RSpec::Matchers`) in order to prevent name # collisions, since `RSpec::Matchers` gets included into the user's namespace. # # Autoloading is used to delay when the matcher classes get loaded, allowing # rspec-matchers to boot faster, and avoiding loading matchers the user is # not using. module BuiltIn autoload :BeAKindOf, 'rspec/matchers/built_in/be_kind_of' autoload :BeAnInstanceOf, 'rspec/matchers/built_in/be_instance_of' autoload :BeBetween, 'rspec/matchers/built_in/be_between' autoload :Be, 'rspec/matchers/built_in/be' autoload :BeComparedTo, 'rspec/matchers/built_in/be' autoload :BeFalsey, 'rspec/matchers/built_in/be' autoload :BeHelpers, 'rspec/matchers/built_in/be' autoload :BeNil, 'rspec/matchers/built_in/be' autoload :BePredicate, 'rspec/matchers/built_in/has' autoload :BeTruthy, 'rspec/matchers/built_in/be' autoload :BeWithin, 'rspec/matchers/built_in/be_within' autoload :Change, 'rspec/matchers/built_in/change' autoload :Compound, 'rspec/matchers/built_in/compound' autoload :ContainExactly, 'rspec/matchers/built_in/contain_exactly' autoload :Cover, 'rspec/matchers/built_in/cover' autoload :EndWith, 'rspec/matchers/built_in/start_or_end_with' autoload :Eq, 'rspec/matchers/built_in/eq' autoload :Eql, 'rspec/matchers/built_in/eql' autoload :Equal, 'rspec/matchers/built_in/equal' autoload :Exist, 'rspec/matchers/built_in/exist' autoload :Has, 'rspec/matchers/built_in/has' autoload :HaveAttributes, 'rspec/matchers/built_in/have_attributes' autoload :Include, 'rspec/matchers/built_in/include' autoload :All, 'rspec/matchers/built_in/all' autoload :Match, 'rspec/matchers/built_in/match' autoload :NegativeOperatorMatcher, 'rspec/matchers/built_in/operators' autoload :OperatorMatcher, 'rspec/matchers/built_in/operators' autoload :Output, 'rspec/matchers/built_in/output' autoload :PositiveOperatorMatcher, 'rspec/matchers/built_in/operators' autoload :RaiseError, 'rspec/matchers/built_in/raise_error' autoload :RespondTo, 'rspec/matchers/built_in/respond_to' autoload :Satisfy, 'rspec/matchers/built_in/satisfy' autoload :StartWith, 'rspec/matchers/built_in/start_or_end_with' autoload :ThrowSymbol, 'rspec/matchers/built_in/throw_symbol' autoload :YieldControl, 'rspec/matchers/built_in/yield' autoload :YieldSuccessiveArgs, 'rspec/matchers/built_in/yield' autoload :YieldWithArgs, 'rspec/matchers/built_in/yield' autoload :YieldWithNoArgs, 'rspec/matchers/built_in/yield' end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/000077500000000000000000000000001455770000100227125ustar00rootroot00000000000000rspec-expectations-3.13.0/lib/rspec/matchers/built_in/all.rb000066400000000000000000000046531455770000100240170ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `all`. # Not intended to be instantiated directly. class All < BaseMatcher # @private attr_reader :matcher, :failed_objects def initialize(matcher) @matcher = matcher @failed_objects = {} end # @private def does_not_match?(_actual) raise NotImplementedError, '`expect().not_to all( matcher )` is not supported.' end # @api private # @return [String] def failure_message unless iterable? return "#{improve_hash_formatting(super)}, but was not iterable" end all_messages = [improve_hash_formatting(super)] failed_objects.each do |index, matcher_failure_message| all_messages << failure_message_for_item(index, matcher_failure_message) end all_messages.join("\n\n") end # @api private # @return [String] def description improve_hash_formatting "all #{description_of matcher}" end private def match(_expected, _actual) return false unless iterable? index_failed_objects failed_objects.empty? end def index_failed_objects actual.each_with_index do |actual_item, index| cloned_matcher = matcher.clone matches = cloned_matcher.matches?(actual_item) failed_objects[index] = cloned_matcher.failure_message unless matches end end def failure_message_for_item(index, failure_message) failure_message = indent_multiline_message(add_new_line_if_needed(failure_message)) indent_multiline_message("object at index #{index} failed to match:#{failure_message}") end def add_new_line_if_needed(message) message.start_with?("\n") ? message : "\n#{message}" end def indent_multiline_message(message) message = message.sub(/\n+\z/, '') message.lines.map do |line| line =~ /\S/ ? ' ' + line : line end.join end def initialize_copy(other) @matcher = @matcher.clone @failed_objects = @failed_objects.clone super end def iterable? @actual.respond_to?(:each_with_index) end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/base_matcher.rb000066400000000000000000000167451455770000100256710ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # # Used _internally_ as a base class for matchers that ship with # rspec-expectations and rspec-rails. # # ### Warning: # # This class is for internal use, and subject to change without notice. # We strongly recommend that you do not base your custom matchers on this # class. If/when this changes, we will announce it and remove this warning. class BaseMatcher include RSpec::Matchers::Composable # @api private # Used to detect when no arg is passed to `initialize`. # `nil` cannot be used because it's a valid value to pass. UNDEFINED = Object.new.freeze # @private attr_reader :actual, :expected, :rescued_exception # @private attr_writer :matcher_name def initialize(expected=UNDEFINED) @expected = expected unless UNDEFINED.equal?(expected) end # @api private # Indicates if the match is successful. Delegates to `match`, which # should be defined on a subclass. Takes care of consistently # initializing the `actual` attribute. def matches?(actual) @actual = actual match(expected, actual) end # @api private # Used to wrap a block of code that will indicate failure by # raising one of the named exceptions. # # This is used by rspec-rails for some of its matchers that # wrap rails' assertions. def match_unless_raises(*exceptions) exceptions.unshift Exception if exceptions.empty? begin yield true rescue *exceptions => @rescued_exception false end end # @api private # Generates a description using {EnglishPhrasing}. # @return [String] def description desc = EnglishPhrasing.split_words(self.class.matcher_name) desc << EnglishPhrasing.list(@expected) if defined?(@expected) desc end # @api private # Matchers are not diffable by default. Override this to make your # subclass diffable. def diffable? false end # @api private # Most matchers are value matchers (i.e. meant to work with `expect(value)`) # rather than block matchers (i.e. meant to work with `expect { }`), so # this defaults to false. Block matchers must override this to return true. def supports_block_expectations? false end # @private def supports_value_expectations? true end # @api private def expects_call_stack_jump? false end # @private def expected_formatted RSpec::Support::ObjectFormatter.format(@expected) end # @private def actual_formatted RSpec::Support::ObjectFormatter.format(@actual) end # @private def self.matcher_name @matcher_name ||= underscore(name.split('::').last) end # @private def matcher_name if defined?(@matcher_name) @matcher_name else self.class.matcher_name end end # @private # Borrowed from ActiveSupport. def self.underscore(camel_cased_word) word = camel_cased_word.to_s.dup word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') word.gsub!(/([a-z\d])([A-Z])/, '\1_\2') word.tr!('-', '_') word.downcase! word end private_class_method :underscore private def assert_ivars(*expected_ivars) return unless (expected_ivars - present_ivars).any? ivar_list = EnglishPhrasing.list(expected_ivars) raise "#{self.class.name} needs to supply#{ivar_list}" end if RUBY_VERSION.to_f < 1.9 # :nocov: def present_ivars instance_variables.map(&:to_sym) end # :nocov: else alias present_ivars instance_variables end # @private module HashFormatting # `{ :a => 5, :b => 2 }.inspect` produces: # # {:a=>5, :b=>2} # # ...but it looks much better as: # # {:a => 5, :b => 2} # # This is idempotent and safe to run on a string multiple times. def improve_hash_formatting(inspect_string) inspect_string.gsub(/(\S)=>(\S)/, '\1 => \2') end module_function :improve_hash_formatting end include HashFormatting # @private module StringEncodingFormatting # @api private # @return [Boolean] True if the actual and expected string encoding are different. # i.e. the failure may be related to encoding differences and the encoding # should be shown to the user. false otherwise. if String.method_defined?(:encoding) def string_encoding_differs? actual.is_a?(String) && expected.is_a?(String) && actual.encoding != expected.encoding end else # @api private # @return [Boolean] False always as the curent Ruby version does not support String encoding def string_encoding_differs? false end end module_function :string_encoding_differs? if String.method_defined?(:encoding) # @api private # Formats a String's encoding as a human readable string # @param value [String] # @return [String] def format_encoding(value) "#" end else # @api private # Formats a String's encoding as a human readable string # @param _value [String] # @return [nil] nil as the curent Ruby version does not support String encoding def format_encoding(_value) nil end end module_function :format_encoding end include StringEncodingFormatting # @api private # Provides default implementations of failure messages, based on the `description`. module DefaultFailureMessages # @api private # Provides a good generic failure message. Based on `description`. # When subclassing, if you are not satisfied with this failure message # you often only need to override `description`. # @return [String] def failure_message "expected #{description_of @actual} to #{description}".dup end # @api private # Provides a good generic negative failure message. Based on `description`. # When subclassing, if you are not satisfied with this failure message # you often only need to override `description`. # @return [String] def failure_message_when_negated "expected #{description_of @actual} not to #{description}".dup end # @private def self.has_default_failure_messages?(matcher) matcher.method(:failure_message).owner == self && matcher.method(:failure_message_when_negated).owner == self rescue NameError false end end include DefaultFailureMessages end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/be.rb000066400000000000000000000110341455770000100236240ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `be_truthy`. # Not intended to be instantiated directly. class BeTruthy < BaseMatcher # @api private # @return [String] def failure_message "expected: truthy value\n got: #{actual_formatted}" end # @api private # @return [String] def failure_message_when_negated "expected: falsey value\n got: #{actual_formatted}" end private def match(_, actual) !!actual end end # @api private # Provides the implementation for `be_falsey`. # Not intended to be instantiated directly. class BeFalsey < BaseMatcher # @api private # @return [String] def failure_message "expected: falsey value\n got: #{actual_formatted}" end # @api private # @return [String] def failure_message_when_negated "expected: truthy value\n got: #{actual_formatted}" end private def match(_, actual) !actual end end # @api private # Provides the implementation for `be_nil`. # Not intended to be instantiated directly. class BeNil < BaseMatcher # @api private # @return [String] def failure_message "expected: nil\n got: #{actual_formatted}" end # @api private # @return [String] def failure_message_when_negated "expected: not nil\n got: nil" end private def match(_, actual) actual.nil? end end # @private module BeHelpers private def args_to_s @args.empty? ? "" : parenthesize(inspected_args.join(', ')) end def parenthesize(string) "(#{string})" end def inspected_args @args.map { |a| RSpec::Support::ObjectFormatter.format(a) } end def expected_to_sentence EnglishPhrasing.split_words(@expected) end def args_to_sentence EnglishPhrasing.list(@args) end end # @api private # Provides the implementation for `be`. # Not intended to be instantiated directly. class Be < BaseMatcher include BeHelpers def initialize(*args) @args = args end # @api private # @return [String] def failure_message "expected #{actual_formatted} to evaluate to true" end # @api private # @return [String] def failure_message_when_negated "expected #{actual_formatted} to evaluate to false" end [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator| define_method operator do |operand| BeComparedTo.new(operand, operator) end end private def match(_, actual) !!actual end end # @api private # Provides the implementation of `be value`. # Not intended to be instantiated directly. class BeComparedTo < BaseMatcher include BeHelpers def initialize(operand, operator) @expected = operand @operator = operator @args = [] end def matches?(actual) perform_match(actual) rescue ArgumentError, NoMethodError false end def does_not_match?(actual) !perform_match(actual) rescue ArgumentError, NoMethodError false end # @api private # @return [String] def failure_message "expected: #{@operator} #{expected_formatted}\n" \ " got: #{@operator.to_s.gsub(/./, ' ')} #{actual_formatted}" end # @api private # @return [String] def failure_message_when_negated message = "`expect(#{actual_formatted}).not_to " \ "be #{@operator} #{expected_formatted}`" if [:<, :>, :<=, :>=].include?(@operator) message + " not only FAILED, it is a bit confusing." else message end end # @api private # @return [String] def description "be #{@operator} #{expected_to_sentence}#{args_to_sentence}" end private def perform_match(actual) @actual = actual @actual.__send__ @operator, @expected end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/be_between.rb000066400000000000000000000037701455770000100253450ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `be_between`. # Not intended to be instantiated directly. class BeBetween < BaseMatcher def initialize(min, max) @min, @max = min, max inclusive end # @api public # Makes the between comparison inclusive. # # @example # expect(3).to be_between(2, 3).inclusive # # @note The matcher is inclusive by default; this simply provides # a way to be more explicit about it. def inclusive @less_than_operator = :<= @greater_than_operator = :>= @mode = :inclusive self end # @api public # Makes the between comparison exclusive. # # @example # expect(3).to be_between(2, 4).exclusive def exclusive @less_than_operator = :< @greater_than_operator = :> @mode = :exclusive self end # @api private # @return [Boolean] def matches?(actual) @actual = actual comparable? && compare rescue ArgumentError false end # @api private # @return [String] def failure_message "#{super}#{not_comparable_clause}" end # @api private # @return [String] def description "be between #{description_of @min} and #{description_of @max} (#{@mode})" end private def comparable? @actual.respond_to?(@less_than_operator) && @actual.respond_to?(@greater_than_operator) end def not_comparable_clause ", but it does not respond to `#{@less_than_operator}` and `#{@greater_than_operator}`" unless comparable? end def compare @actual.__send__(@greater_than_operator, @min) && @actual.__send__(@less_than_operator, @max) end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/be_instance_of.rb000066400000000000000000000013731455770000100262010ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `be_an_instance_of`. # Not intended to be instantiated directly. class BeAnInstanceOf < BaseMatcher # @api private # @return [String] def description "be an instance of #{expected}" end private def match(expected, actual) actual.instance_of?(expected) rescue NoMethodError raise ::ArgumentError, "The #{matcher_name} matcher requires that " \ "the actual object responds to #instance_of? method " \ "but a `NoMethodError` was encountered instead." end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/be_kind_of.rb000066400000000000000000000011501455770000100253130ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `be_a_kind_of`. # Not intended to be instantiated directly. class BeAKindOf < BaseMatcher private def match(expected, actual) actual.kind_of?(expected) rescue NoMethodError raise ::ArgumentError, "The #{matcher_name} matcher requires that " \ "the actual object responds to #kind_of? method " \ "but a `NoMethodError` was encountered instead." end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/be_within.rb000066400000000000000000000034631455770000100252150ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `be_within`. # Not intended to be instantiated directly. class BeWithin < BaseMatcher def initialize(delta) @delta = delta end # @api public # Sets the expected value. def of(expected) @expected = expected @tolerance = @delta @unit = '' self end # @api public # Sets the expected value, and makes the matcher do # a percent comparison. def percent_of(expected) @expected = expected @tolerance = @expected.abs * @delta / 100.0 @unit = '%' self end # @private def matches?(actual) @actual = actual raise needs_expected unless defined? @expected numeric? && (@actual - @expected).abs <= @tolerance end # @api private # @return [String] def failure_message "expected #{actual_formatted} to #{description}#{not_numeric_clause}" end # @api private # @return [String] def failure_message_when_negated "expected #{actual_formatted} not to #{description}" end # @api private # @return [String] def description "be within #{@delta}#{@unit} of #{expected_formatted}" end private def numeric? @actual.respond_to?(:-) end def needs_expected ArgumentError.new "You must set an expected value using #of: be_within(#{@delta}).of(expected_value)" end def not_numeric_clause ", but it could not be treated as a numeric value" unless numeric? end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/change.rb000066400000000000000000000351151455770000100244710ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `change`. # Not intended to be instantiated directly. class Change < BaseMatcher # @api public # Specifies the delta of the expected change. def by(expected_delta) ChangeRelatively.new(change_details, expected_delta, :by) do |actual_delta| values_match?(expected_delta, actual_delta) end end # @api public # Specifies a minimum delta of the expected change. def by_at_least(minimum) ChangeRelatively.new(change_details, minimum, :by_at_least) do |actual_delta| actual_delta >= minimum end end # @api public # Specifies a maximum delta of the expected change. def by_at_most(maximum) ChangeRelatively.new(change_details, maximum, :by_at_most) do |actual_delta| actual_delta <= maximum end end # @api public # Specifies the new value you expect. def to(value) ChangeToValue.new(change_details, value) end # @api public # Specifies the original value. def from(value) ChangeFromValue.new(change_details, value) end # @private def matches?(event_proc) raise_block_syntax_error if block_given? perform_change(event_proc) && change_details.changed? end def does_not_match?(event_proc) raise_block_syntax_error if block_given? perform_change(event_proc) && !change_details.changed? end # @api private # @return [String] def failure_message "expected #{change_details.value_representation} to have changed, " \ "but #{positive_failure_reason}" end # @api private # @return [String] def failure_message_when_negated "expected #{change_details.value_representation} not to have changed, " \ "but #{negative_failure_reason}" end # @api private # @return [String] def description "change #{change_details.value_representation}" end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def initialize(receiver=nil, message=nil, &block) @receiver = receiver @message = message @block = block end def change_details @change_details ||= ChangeDetails.new(matcher_name, @receiver, @message, &@block) end def perform_change(event_proc) @event_proc = event_proc change_details.perform_change(event_proc) do |actual_before| # pre-compute values derived from the `before` value before the # mutation is applied, in case the specified mutation is mutation # of a single object (rather than a changing what object a method # returns). We need to cache these values before the `before` value # they are based on potentially gets mutated. @actual_before_description = description_of(actual_before) end end def raise_block_syntax_error raise SyntaxError, "Block not received by the `change` matcher. " \ "Perhaps you want to use `{ ... }` instead of do/end?" end def positive_failure_reason return "was not given a block" unless Proc === @event_proc "is still #{@actual_before_description}" end def negative_failure_reason return "was not given a block" unless Proc === @event_proc "did change from #{@actual_before_description} " \ "to #{description_of change_details.actual_after}" end end # Used to specify a relative change. # @api private class ChangeRelatively < BaseMatcher def initialize(change_details, expected_delta, relativity, &comparer) @change_details = change_details @expected_delta = expected_delta @relativity = relativity @comparer = comparer end # @private def failure_message "expected #{@change_details.value_representation} to have changed " \ "#{@relativity.to_s.tr('_', ' ')} " \ "#{description_of @expected_delta}, but #{failure_reason}" end # @private def matches?(event_proc) @event_proc = event_proc @change_details.perform_change(event_proc) && @comparer.call(@change_details.actual_delta) end # @private def does_not_match?(_event_proc) raise NotImplementedError, "`expect { }.not_to change " \ "{ }.#{@relativity}()` is not supported" end # @private def description "change #{@change_details.value_representation} " \ "#{@relativity.to_s.tr('_', ' ')} #{description_of @expected_delta}" end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def failure_reason return "was not given a block" unless Proc === @event_proc "was changed by #{description_of @change_details.actual_delta}" end end # @api private # Base class for specifying a change from and/or to specific values. class SpecificValuesChange < BaseMatcher # @private MATCH_ANYTHING = ::Object.ancestors.last def initialize(change_details, from, to) @change_details = change_details @expected_before = from @expected_after = to end # @private def matches?(event_proc) perform_change(event_proc) && @change_details.changed? && @matches_before && matches_after? end # @private def description "change #{@change_details.value_representation} #{change_description}" end # @private def failure_message return not_given_a_block_failure unless Proc === @event_proc return before_value_failure unless @matches_before return did_not_change_failure unless @change_details.changed? after_value_failure end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def perform_change(event_proc) @event_proc = event_proc @change_details.perform_change(event_proc) do |actual_before| # pre-compute values derived from the `before` value before the # mutation is applied, in case the specified mutation is mutation # of a single object (rather than a changing what object a method # returns). We need to cache these values before the `before` value # they are based on potentially gets mutated. @matches_before = values_match?(@expected_before, actual_before) @actual_before_description = description_of(actual_before) end end def matches_after? values_match?(@expected_after, @change_details.actual_after) end def before_value_failure "expected #{@change_details.value_representation} " \ "to have initially been #{description_of @expected_before}, " \ "but was #{@actual_before_description}" end def after_value_failure "expected #{@change_details.value_representation} " \ "to have changed to #{description_of @expected_after}, " \ "but is now #{description_of @change_details.actual_after}" end def did_not_change_failure "expected #{@change_details.value_representation} " \ "to have changed #{change_description}, but did not change" end def did_change_failure "expected #{@change_details.value_representation} not to have changed, but " \ "did change from #{@actual_before_description} " \ "to #{description_of @change_details.actual_after}" end def not_given_a_block_failure "expected #{@change_details.value_representation} to have changed " \ "#{change_description}, but was not given a block" end end # @api private # Used to specify a change from a specific value # (and, optionally, to a specific value). class ChangeFromValue < SpecificValuesChange def initialize(change_details, expected_before) @description_suffix = nil super(change_details, expected_before, MATCH_ANYTHING) end # @api public # Specifies the new value you expect. def to(value) @expected_after = value @description_suffix = " to #{description_of value}" self end # @private def does_not_match?(event_proc) if @description_suffix raise NotImplementedError, "`expect { }.not_to change { }.to()` " \ "is not supported" end perform_change(event_proc) && !@change_details.changed? && @matches_before end # @private def failure_message_when_negated return not_given_a_block_failure unless Proc === @event_proc return before_value_failure unless @matches_before did_change_failure end private def change_description "from #{description_of @expected_before}#{@description_suffix}" end end # @api private # Used to specify a change to a specific value # (and, optionally, from a specific value). class ChangeToValue < SpecificValuesChange def initialize(change_details, expected_after) @description_suffix = nil super(change_details, MATCH_ANYTHING, expected_after) end # @api public # Specifies the original value. def from(value) @expected_before = value @description_suffix = " from #{description_of value}" self end # @private def does_not_match?(_event_proc) raise NotImplementedError, "`expect { }.not_to change { }.to()` " \ "is not supported" end private def change_description "to #{description_of @expected_after}#{@description_suffix}" end end # @private # Encapsulates the details of the before/after values. # # Note that this class exposes the `actual_after` value, to allow the # matchers above to derive failure messages, etc from the value on demand # as needed, but it intentionally does _not_ expose the `actual_before` # value. Some usages of the `change` matcher mutate a specific object # returned by the value proc, which means that failure message snippets, # etc, which are derived from the `before` value may not be accurate if # they are lazily computed as needed. We must pre-compute them before # applying the change in the `expect` block. To ensure that all `change` # matchers do that properly, we do not expose the `actual_before` value. # Instead, matchers must pass a block to `perform_change`, which yields # the `actual_before` value before applying the change. class ChangeDetails attr_reader :actual_after UNDEFINED = Module.new.freeze def initialize(matcher_name, receiver=nil, message=nil, &block) if receiver && !message raise( ArgumentError, "`change` requires either an object and message " \ "(`change(obj, :msg)`) or a block (`change { }`). " \ "You passed an object but no message." ) end @matcher_name = matcher_name @receiver = receiver @message = message @value_proc = block # TODO: temporary measure to mute warning of access to an initialized # instance variable when a deprecated implicit block expectation # syntax is used. This may be removed once `fail` is used, and the # matcher never issues this warning. @actual_after = UNDEFINED end def value_representation @value_representation ||= if @message "`#{message_notation(@receiver, @message)}`" elsif (value_block_snippet = extract_value_block_snippet) "`#{value_block_snippet}`" else 'result' end end def perform_change(event_proc) @actual_before = evaluate_value_proc @before_hash = @actual_before.hash yield @actual_before if block_given? return false unless Proc === event_proc event_proc.call @actual_after = evaluate_value_proc @actual_hash = @actual_after.hash true end def changed? # Consider it changed if either: # # - The before/after values are unequal # - The before/after values have different hash values # # The latter case specifically handles the case when the value proc # returns the exact same object, but it has been mutated. # # Note that it is not sufficient to only check the hashes; it is # possible for two values to be unequal (and of different classes) # but to return the same hash value. Also, some objects may change # their hash after being compared with `==`/`!=`. @actual_before != @actual_after || @before_hash != @actual_hash end def actual_delta @actual_after - @actual_before end private def evaluate_value_proc @value_proc ? @value_proc.call : @receiver.__send__(@message) end def message_notation(receiver, message) case receiver when Module "#{receiver}.#{message}" else "#{Support.class_of(receiver)}##{message}" end end if RSpec::Support::RubyFeatures.ripper_supported? def extract_value_block_snippet return nil unless @value_proc Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@value_proc, @matcher_name) end else def extract_value_block_snippet nil end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/compound.rb000066400000000000000000000221151455770000100250640ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Base class for `and` and `or` compound matchers. class Compound < BaseMatcher # @private attr_reader :matcher_1, :matcher_2, :evaluator def initialize(matcher_1, matcher_2) @matcher_1 = matcher_1 @matcher_2 = matcher_2 end # @private def does_not_match?(_actual) raise NotImplementedError, "`expect(...).not_to matcher.#{conjunction} matcher` " \ "is not supported, since it creates a bit of an ambiguity. Instead, define negated versions " \ "of whatever matchers you wish to negate with `RSpec::Matchers.define_negated_matcher` and " \ "use `expect(...).to matcher.#{conjunction} matcher`." end # @api private # @return [String] def description "#{matcher_1.description} #{conjunction} #{matcher_2.description}" end # @api private def supports_block_expectations? matcher_supports_block_expectations?(matcher_1) && matcher_supports_block_expectations?(matcher_2) end # @api private def supports_value_expectations? matcher_supports_value_expectations?(matcher_1) && matcher_supports_value_expectations?(matcher_2) end # @api private def expects_call_stack_jump? NestedEvaluator.matcher_expects_call_stack_jump?(matcher_1) || NestedEvaluator.matcher_expects_call_stack_jump?(matcher_2) end # @api private # @return [Boolean] def diffable? matcher_is_diffable?(matcher_1) || matcher_is_diffable?(matcher_2) end # @api private # @return [RSpec::Matchers::MultiMatcherDiff] def expected return nil unless evaluator ::RSpec::Matchers::MultiMatcherDiff.for_many_matchers(diffable_matcher_list) end protected def diffable_matcher_list list = [] list.concat(diffable_matcher_list_for(matcher_1)) unless matcher_1_matches? list.concat(diffable_matcher_list_for(matcher_2)) unless matcher_2_matches? list end private def initialize_copy(other) @matcher_1 = @matcher_1.clone @matcher_2 = @matcher_2.clone super end def match(_expected, actual) evaluator_klass = if supports_block_expectations? && Proc === actual NestedEvaluator else SequentialEvaluator end @evaluator = evaluator_klass.new(actual, matcher_1, matcher_2) end def indent_multiline_message(message) message.lines.map do |line| line =~ /\S/ ? ' ' + line : line end.join end def compound_failure_message "#{indent_multiline_message(matcher_1.failure_message.sub(/\n+\z/, ''))}" \ "\n\n...#{conjunction}:" \ "\n\n#{indent_multiline_message(matcher_2.failure_message.sub(/\A\n+/, ''))}" end def matcher_1_matches? evaluator.matcher_matches?(matcher_1) end def matcher_2_matches? evaluator.matcher_matches?(matcher_2) end def matcher_supports_block_expectations?(matcher) matcher.supports_block_expectations? rescue NoMethodError false end def matcher_supports_value_expectations?(matcher) matcher.supports_value_expectations? rescue NoMethodError true end def matcher_is_diffable?(matcher) matcher.diffable? rescue NoMethodError false end def diffable_matcher_list_for(matcher) return [] unless matcher_is_diffable?(matcher) return matcher.diffable_matcher_list if Compound === matcher [matcher] end # For value expectations, we can evaluate the matchers sequentially. class SequentialEvaluator def initialize(actual, *) @actual = actual end def matcher_matches?(matcher) matcher.matches?(@actual) end end # Normally, we evaluate the matching sequentially. For an expression like # `expect(x).to foo.and bar`, this becomes: # # expect(x).to foo # expect(x).to bar # # For block expectations, we need to nest them instead, so that # `expect { x }.to foo.and bar` becomes: # # expect { # expect { x }.to foo # }.to bar # # This is necessary so that the `expect` block is only executed once. class NestedEvaluator def initialize(actual, matcher_1, matcher_2) @actual = actual @matcher_1 = matcher_1 @matcher_2 = matcher_2 @match_results = {} inner, outer = order_block_matchers @match_results[outer] = outer.matches?(Proc.new do |*args| @match_results[inner] = inner.matches?(inner_matcher_block(args)) end) end def matcher_matches?(matcher) @match_results.fetch(matcher) do raise ArgumentError, "Your #{matcher.description} has no match " \ "results, this can occur when an unexpected call stack or " \ "local jump occurs. Perhaps one of your matchers needs to " \ "declare `expects_call_stack_jump?` as `true`?" end end private # Some block matchers (such as `yield_xyz`) pass args to the `expect` block. # When such a matcher is used as the outer matcher, we need to forward the # the args on to the `expect` block. def inner_matcher_block(outer_args) return @actual if outer_args.empty? Proc.new do |*inner_args| unless inner_args.empty? raise ArgumentError, "(#{@matcher_1.description}) and " \ "(#{@matcher_2.description}) cannot be combined in a compound expectation " \ "since both matchers pass arguments to the block." end @actual.call(*outer_args) end end # For a matcher like `raise_error` or `throw_symbol`, where the block will jump # up the call stack, we need to order things so that it is the inner matcher. # For example, we need it to be this: # # expect { # expect { # x += 1 # raise "boom" # }.to raise_error("boom") # }.to change { x }.by(1) # # ...rather than: # # expect { # expect { # x += 1 # raise "boom" # }.to change { x }.by(1) # }.to raise_error("boom") # # In the latter case, the after-block logic in the `change` matcher would never # get executed because the `raise "boom"` line would jump to the `rescue` in the # `raise_error` logic, so only the former case will work properly. # # This method figures out which matcher should be the inner matcher and which # should be the outer matcher. def order_block_matchers return @matcher_1, @matcher_2 unless self.class.matcher_expects_call_stack_jump?(@matcher_2) return @matcher_2, @matcher_1 unless self.class.matcher_expects_call_stack_jump?(@matcher_1) raise ArgumentError, "(#{@matcher_1.description}) and " \ "(#{@matcher_2.description}) cannot be combined in a compound expectation " \ "because they both expect a call stack jump." end def self.matcher_expects_call_stack_jump?(matcher) matcher.expects_call_stack_jump? rescue NoMethodError false end end # @api public # Matcher used to represent a compound `and` expectation. class And < self # @api private # @return [String] def failure_message if matcher_1_matches? matcher_2.failure_message elsif matcher_2_matches? matcher_1.failure_message else compound_failure_message end end private def match(*) super matcher_1_matches? && matcher_2_matches? end def conjunction "and" end end # @api public # Matcher used to represent a compound `or` expectation. class Or < self # @api private # @return [String] def failure_message compound_failure_message end private def match(*) super matcher_1_matches? || matcher_2_matches? end def conjunction "or" end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/contain_exactly.rb000066400000000000000000000262101455770000100264240ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # rubocop:disable Metrics/ClassLength # @api private # Provides the implementation for `contain_exactly` and `match_array`. # Not intended to be instantiated directly. class ContainExactly < BaseMatcher # @api private # @return [String] def failure_message if Array === actual generate_failure_message else "expected a collection that can be converted to an array with " \ "`#to_ary` or `#to_a`, but got #{actual_formatted}" end end # @api private # @return [String] def failure_message_when_negated list = EnglishPhrasing.list(surface_descriptions_in(expected)) "expected #{actual_formatted} not to contain exactly#{list}" end # @api private # @return [String] def description list = EnglishPhrasing.list(surface_descriptions_in(expected)) "contain exactly#{list}" end def matches?(actual) @pairings_maximizer = nil @best_solution = nil @extra_items = nil @missing_items = nil super(actual) end private def generate_failure_message message = expected_collection_line message += actual_collection_line message += missing_elements_line unless missing_items.empty? message += extra_elements_line unless extra_items.empty? message end def expected_collection_line message_line('expected collection contained', expected, true) end def actual_collection_line message_line('actual collection contained', actual) end def missing_elements_line message_line('the missing elements were', missing_items, true) end def extra_elements_line message_line('the extra elements were', extra_items) end def describe_collection(collection, surface_descriptions=false) if surface_descriptions "#{description_of(safe_sort(surface_descriptions_in collection))}\n" else "#{description_of(safe_sort(collection))}\n" end end def message_line(prefix, collection, surface_descriptions=false) "%-32s%s" % [prefix + ':', describe_collection(collection, surface_descriptions)] end def match(_expected, _actual) return false unless convert_actual_to_an_array match_when_sorted? || (extra_items.empty? && missing_items.empty?) end # This cannot always work (e.g. when dealing with unsortable items, # or matchers as expected items), but it's practically free compared to # the slowness of the full matching algorithm, and in common cases this # works, so it's worth a try. def match_when_sorted? values_match?(safe_sort(expected), safe_sort(actual)) end def convert_actual_to_an_array if actual.respond_to?(:to_ary) @actual = actual.to_ary elsif actual.respond_to?(:to_a) && !to_a_disallowed?(actual) @actual = actual.to_a else false end end def safe_sort(array) array.sort rescue Support::AllExceptionsExceptOnesWeMustNotRescue array end if RUBY_VERSION == "1.8.7" def to_a_disallowed?(object) case object when NilClass, String then true else Kernel == RSpec::Support.method_handle_for(object, :to_a).owner end end else def to_a_disallowed?(object) NilClass === object end end def missing_items @missing_items ||= best_solution.unmatched_expected_indexes.map do |index| expected[index] end end def extra_items @extra_items ||= best_solution.unmatched_actual_indexes.map do |index| actual[index] end end def best_solution @best_solution ||= pairings_maximizer.find_best_solution end def pairings_maximizer @pairings_maximizer ||= begin expected_matches = Hash[Array.new(expected.size) { |i| [i, []] }] actual_matches = Hash[Array.new(actual.size) { |i| [i, []] }] expected.each_with_index do |e, ei| actual.each_with_index do |a, ai| next unless values_match?(e, a) expected_matches[ei] << ai actual_matches[ai] << ei end end PairingsMaximizer.new(expected_matches, actual_matches) end end # Once we started supporting composing matchers, the algorithm for this matcher got # much more complicated. Consider this expression: # # expect(["fool", "food"]).to contain_exactly(/foo/, /fool/) # # This should pass (because we can pair /fool/ with "fool" and /foo/ with "food"), but # the original algorithm used by this matcher would pair the first elements it could # (/foo/ with "fool"), which would leave /fool/ and "food" unmatched. When we have # an expected element which is a matcher that matches a superset of actual items # compared to another expected element matcher, we need to consider every possible pairing. # # This class is designed to maximize the number of actual/expected pairings -- or, # conversely, to minimize the number of unpaired items. It's essentially a brute # force solution, but with a few heuristics applied to reduce the size of the # problem space: # # * Any items which match none of the items in the other list are immediately # placed into the `unmatched_expected_indexes` or `unmatched_actual_indexes` array. # The extra items and missing items in the matcher failure message are derived # from these arrays. # * Any items which reciprocally match only each other are paired up and not # considered further. # # What's left is only the items which match multiple items from the other list # (or vice versa). From here, it performs a brute-force depth-first search, # looking for a solution which pairs all elements in both lists, or, barring that, # that produces the fewest unmatched items. # # @private class PairingsMaximizer # @private Solution = Struct.new(:unmatched_expected_indexes, :unmatched_actual_indexes, :indeterminate_expected_indexes, :indeterminate_actual_indexes) do def worse_than?(other) unmatched_item_count > other.unmatched_item_count end def candidate? indeterminate_expected_indexes.empty? && indeterminate_actual_indexes.empty? end def ideal? candidate? && ( unmatched_expected_indexes.empty? || unmatched_actual_indexes.empty? ) end def unmatched_item_count unmatched_expected_indexes.count + unmatched_actual_indexes.count end def +(derived_candidate_solution) self.class.new( unmatched_expected_indexes + derived_candidate_solution.unmatched_expected_indexes, unmatched_actual_indexes + derived_candidate_solution.unmatched_actual_indexes, # Ignore the indeterminate indexes: by the time we get here, # we've dealt with all indeterminates. [], [] ) end end attr_reader :expected_to_actual_matched_indexes, :actual_to_expected_matched_indexes, :solution def initialize(expected_to_actual_matched_indexes, actual_to_expected_matched_indexes) @expected_to_actual_matched_indexes = expected_to_actual_matched_indexes @actual_to_expected_matched_indexes = actual_to_expected_matched_indexes unmatched_expected_indexes, indeterminate_expected_indexes = categorize_indexes(expected_to_actual_matched_indexes, actual_to_expected_matched_indexes) unmatched_actual_indexes, indeterminate_actual_indexes = categorize_indexes(actual_to_expected_matched_indexes, expected_to_actual_matched_indexes) @solution = Solution.new(unmatched_expected_indexes, unmatched_actual_indexes, indeterminate_expected_indexes, indeterminate_actual_indexes) end def find_best_solution return solution if solution.candidate? best_solution_so_far = NullSolution expected_index = solution.indeterminate_expected_indexes.first actuals = expected_to_actual_matched_indexes[expected_index] actuals.each do |actual_index| solution = best_solution_for_pairing(expected_index, actual_index) return solution if solution.ideal? best_solution_so_far = solution if best_solution_so_far.worse_than?(solution) end best_solution_so_far end private # @private # Starting solution that is worse than any other real solution. NullSolution = Class.new do def self.worse_than?(_other) true end end def categorize_indexes(indexes_to_categorize, other_indexes) unmatched = [] indeterminate = [] indexes_to_categorize.each_pair do |index, matches| if matches.empty? unmatched << index elsif !reciprocal_single_match?(matches, index, other_indexes) indeterminate << index end end return unmatched, indeterminate end def reciprocal_single_match?(matches, index, other_list) return false unless matches.one? other_list[matches.first] == [index] end def best_solution_for_pairing(expected_index, actual_index) modified_expecteds = apply_pairing_to( solution.indeterminate_expected_indexes, expected_to_actual_matched_indexes, actual_index) modified_expecteds.delete(expected_index) modified_actuals = apply_pairing_to( solution.indeterminate_actual_indexes, actual_to_expected_matched_indexes, expected_index) modified_actuals.delete(actual_index) solution + self.class.new(modified_expecteds, modified_actuals).find_best_solution end def apply_pairing_to(indeterminates, original_matches, other_list_index) indeterminates.inject({}) do |accum, index| accum[index] = original_matches[index] - [other_list_index] accum end end end end # rubocop:enable Metrics/ClassLength end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/count_expectation.rb000066400000000000000000000117671455770000100270060ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Abstract class to implement `once`, `at_least` and other # count constraints. module CountExpectation # @api public # Specifies that the method is expected to match once. def once exactly(1) end # @api public # Specifies that the method is expected to match twice. def twice exactly(2) end # @api public # Specifies that the method is expected to match thrice. def thrice exactly(3) end # @api public # Specifies that the method is expected to match the given number of times. def exactly(number) set_expected_count(:==, number) self end # @api public # Specifies the maximum number of times the method is expected to match def at_most(number) set_expected_count(:<=, number) self end # @api public # Specifies the minimum number of times the method is expected to match def at_least(number) set_expected_count(:>=, number) self end # @api public # No-op. Provides syntactic sugar. def times self end protected # @api private attr_reader :count_expectation_type, :expected_count private if RUBY_VERSION.to_f > 1.8 def cover?(count, number) count.cover?(number) end else def cover?(count, number) number >= count.first && number <= count.last end end def expected_count_matches?(actual_count) @actual_count = actual_count return @actual_count > 0 unless count_expectation_type return cover?(expected_count, actual_count) if count_expectation_type == :<=> @actual_count.__send__(count_expectation_type, expected_count) end def has_expected_count? !!count_expectation_type end def set_expected_count(relativity, n) raise_unsupported_count_expectation if unsupported_count_expectation?(relativity) count = count_constraint_to_number(n) if count_expectation_type == :<= && relativity == :>= raise_impossible_count_expectation(count) if count > expected_count @count_expectation_type = :<=> @expected_count = count..expected_count elsif count_expectation_type == :>= && relativity == :<= raise_impossible_count_expectation(count) if count < expected_count @count_expectation_type = :<=> @expected_count = expected_count..count else @count_expectation_type = relativity @expected_count = count end end def raise_impossible_count_expectation(count) text = case count_expectation_type when :<= then "at_least(#{count}).at_most(#{expected_count})" when :>= then "at_least(#{expected_count}).at_most(#{count})" end raise ArgumentError, "The constraint #{text} is not possible" end def raise_unsupported_count_expectation text = case count_expectation_type when :<= then "at_least" when :>= then "at_most" when :<=> then "at_least/at_most combination" else "count" end raise ArgumentError, "Multiple #{text} constraints are not supported" end def count_constraint_to_number(n) case n when Numeric then n when :once then 1 when :twice then 2 when :thrice then 3 else raise ArgumentError, "Expected a number, :once, :twice or :thrice," \ " but got #{n}" end end def unsupported_count_expectation?(relativity) return true if count_expectation_type == :== return true if count_expectation_type == :<=> (count_expectation_type == :<= && relativity == :<=) || (count_expectation_type == :>= && relativity == :>=) end def count_expectation_description "#{human_readable_expectation_type}#{human_readable_count(expected_count)}" end def count_failure_reason(action) "#{count_expectation_description}" \ " but #{action}#{human_readable_count(@actual_count)}" end def human_readable_expectation_type case count_expectation_type when :<= then ' at most' when :>= then ' at least' when :<=> then ' between' else '' end end def human_readable_count(count) case count when Range then " #{count.first} and #{count.last} times" when nil then '' when 1 then ' once' when 2 then ' twice' else " #{count} times" end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/cover.rb000066400000000000000000000010421455770000100243520ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `cover`. # Not intended to be instantiated directly. class Cover < BaseMatcher def initialize(*expected) @expected = expected end def matches?(range) @actual = range @expected.all? { |e| range.cover?(e) } end def does_not_match?(range) @actual = range expected.none? { |e| range.cover?(e) } end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/eq.rb000066400000000000000000000022321455770000100236430ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `eq`. # Not intended to be instantiated directly. class Eq < BaseMatcher # @api private # @return [String] def failure_message if string_encoding_differs? "\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using ==)\n" else "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n" end end # @api private # @return [String] def failure_message_when_negated "\nexpected: value != #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n" end # @api private # @return [String] def description "eq #{expected_formatted}" end # @api private # @return [Boolean] def diffable? true end private def match(expected, actual) actual == expected end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/eql.rb000066400000000000000000000020501455770000100240150ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `eql`. # Not intended to be instantiated directly. class Eql < BaseMatcher # @api private # @return [String] def failure_message if string_encoding_differs? "\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using eql?)\n" else "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n" end end # @api private # @return [String] def failure_message_when_negated "\nexpected: value != #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n" end # @api private # @return [Boolean] def diffable? true end private def match(expected, actual) actual.eql? expected end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/equal.rb000066400000000000000000000035711455770000100243540ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `equal`. # Not intended to be instantiated directly. class Equal < BaseMatcher # @api private # @return [String] def failure_message if expected_is_a_literal_singleton? simple_failure_message else detailed_failure_message end end # @api private # @return [String] def failure_message_when_negated <<-MESSAGE expected not #{inspect_object(actual)} got #{inspect_object(expected)} Compared using equal?, which compares object identity. MESSAGE end # @api private # @return [Boolean] def diffable? !expected_is_a_literal_singleton? end private def match(expected, actual) actual.equal? expected end LITERAL_SINGLETONS = [true, false, nil] def expected_is_a_literal_singleton? LITERAL_SINGLETONS.include?(expected) end def actual_inspected if LITERAL_SINGLETONS.include?(actual) actual_formatted else inspect_object(actual) end end def simple_failure_message "\nexpected #{expected_formatted}\n got #{actual_inspected}\n" end def detailed_failure_message <<-MESSAGE expected #{inspect_object(expected)} got #{inspect_object(actual)} Compared using equal?, which compares object identity, but expected and actual are not the same object. Use `expect(actual).to eq(expected)` if you don't care about object identity in this example. MESSAGE end def inspect_object(o) "#<#{o.class}:#{o.object_id}> => #{RSpec::Support::ObjectFormatter.format(o)}" end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/exist.rb000066400000000000000000000050641455770000100244000ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `exist`. # Not intended to be instantiated directly. class Exist < BaseMatcher def initialize(*expected) @expected = expected end # @api private # @return [Boolean] def matches?(actual) @actual = actual @test = ExistenceTest.new @actual, @expected @test.valid_test? && @test.actual_exists? end # @api private # @return [Boolean] def does_not_match?(actual) @actual = actual @test = ExistenceTest.new @actual, @expected @test.valid_test? && !@test.actual_exists? end # @api private # @return [String] def failure_message "expected #{actual_formatted} to exist#{@test.validity_message}" end # @api private # @return [String] def failure_message_when_negated "expected #{actual_formatted} not to exist#{@test.validity_message}" end # @api private # Simple class for memoizing actual/expected for this matcher # and examining the match class ExistenceTest < Struct.new(:actual, :expected) # @api private # @return [Boolean] def valid_test? uniq_truthy_values.size == 1 end # @api private # @return [Boolean] def actual_exists? existence_values.first end # @api private # @return [String] def validity_message case uniq_truthy_values.size when 0 " but it does not respond to either `exist?` or `exists?`" when 2 " but `exist?` and `exists?` returned different values:\n\n"\ " exist?: #{existence_values.first}\n"\ "exists?: #{existence_values.last}" end end private def uniq_truthy_values @uniq_truthy_values ||= existence_values.map { |v| !!v }.uniq end def existence_values @existence_values ||= predicates.map { |p| actual.__send__(p, *expected) } end def predicates @predicates ||= [:exist?, :exists?].select { |p| actual.respond_to?(p) && !deprecated(p, actual) } end def deprecated(predicate, actual) predicate == :exists? && (File == actual || FileTest == actual || Dir == actual) end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/has.rb000066400000000000000000000112461455770000100240160ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for dynamic predicate matchers. # Not intended to be inherited directly. class DynamicPredicate < BaseMatcher include BeHelpers def initialize(method_name, *args, &block) @method_name, @args, @block = method_name, args, block end ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true) # @private def matches?(actual, &block) @actual = actual @block ||= block predicate_accessible? && predicate_matches? end # @private def does_not_match?(actual, &block) @actual = actual @block ||= block predicate_accessible? && predicate_matches?(false) end # @api private # @return [String] def failure_message failure_message_expecting(true) end # @api private # @return [String] def failure_message_when_negated failure_message_expecting(false) end # @api private # @return [String] def description "#{method_description}#{args_to_sentence}" end private def predicate_accessible? @actual.respond_to? predicate end # support 1.8.7, evaluate once at load time for performance if String === methods.first # :nocov: def private_predicate? @actual.private_methods.include? predicate.to_s end # :nocov: else def private_predicate? @actual.private_methods.include? predicate end end def predicate_result @predicate_result = actual.__send__(predicate_method_name, *@args, &@block) end def predicate_method_name predicate end def predicate_matches?(value=true) if RSpec::Expectations.configuration.strict_predicate_matchers? value == predicate_result else value == !!predicate_result end end def root # On 1.9, there appears to be a bug where String#match can return `false` # rather than the match data object. Changing to Regex#match appears to # work around this bug. For an example of this bug, see: # https://travis-ci.org/rspec/rspec-expectations/jobs/27549635 self.class::REGEX.match(@method_name.to_s).captures.first end def method_description EnglishPhrasing.split_words(@method_name) end def failure_message_expecting(value) validity_message || "expected `#{actual_formatted}.#{predicate}#{args_to_s}` to #{expectation_of value}, got #{description_of @predicate_result}" end def expectation_of(value) if RSpec::Expectations.configuration.strict_predicate_matchers? "return #{value}" elsif value "be truthy" else "be falsey" end end def validity_message return nil if predicate_accessible? "expected #{actual_formatted} to respond to `#{predicate}`#{failure_to_respond_explanation}" end def failure_to_respond_explanation if private_predicate? " but `#{predicate}` is a private method" end end end # @api private # Provides the implementation for `has_`. # Not intended to be instantiated directly. class Has < DynamicPredicate # :nodoc: REGEX = Matchers::HAS_REGEX private def predicate @predicate ||= :"has_#{root}?" end end # @api private # Provides the implementation of `be_`. # Not intended to be instantiated directly. class BePredicate < DynamicPredicate # :nodoc: REGEX = Matchers::BE_PREDICATE_REGEX private def predicate @predicate ||= :"#{root}?" end def predicate_method_name actual.respond_to?(predicate) ? predicate : present_tense_predicate end def failure_to_respond_explanation super || if predicate == :true? " or perhaps you meant `be true` or `be_truthy`" elsif predicate == :false? " or perhaps you meant `be false` or `be_falsey`" end end def predicate_accessible? super || actual.respond_to?(present_tense_predicate) end def present_tense_predicate :"#{root}s?" end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/have_attributes.rb000066400000000000000000000061651455770000100264400ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `have_attributes`. # Not intended to be instantiated directly. class HaveAttributes < BaseMatcher # @private attr_reader :respond_to_failed def initialize(expected) @expected = expected @values = {} @respond_to_failed = false @negated = false end # @private def actual @values end # @api private # @return [Boolean] def matches?(actual) @actual = actual @negated = false return false unless respond_to_attributes? perform_match(:all?) end # @api private # @return [Boolean] def does_not_match?(actual) @actual = actual @negated = true return false unless respond_to_attributes? perform_match(:none?) end # @api private # @return [String] def description described_items = surface_descriptions_in(expected) improve_hash_formatting "have attributes #{RSpec::Support::ObjectFormatter.format(described_items)}" end # @api private # @return [Boolean] def diffable? !@respond_to_failed && !@negated end # @api private # @return [String] def failure_message respond_to_failure_message_or do "expected #{actual_formatted} to #{description} but had attributes #{ formatted_values }" end end # @api private # @return [String] def failure_message_when_negated respond_to_failure_message_or { "expected #{actual_formatted} not to #{description}" } end private def cache_all_values @values = {} expected.each do |attribute_key, _attribute_value| actual_value = @actual.__send__(attribute_key) @values[attribute_key] = actual_value end end def perform_match(predicate) cache_all_values expected.__send__(predicate) do |attribute_key, attribute_value| actual_has_attribute?(attribute_key, attribute_value) end end def actual_has_attribute?(attribute_key, attribute_value) values_match?(attribute_value, @values.fetch(attribute_key)) end def respond_to_attributes? matches = respond_to_matcher.matches?(@actual) @respond_to_failed = !matches matches end def respond_to_matcher @respond_to_matcher ||= RespondTo.new(*expected.keys).with(0).arguments.tap { |m| m.ignoring_method_signature_failure! } end def respond_to_failure_message_or if respond_to_failed respond_to_matcher.failure_message else improve_hash_formatting(yield) end end def formatted_values values = RSpec::Support::ObjectFormatter.format(@values) improve_hash_formatting(values) end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/include.rb000066400000000000000000000146761455770000100247000ustar00rootroot00000000000000require 'rspec/matchers/built_in/count_expectation' module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `include`. # Not intended to be instantiated directly. class Include < BaseMatcher # rubocop:disable Metrics/ClassLength include CountExpectation # @private attr_reader :expecteds # @api private def initialize(*expecteds) @expecteds = expecteds end # @api private # @return [Boolean] def matches?(actual) check_actual?(actual) && if check_expected_count? expected_count_matches?(count_inclusions) else perform_match { |v| v } end end # @api private # @return [Boolean] def does_not_match?(actual) check_actual?(actual) && if check_expected_count? !expected_count_matches?(count_inclusions) else perform_match { |v| !v } end end # @api private # @return [String] def description improve_hash_formatting("include#{readable_list_of(expecteds)}#{count_expectation_description}") end # @api private # @return [String] def failure_message format_failure_message("to") { super } end # @api private # @return [String] def failure_message_when_negated format_failure_message("not to") { super } end # @api private # @return [Boolean] def diffable? !diff_would_wrongly_highlight_matched_item? end # @api private # @return [Array, Hash] def expected if expecteds.one? && Hash === expecteds.first expecteds.first else expecteds end end private def check_actual?(actual) actual = actual.to_hash if convert_to_hash?(actual) @actual = actual @actual.respond_to?(:include?) end def check_expected_count? case when !has_expected_count? return false when expecteds.size != 1 raise NotImplementedError, 'Count constraint supported only when testing for a single value being included' when actual.is_a?(Hash) raise NotImplementedError, 'Count constraint on hash keys not implemented' end true end def format_failure_message(preposition) msg = if actual.respond_to?(:include?) "expected #{description_of @actual} #{preposition}" \ " include#{readable_list_of @divergent_items}" \ "#{count_failure_reason('it is included') if has_expected_count?}" else "#{yield}, but it does not respond to `include?`" end improve_hash_formatting(msg) end def readable_list_of(items) described_items = surface_descriptions_in(items) if described_items.all? { |item| item.is_a?(Hash) } " #{described_items.inject(:merge).inspect}" else EnglishPhrasing.list(described_items) end end def perform_match(&block) @divergent_items = excluded_from_actual(&block) @divergent_items.empty? end def excluded_from_actual return [] unless @actual.respond_to?(:include?) expecteds.inject([]) do |memo, expected_item| if comparing_hash_to_a_subset?(expected_item) expected_item.each do |(key, value)| memo << { key => value } unless yield actual_hash_includes?(key, value) end elsif comparing_hash_keys?(expected_item) memo << expected_item unless yield actual_hash_has_key?(expected_item) else memo << expected_item unless yield actual_collection_includes?(expected_item) end memo end end def comparing_hash_to_a_subset?(expected_item) actual.is_a?(Hash) && expected_item.is_a?(Hash) end def actual_hash_includes?(expected_key, expected_value) actual_value = actual.fetch(expected_key) do actual.find(Proc.new { return false }) { |actual_key, _| values_match?(expected_key, actual_key) }[1] end values_match?(expected_value, actual_value) end def comparing_hash_keys?(expected_item) actual.is_a?(Hash) && !expected_item.is_a?(Hash) end def actual_hash_has_key?(expected_key) # We check `key?` first for perf: # `key?` is O(1), but `any?` is O(N). has_exact_key = begin actual.key?(expected_key) rescue false end has_exact_key || actual.keys.any? { |key| values_match?(expected_key, key) } end def actual_collection_includes?(expected_item) return true if actual.include?(expected_item) # String lacks an `any?` method... return false unless actual.respond_to?(:any?) actual.any? { |value| values_match?(expected_item, value) } end if RUBY_VERSION < '1.9' def count_enumerable(expected_item) actual.select { |value| values_match?(expected_item, value) }.size end else def count_enumerable(expected_item) actual.count { |value| values_match?(expected_item, value) } end end def count_inclusions @divergent_items = expected case actual when String actual.scan(expected.first).length when Enumerable count_enumerable(Hash === expected ? expected : expected.first) else raise NotImplementedError, 'Count constraints are implemented for Enumerable and String values only' end end def diff_would_wrongly_highlight_matched_item? return false unless actual.is_a?(String) && expected.is_a?(Array) lines = actual.split("\n") expected.any? do |str| actual.include?(str) && lines.none? { |line| line == str } end end def convert_to_hash?(obj) !obj.respond_to?(:include?) && obj.respond_to?(:to_hash) end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/match.rb000066400000000000000000000056711455770000100243440ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `match`. # Not intended to be instantiated directly. class Match < BaseMatcher def initialize(expected) super(expected) @expected_captures = nil end # @api private # @return [String] def description if @expected_captures && @expected.match(actual) "match #{surface_descriptions_in(expected).inspect} with captures #{surface_descriptions_in(@expected_captures).inspect}" else "match #{surface_descriptions_in(expected).inspect}" end end # @api private # @return [Boolean] def diffable? true end # Used to specify the captures we match against # @return [self] def with_captures(*captures) @expected_captures = captures self end private def match(expected, actual) return match_captures(expected, actual) if @expected_captures return true if values_match?(expected, actual) return false unless can_safely_call_match?(expected, actual) actual.match(expected) end def can_safely_call_match?(expected, actual) return false unless actual.respond_to?(:match) !(RSpec::Matchers.is_a_matcher?(expected) && (String === actual || Regexp === actual)) end def match_captures(expected, actual) match = actual.match(expected) if match match = ReliableMatchData.new(match) if match.names.empty? values_match?(@expected_captures, match.captures) else expected_matcher = @expected_captures.last values_match?(expected_matcher, Hash[match.names.zip(match.captures)]) || values_match?(expected_matcher, Hash[match.names.map(&:to_sym).zip(match.captures)]) || values_match?(@expected_captures, match.captures) end else false end end end # @api private # Used to wrap match data and make it reliable for 1.8.7 class ReliableMatchData def initialize(match_data) @match_data = match_data end if RUBY_VERSION == "1.8.7" # @api private # Returns match data names for named captures # @return Array def names [] end else # @api private # Returns match data names for named captures # @return Array def names match_data.names end end # @api private # returns an array of captures from the match data # @return Array def captures match_data.captures end protected attr_reader :match_data end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/operators.rb000066400000000000000000000104111455770000100252520ustar00rootroot00000000000000require 'rspec/support' module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for operator matchers. # Not intended to be instantiated directly. # Only available for use with `should`. class OperatorMatcher class << self # @private def registry @registry ||= {} end # @private def register(klass, operator, matcher) registry[klass] ||= {} registry[klass][operator] = matcher end # @private def unregister(klass, operator) registry[klass] && registry[klass].delete(operator) end # @private def get(klass, operator) klass.ancestors.each do |ancestor| matcher = registry[ancestor] && registry[ancestor][operator] return matcher if matcher end nil end end register Enumerable, '=~', BuiltIn::ContainExactly def initialize(actual) @actual = actual end # @private def self.use_custom_matcher_or_delegate(operator) define_method(operator) do |expected| if !has_non_generic_implementation_of?(operator) && (matcher = OperatorMatcher.get(@actual.class, operator)) @actual.__send__(::RSpec::Matchers.last_expectation_handler.should_method, matcher.new(expected)) else eval_match(@actual, operator, expected) end end negative_operator = operator.sub(/^=/, '!') if negative_operator != operator && respond_to?(negative_operator) define_method(negative_operator) do |_expected| opposite_should = ::RSpec::Matchers.last_expectation_handler.opposite_should_method raise "RSpec does not support `#{::RSpec::Matchers.last_expectation_handler.should_method} #{negative_operator} expected`. " \ "Use `#{opposite_should} #{operator} expected` instead." end end end ['==', '===', '=~', '>', '>=', '<', '<='].each do |operator| use_custom_matcher_or_delegate operator end # @private def fail_with_message(message) RSpec::Expectations.fail_with(message, @expected, @actual) end # @api private # @return [String] def description "#{@operator} #{RSpec::Support::ObjectFormatter.format(@expected)}" end private def has_non_generic_implementation_of?(op) Support.method_handle_for(@actual, op).owner != ::Kernel rescue NameError false end def eval_match(actual, operator, expected) ::RSpec::Matchers.last_matcher = self @operator, @expected = operator, expected __delegate_operator(actual, operator, expected) end end # @private # Handles operator matcher for `should`. class PositiveOperatorMatcher < OperatorMatcher def __delegate_operator(actual, operator, expected) if actual.__send__(operator, expected) true else expected_formatted = RSpec::Support::ObjectFormatter.format(expected) actual_formatted = RSpec::Support::ObjectFormatter.format(actual) if ['==', '===', '=~'].include?(operator) fail_with_message("expected: #{expected_formatted}\n got: #{actual_formatted} (using #{operator})") else fail_with_message("expected: #{operator} #{expected_formatted}\n got: #{operator.gsub(/./, ' ')} #{actual_formatted}") end end end end # @private # Handles operator matcher for `should_not`. class NegativeOperatorMatcher < OperatorMatcher def __delegate_operator(actual, operator, expected) return false unless actual.__send__(operator, expected) expected_formatted = RSpec::Support::ObjectFormatter.format(expected) actual_formatted = RSpec::Support::ObjectFormatter.format(actual) fail_with_message("expected not: #{operator} #{expected_formatted}\n got: #{operator.gsub(/./, ' ')} #{actual_formatted}") end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/output.rb000066400000000000000000000127041455770000100246030ustar00rootroot00000000000000require 'stringio' module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `output`. # Not intended to be instantiated directly. class Output < BaseMatcher def initialize(expected) @expected = expected @actual = "" @block = nil @stream_capturer = NullCapture end def matches?(block) @block = block return false unless Proc === block @actual = @stream_capturer.capture(block) @expected ? values_match?(@expected, @actual) : captured? end def does_not_match?(block) !matches?(block) && Proc === block end # @api public # Tells the matcher to match against stdout. # Works only when the main Ruby process prints to stdout def to_stdout @stream_capturer = CaptureStdout self end # @api public # Tells the matcher to match against stderr. # Works only when the main Ruby process prints to stderr def to_stderr @stream_capturer = CaptureStderr self end # @api public # Tells the matcher to match against stdout. # Works when subprocesses print to stdout as well. # This is significantly (~30x) slower than `to_stdout` def to_stdout_from_any_process @stream_capturer = CaptureStreamToTempfile.new("stdout", $stdout) self end # @api public # Tells the matcher to match against stderr. # Works when subprocesses print to stderr as well. # This is significantly (~30x) slower than `to_stderr` def to_stderr_from_any_process @stream_capturer = CaptureStreamToTempfile.new("stderr", $stderr) self end # @api private # @return [String] def failure_message "expected block to #{description}, but #{positive_failure_reason}" end # @api private # @return [String] def failure_message_when_negated "expected block to not #{description}, but #{negative_failure_reason}" end # @api private # @return [String] def description if @expected "output #{description_of @expected} to #{@stream_capturer.name}" else "output to #{@stream_capturer.name}" end end # @api private # @return [Boolean] def diffable? true end # @api private # Indicates this matcher matches against a block. # @return [True] def supports_block_expectations? true end # @api private # Indicates this matcher matches against a block only. # @return [False] def supports_value_expectations? false end private def captured? @actual.length > 0 end def positive_failure_reason return "was not a block" unless Proc === @block return "output #{actual_output_description}" if @expected "did not" end def negative_failure_reason return "was not a block" unless Proc === @block "output #{actual_output_description}" end def actual_output_description return "nothing" unless captured? actual_formatted end end # @private module NullCapture def self.name "some stream" end def self.capture(_block) raise "You must chain `to_stdout` or `to_stderr` off of the `output(...)` matcher." end end # @private module CaptureStdout def self.name 'stdout' end def self.capture(block) captured_stream = StringIO.new original_stream = $stdout $stdout = captured_stream block.call captured_stream.string ensure $stdout = original_stream end end # @private module CaptureStderr def self.name 'stderr' end def self.capture(block) captured_stream = StringIO.new original_stream = $stderr $stderr = captured_stream block.call captured_stream.string ensure $stderr = original_stream end end # @private class CaptureStreamToTempfile < Struct.new(:name, :stream) def capture(block) # We delay loading tempfile until it is actually needed because # we want to minimize stdlibs loaded so that users who use a # portion of the stdlib can't have passing specs while forgetting # to load it themselves. `CaptureStreamToTempfile` is rarely used # and `tempfile` pulls in a bunch of things (delegate, tmpdir, # thread, fileutils, etc), so it's worth delaying it until this point. require 'tempfile' original_stream = stream.clone captured_stream = Tempfile.new(name) begin captured_stream.sync = true stream.reopen(captured_stream) block.call captured_stream.rewind captured_stream.read ensure stream.reopen(original_stream) captured_stream.close captured_stream.unlink end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/raise_error.rb000066400000000000000000000232061455770000100255560ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `raise_error`. # Not intended to be instantiated directly. # rubocop:disable Metrics/ClassLength # rubocop:disable Lint/RescueException class RaiseError include Composable # Used as a sentinel value to be able to tell when the user did not pass an # argument. We can't use `nil` for that because we need to warn when `nil` is # passed in a different way. It's an Object, not a Module, since Module's `===` # does not evaluate to true when compared to itself. UndefinedValue = Object.new.freeze def initialize(expected_error_or_message, expected_message, &block) @block = block @actual_error = nil @warn_about_bare_error = UndefinedValue === expected_error_or_message @warn_about_nil_error = expected_error_or_message.nil? case expected_error_or_message when nil, UndefinedValue @expected_error = Exception @expected_message = expected_message when String @expected_error = Exception @expected_message = expected_error_or_message else @expected_error = expected_error_or_message @expected_message = expected_message end end # @api public # Specifies the expected error message. def with_message(expected_message) raise_message_already_set if @expected_message @warn_about_bare_error = false @expected_message = expected_message self end # rubocop:disable Metrics/MethodLength # @private def matches?(given_proc, negative_expectation=false, &block) @given_proc = given_proc @block ||= block @raised_expected_error = false @with_expected_message = false @eval_block = false @eval_block_passed = false return false unless Proc === given_proc begin given_proc.call rescue Exception => @actual_error if values_match?(@expected_error, @actual_error) || values_match?(@expected_error, actual_error_message) @raised_expected_error = true @with_expected_message = verify_message end end unless negative_expectation warn_about_bare_error! if warn_about_bare_error? warn_about_nil_error! if warn_about_nil_error? eval_block if ready_to_eval_block? end expectation_matched? end # rubocop:enable Metrics/MethodLength # @private def does_not_match?(given_proc) warn_for_negative_false_positives! !matches?(given_proc, :negative_expectation) && Proc === given_proc end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end # @private def expects_call_stack_jump? true end # @api private # @return [String] def failure_message @eval_block ? actual_error_message : "expected #{expected_error}#{given_error}" end # @api private # @return [String] def failure_message_when_negated "expected no #{expected_error}#{given_error}" end # @api private # @return [String] def description "raise #{expected_error}" end private def actual_error_message return nil unless @actual_error @actual_error.respond_to?(:original_message) ? @actual_error.original_message : @actual_error.message end def expectation_matched? error_and_message_match? && block_matches? end def error_and_message_match? @raised_expected_error && @with_expected_message end def block_matches? @eval_block ? @eval_block_passed : true end def ready_to_eval_block? @raised_expected_error && @with_expected_message && @block end def eval_block @eval_block = true begin @block[@actual_error] @eval_block_passed = true rescue Exception => err @actual_error = err end end def verify_message return true if @expected_message.nil? values_match?(@expected_message, actual_error_message.to_s) end def warn_for_negative_false_positives! expression = if expecting_specific_exception? && @expected_message "`expect { }.not_to raise_error(SpecificErrorClass, message)`" elsif expecting_specific_exception? "`expect { }.not_to raise_error(SpecificErrorClass)`" elsif @expected_message "`expect { }.not_to raise_error(message)`" elsif @warn_about_nil_error "`expect { }.not_to raise_error(nil)`" end return unless expression warn_about_negative_false_positive! expression end def handle_warning(message) RSpec::Expectations.configuration.false_positives_handler.call(message) end def warn_about_bare_error? @warn_about_bare_error && @block.nil? end def warn_about_nil_error? @warn_about_nil_error end def warn_about_bare_error! handle_warning("Using the `raise_error` matcher without providing a specific " \ "error or message risks false positives, since `raise_error` " \ "will match when Ruby raises a `NoMethodError`, `NameError` or " \ "`ArgumentError`, potentially allowing the expectation to pass " \ "without even executing the method you are intending to call. " \ "#{warning}"\ "Instead consider providing a specific error class or message. " \ "This message can be suppressed by setting: " \ "`RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end def warn_about_nil_error! handle_warning("Using the `raise_error` matcher with a `nil` error is probably " \ "unintentional, it risks false positives, since `raise_error` " \ "will match when Ruby raises a `NoMethodError`, `NameError` or " \ "`ArgumentError`, potentially allowing the expectation to pass " \ "without even executing the method you are intending to call. " \ "#{warning}"\ "Instead consider providing a specific error class or message. " \ "This message can be suppressed by setting: " \ "`RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end def warn_about_negative_false_positive!(expression) handle_warning("Using #{expression} risks false positives, since literally " \ "any other error would cause the expectation to pass, " \ "including those raised by Ruby (e.g. `NoMethodError`, `NameError` " \ "and `ArgumentError`), meaning the code you are intending to test " \ "may not even get reached. Instead consider using " \ "`expect { }.not_to raise_error` or `expect { }.to raise_error" \ "(DifferentSpecificErrorClass)`. This message can be suppressed by " \ "setting: `RSpec::Expectations.configuration.on_potential_false" \ "_positives = :nothing`") end def expected_error case @expected_message when nil if RSpec::Support.is_a_matcher?(@expected_error) "Exception with #{description_of(@expected_error)}" else description_of(@expected_error) end when Regexp "#{@expected_error} with message matching #{description_of(@expected_message)}" else "#{@expected_error} with #{description_of(@expected_message)}" end end def format_backtrace(backtrace) formatter = Matchers.configuration.backtrace_formatter formatter.format_backtrace(backtrace) end def given_error return " but was not given a block" unless Proc === @given_proc return " but nothing was raised" unless @actual_error backtrace = format_backtrace(@actual_error.backtrace) [ ", got #{description_of(@actual_error)} with backtrace:", *backtrace ].join("\n # ") end def expecting_specific_exception? @expected_error != Exception end def raise_message_already_set raise "`expect { }.to raise_error(message).with_message(message)` is not valid. " \ 'The matcher only allows the expected message to be specified once' end def warning warning = "Actual error raised was #{description_of(@actual_error)}. " warning if @actual_error end end # rubocop:enable Lint/RescueException # rubocop:enable Metrics/ClassLength end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/respond_to.rb000066400000000000000000000154161455770000100254220ustar00rootroot00000000000000RSpec::Support.require_rspec_support "method_signature_verifier" module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `respond_to`. # Not intended to be instantiated directly. class RespondTo < BaseMatcher def initialize(*names) @names = names @expected_arity = nil @expected_keywords = [] @ignoring_method_signature_failure = false @unlimited_arguments = nil @arbitrary_keywords = nil end # @api public # Specifies the number of expected arguments. # # @example # expect(obj).to respond_to(:message).with(3).arguments def with(n) @expected_arity = n self end # @api public # Specifies keyword arguments, if any. # # @example # expect(obj).to respond_to(:message).with_keywords(:color, :shape) # @example with an expected number of arguments # expect(obj).to respond_to(:message).with(3).arguments.and_keywords(:color, :shape) def with_keywords(*keywords) @expected_keywords = keywords self end alias :and_keywords :with_keywords # @api public # Specifies that the method accepts any keyword, i.e. the method has # a splatted keyword parameter of the form **kw_args. # # @example # expect(obj).to respond_to(:message).with_any_keywords def with_any_keywords @arbitrary_keywords = true self end alias :and_any_keywords :with_any_keywords # @api public # Specifies that the number of arguments has no upper limit, i.e. the # method has a splatted parameter of the form *args. # # @example # expect(obj).to respond_to(:message).with_unlimited_arguments def with_unlimited_arguments @unlimited_arguments = true self end alias :and_unlimited_arguments :with_unlimited_arguments # @api public # No-op. Intended to be used as syntactic sugar when using `with`. # # @example # expect(obj).to respond_to(:message).with(3).arguments def argument self end alias :arguments :argument # @private def matches?(actual) find_failing_method_names(actual, :reject).empty? end # @private def does_not_match?(actual) find_failing_method_names(actual, :select).empty? end # @api private # @return [String] def failure_message "expected #{actual_formatted} to respond to #{@failing_method_names.map { |name| description_of(name) }.join(', ')}#{with_arity}" end # @api private # @return [String] def failure_message_when_negated failure_message.sub(/to respond to/, 'not to respond to') end # @api private # @return [String] def description "respond to #{pp_names}#{with_arity}" end # @api private # Used by other matchers to suppress a check def ignoring_method_signature_failure! @ignoring_method_signature_failure = true end private def find_failing_method_names(actual, filter_method) @actual = actual @failing_method_names = @names.__send__(filter_method) do |name| @actual.respond_to?(name) && matches_arity?(actual, name) end end def matches_arity?(actual, name) ArityCheck.new(@expected_arity, @expected_keywords, @arbitrary_keywords, @unlimited_arguments).matches?(actual, name) rescue NameError return true if @ignoring_method_signature_failure raise ArgumentError, "The #{matcher_name} matcher requires that " \ "the actual object define the method(s) in " \ "order to check arity, but the method " \ "`#{name}` is not defined. Remove the arity " \ "check or define the method to continue." end def with_arity str = ''.dup str << " with #{with_arity_string}" if @expected_arity str << " #{str.length == 0 ? 'with' : 'and'} #{with_keywords_string}" if @expected_keywords && @expected_keywords.count > 0 str << " #{str.length == 0 ? 'with' : 'and'} unlimited arguments" if @unlimited_arguments str << " #{str.length == 0 ? 'with' : 'and'} any keywords" if @arbitrary_keywords str end def with_arity_string "#{@expected_arity} argument#{@expected_arity == 1 ? '' : 's'}" end def with_keywords_string kw_str = case @expected_keywords.count when 1 @expected_keywords.first.inspect when 2 @expected_keywords.map(&:inspect).join(' and ') else "#{@expected_keywords[0...-1].map(&:inspect).join(', ')}, and #{@expected_keywords.last.inspect}" end "keyword#{@expected_keywords.count == 1 ? '' : 's'} #{kw_str}" end def pp_names @names.length == 1 ? "##{@names.first}" : description_of(@names) end # @private class ArityCheck def initialize(expected_arity, expected_keywords, arbitrary_keywords, unlimited_arguments) expectation = Support::MethodSignatureExpectation.new if expected_arity.is_a?(Range) expectation.min_count = expected_arity.min expectation.max_count = expected_arity.max else expectation.min_count = expected_arity end expectation.keywords = expected_keywords expectation.expect_unlimited_arguments = unlimited_arguments expectation.expect_arbitrary_keywords = arbitrary_keywords @expectation = expectation end def matches?(actual, name) return true if @expectation.empty? verifier_for(actual, name).with_expectation(@expectation).valid? end def verifier_for(actual, name) Support::StrictSignatureVerifier.new(method_signature_for(actual, name)) end def method_signature_for(actual, name) method_handle = Support.method_handle_for(actual, name) if name == :new && method_handle.owner === ::Class && ::Class === actual Support::MethodSignature.new(actual.instance_method(:initialize)) else Support::MethodSignature.new(method_handle) end end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/satisfy.rb000066400000000000000000000027541455770000100247310ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `satisfy`. # Not intended to be instantiated directly. class Satisfy < BaseMatcher def initialize(description=nil, &block) @description = description @block = block end # @private def matches?(actual, &block) @block = block if block @actual = actual @block.call(actual) end # @private def description @description ||= "satisfy #{block_representation}" end # @api private # @return [String] def failure_message "expected #{actual_formatted} to #{description}" end # @api private # @return [String] def failure_message_when_negated "expected #{actual_formatted} not to #{description}" end private if RSpec::Support::RubyFeatures.ripper_supported? def block_representation if (block_snippet = extract_block_snippet) "expression `#{block_snippet}`" else 'block' end end def extract_block_snippet return nil unless @block Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@block, matcher_name) end else def block_representation 'block' end end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/start_or_end_with.rb000066400000000000000000000053341455770000100267620ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Base class for the `end_with` and `start_with` matchers. # Not intended to be instantiated directly. class StartOrEndWith < BaseMatcher def initialize(*expected) @actual_does_not_have_ordered_elements = false @expected = expected.length == 1 ? expected.first : expected end # @api private # @return [String] def failure_message super.tap do |msg| if @actual_does_not_have_ordered_elements msg << ", but it does not have ordered elements" elsif !actual.respond_to?(:[]) msg << ", but it cannot be indexed using #[]" end end end # @api private # @return [String] def description return super unless Hash === expected english_name = EnglishPhrasing.split_words(self.class.matcher_name) description_of_expected = surface_descriptions_in(expected).inspect "#{english_name} #{description_of_expected}" end private def match(_expected, actual) return false unless actual.respond_to?(:[]) begin return true if subsets_comparable? && subset_matches? element_matches? rescue ArgumentError @actual_does_not_have_ordered_elements = true return false end end def subsets_comparable? # Structs support the Enumerable interface but don't really have # the semantics of a subset of a larger set... return false if Struct === expected expected.respond_to?(:length) end end # For RSpec 3.1, the base class was named `StartAndEndWith`. For SemVer reasons, # we still provide this constant until 4.0. # @deprecated Use StartOrEndWith instead. # @private StartAndEndWith = StartOrEndWith # @api private # Provides the implementation for `start_with`. # Not intended to be instantiated directly. class StartWith < StartOrEndWith private def subset_matches? values_match?(expected, actual[0, expected.length]) end def element_matches? values_match?(expected, actual[0]) end end # @api private # Provides the implementation for `end_with`. # Not intended to be instantiated directly. class EndWith < StartOrEndWith private def subset_matches? values_match?(expected, actual[-expected.length, expected.length]) end def element_matches? values_match?(expected, actual[-1]) end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/throw_symbol.rb000066400000000000000000000077221455770000100257770ustar00rootroot00000000000000module RSpec module Matchers module BuiltIn # @api private # Provides the implementation for `throw_symbol`. # Not intended to be instantiated directly. class ThrowSymbol include Composable def initialize(expected_symbol=nil, expected_arg=nil) @expected_symbol = expected_symbol @expected_arg = expected_arg @caught_symbol = @caught_arg = nil end # rubocop:disable Metrics/MethodLength # @private def matches?(given_proc) @block = given_proc return false unless Proc === given_proc begin if @expected_symbol.nil? given_proc.call else @caught_arg = catch :proc_did_not_throw_anything do catch @expected_symbol do given_proc.call throw :proc_did_not_throw_anything, :nothing_thrown end end if @caught_arg == :nothing_thrown @caught_arg = nil else @caught_symbol = @expected_symbol end end # Ruby 1.8 uses NameError with `symbol' # Ruby 1.9 uses ArgumentError with :symbol rescue NameError, ArgumentError => e unless (match_data = e.message.match(/uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/)) other_exception = e raise end @caught_symbol = match_data.captures[1].to_sym rescue => other_exception raise ensure # rubocop:disable Lint/EnsureReturn unless other_exception if @expected_symbol.nil? return !!@caught_symbol else if @expected_arg.nil? return @caught_symbol == @expected_symbol else return (@caught_symbol == @expected_symbol) && values_match?(@expected_arg, @caught_arg) end end end # rubocop:enable Lint/EnsureReturn end end # rubocop:enable Metrics/MethodLength def does_not_match?(given_proc) !matches?(given_proc) && Proc === given_proc end # @api private # @return [String] def failure_message "expected #{expected} to be thrown, #{actual_result}" end # @api private # @return [String] def failure_message_when_negated "expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, #{actual_result}" end # @api private # @return [String] def description "throw #{expected}" end # @api private # Indicates this matcher matches against a block. # @return [True] def supports_block_expectations? true end # @api private def supports_value_expectations? false end # @api private def expects_call_stack_jump? true end private def actual_result return "but was not a block" unless Proc === @block "got #{caught}" end def expected(symbol_desc='a Symbol') throw_description(@expected_symbol || symbol_desc, @expected_arg) end def caught throw_description(@caught_symbol || 'nothing', @caught_arg) end def throw_description(symbol, arg) symbol_description = symbol.is_a?(String) ? symbol : description_of(symbol) arg_description = if arg " with #{description_of arg}" elsif @expected_arg && @caught_symbol == @expected_symbol " with no argument" else "" end symbol_description + arg_description end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/built_in/yield.rb000066400000000000000000000257431455770000100243600ustar00rootroot00000000000000require 'rspec/matchers/built_in/count_expectation' RSpec::Support.require_rspec_support 'method_signature_verifier' module RSpec module Matchers module BuiltIn # @private # Object that is yielded to `expect` when one of the # yield matchers is used. Provides information about # the yield behavior of the object-under-test. class YieldProbe def self.probe(block, &callback) probe = new(block, &callback) return probe unless probe.has_block? probe.probe end attr_accessor :num_yields, :yielded_args def initialize(block, &callback) @block = block @callback = callback || Proc.new {} @used = false self.num_yields = 0 self.yielded_args = [] end def has_block? Proc === @block end def probe assert_valid_expect_block! @block.call(self) assert_used! self end def to_proc @used = true probe = self callback = @callback Proc.new do |*args| probe.num_yields += 1 probe.yielded_args << args callback.call(*args) nil # to indicate the block does not return a meaningful value end end def single_yield_args yielded_args.first end def yielded_once?(matcher_name) case num_yields when 1 then true when 0 then false else raise "The #{matcher_name} matcher is not designed to be used with a " \ 'method that yields multiple times. Use the yield_successive_args ' \ 'matcher for that case.' end end def assert_used! return if @used raise 'You must pass the argument yielded to your expect block on ' \ 'to the method-under-test as a block. It acts as a probe that ' \ 'allows the matcher to detect whether or not the method-under-test ' \ 'yields, and, if so, how many times, and what the yielded arguments ' \ 'are.' end if RUBY_VERSION.to_f > 1.8 def assert_valid_expect_block! block_signature = RSpec::Support::BlockSignature.new(@block) return if RSpec::Support::StrictSignatureVerifier.new(block_signature, [self]).valid? raise 'Your expect block must accept an argument to be used with this ' \ 'matcher. Pass the argument as a block on to the method you are testing.' end else # :nocov: # On 1.8.7, `lambda { }.arity` and `lambda { |*a| }.arity` both return -1, # so we can't distinguish between accepting no args and an arg splat. # It's OK to skip, this, though; it just provides a nice error message # when the user forgets to accept an arg in their block. They'll still get # the `assert_used!` error message from above, which is sufficient. def assert_valid_expect_block! # nothing to do end # :nocov: end end # @api private # Provides the implementation for `yield_control`. # Not intended to be instantiated directly. class YieldControl < BaseMatcher include CountExpectation # @private def matches?(block) @probe = YieldProbe.probe(block) return false unless @probe.has_block? expected_count_matches?(@probe.num_yields) end # @private def does_not_match?(block) !matches?(block) && @probe.has_block? end # @api private # @return [String] def failure_message 'expected given block to yield control' + failure_reason end # @api private # @return [String] def failure_message_when_negated 'expected given block not to yield control' + failure_reason end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def failure_reason return ' but was not a block' unless @probe.has_block? return "#{count_expectation_description} but did not yield" if @probe.num_yields == 0 count_failure_reason('yielded') end end # @api private # Provides the implementation for `yield_with_no_args`. # Not intended to be instantiated directly. class YieldWithNoArgs < BaseMatcher # @private def matches?(block) @probe = YieldProbe.probe(block) return false unless @probe.has_block? @probe.yielded_once?(:yield_with_no_args) && @probe.single_yield_args.empty? end # @private def does_not_match?(block) !matches?(block) && @probe.has_block? end # @private def failure_message "expected given block to yield with no arguments, but #{positive_failure_reason}" end # @private def failure_message_when_negated "expected given block not to yield with no arguments, but #{negative_failure_reason}" end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def positive_failure_reason return 'was not a block' unless @probe.has_block? return 'did not yield' if @probe.num_yields.zero? "yielded with arguments: #{description_of @probe.single_yield_args}" end def negative_failure_reason return 'was not a block' unless @probe.has_block? 'did' end end # @api private # Provides the implementation for `yield_with_args`. # Not intended to be instantiated directly. class YieldWithArgs < BaseMatcher def initialize(*args) @expected = args end # @private def matches?(block) @args_matched_when_yielded = true @probe = YieldProbe.new(block) do @actual = @probe.single_yield_args @actual_formatted = actual_formatted @args_matched_when_yielded &&= args_currently_match? end return false unless @probe.has_block? @probe.probe @probe.yielded_once?(:yield_with_args) && @args_matched_when_yielded end # @private def does_not_match?(block) !matches?(block) && @probe.has_block? end # @private def failure_message "expected given block to yield with arguments, but #{positive_failure_reason}" end # @private def failure_message_when_negated "expected given block not to yield with arguments, but #{negative_failure_reason}" end # @private def description desc = 'yield with args' desc = "#{desc}(#{expected_arg_description})" unless @expected.empty? desc end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def positive_failure_reason return 'was not a block' unless @probe.has_block? return 'did not yield' if @probe.num_yields.zero? @positive_args_failure end def expected_arg_description @expected.map { |e| description_of e }.join(', ') end def negative_failure_reason if !@probe.has_block? 'was not a block' elsif @args_matched_when_yielded && !@expected.empty? 'yielded with expected arguments' \ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{@actual_formatted}" else 'did' end end def args_currently_match? if @expected.empty? # expect {...}.to yield_with_args @positive_args_failure = 'yielded with no arguments' if @actual.empty? return !@actual.empty? end unless (match = all_args_match?) @positive_args_failure = 'yielded with unexpected arguments' \ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{@actual_formatted}" end match end def all_args_match? values_match?(@expected, @actual) end end # @api private # Provides the implementation for `yield_successive_args`. # Not intended to be instantiated directly. class YieldSuccessiveArgs < BaseMatcher def initialize(*args) @expected = args end # @private def matches?(block) @actual_formatted = [] @actual = [] args_matched_when_yielded = true yield_count = 0 @probe = YieldProbe.probe(block) do |*arg_array| arg_or_args = arg_array.size == 1 ? arg_array.first : arg_array @actual_formatted << RSpec::Support::ObjectFormatter.format(arg_or_args) @actual << arg_or_args args_matched_when_yielded &&= values_match?(@expected[yield_count], arg_or_args) yield_count += 1 end return false unless @probe.has_block? args_matched_when_yielded && yield_count == @expected.length end def does_not_match?(block) !matches?(block) && @probe.has_block? end # @private def failure_message 'expected given block to yield successively with arguments, ' \ "but #{positive_failure_reason}" end # @private def failure_message_when_negated 'expected given block not to yield successively with arguments, ' \ "but #{negative_failure_reason}" end # @private def description "yield successive args(#{expected_arg_description})" end # @private def supports_block_expectations? true end # @private def supports_value_expectations? false end private def expected_arg_description @expected.map { |e| description_of e }.join(', ') end def positive_failure_reason return 'was not a block' unless @probe.has_block? 'yielded with unexpected arguments' \ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ "\n got: [#{@actual_formatted.join(", ")}]" end def negative_failure_reason return 'was not a block' unless @probe.has_block? 'yielded with expected arguments' \ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ "\n got: [#{@actual_formatted.join(", ")}]" end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/composable.rb000066400000000000000000000143061455770000100235620ustar00rootroot00000000000000RSpec::Support.require_rspec_support "fuzzy_matcher" module RSpec module Matchers # Mixin designed to support the composable matcher features # of RSpec 3+. Mix it into your custom matcher classes to # allow them to be used in a composable fashion. # # @api public module Composable # Creates a compound `and` expectation. The matcher will # only pass if both sub-matchers pass. # This can be chained together to form an arbitrarily long # chain of matchers. # # @example # expect(alphabet).to start_with("a").and end_with("z") # expect(alphabet).to start_with("a") & end_with("z") # # @note The negative form (`expect(...).not_to matcher.and other`) # is not supported at this time. def and(matcher) BuiltIn::Compound::And.new self, matcher end alias & and # Creates a compound `or` expectation. The matcher will # pass if either sub-matcher passes. # This can be chained together to form an arbitrarily long # chain of matchers. # # @example # expect(stoplight.color).to eq("red").or eq("green").or eq("yellow") # expect(stoplight.color).to eq("red") | eq("green") | eq("yellow") # # @note The negative form (`expect(...).not_to matcher.or other`) # is not supported at this time. def or(matcher) BuiltIn::Compound::Or.new self, matcher end alias | or # Delegates to `#matches?`. Allows matchers to be used in composable # fashion and also supports using matchers in case statements. def ===(value) matches?(value) end private # This provides a generic way to fuzzy-match an expected value against # an actual value. It understands nested data structures (e.g. hashes # and arrays) and is able to match against a matcher being used as # the expected value or within the expected value at any level of # nesting. # # Within a custom matcher you are encouraged to use this whenever your # matcher needs to match two values, unless it needs more precise semantics. # For example, the `eq` matcher _does not_ use this as it is meant to # use `==` (and only `==`) for matching. # # @param expected [Object] what is expected # @param actual [Object] the actual value # # @!visibility public def values_match?(expected, actual) expected = with_matchers_cloned(expected) Support::FuzzyMatcher.values_match?(expected, actual) end # Returns the description of the given object in a way that is # aware of composed matchers. If the object is a matcher with # a `description` method, returns the description; otherwise # returns `object.inspect`. # # You are encouraged to use this in your custom matcher's # `description`, `failure_message` or # `failure_message_when_negated` implementation if you are # supporting matcher arguments. # # @!visibility public def description_of(object) RSpec::Support::ObjectFormatter.format(object) end # Transforms the given data structure (typically a hash or array) # into a new data structure that, when `#inspect` is called on it, # will provide descriptions of any contained matchers rather than # the normal `#inspect` output. # # You are encouraged to use this in your custom matcher's # `description`, `failure_message` or # `failure_message_when_negated` implementation if you are # supporting any arguments which may be a data structure # containing matchers. # # @!visibility public def surface_descriptions_in(item) if Matchers.is_a_describable_matcher?(item) DescribableItem.new(item) elsif Hash === item Hash[surface_descriptions_in(item.to_a)] elsif Struct === item || unreadable_io?(item) RSpec::Support::ObjectFormatter.format(item) elsif should_enumerate?(item) item.map { |subitem| surface_descriptions_in(subitem) } else item end end # @private # Historically, a single matcher instance was only checked # against a single value. Given that the matcher was only # used once, it's been common to memoize some intermediate # calculation that is derived from the `actual` value in # order to reuse that intermediate result in the failure # message. # # This can cause a problem when using such a matcher as an # argument to another matcher in a composed matcher expression, # since the matcher instance may be checked against multiple # values and produce invalid results due to the memoization. # # To deal with this, we clone any matchers in `expected` via # this method when using `values_match?`, so that any memoization # does not "leak" between checks. def with_matchers_cloned(object) if Matchers.is_a_matcher?(object) object.clone elsif Hash === object Hash[with_matchers_cloned(object.to_a)] elsif should_enumerate?(object) object.map { |subobject| with_matchers_cloned(subobject) } else object end end # @api private # We should enumerate arrays as long as they are not recursive. def should_enumerate?(item) Array === item && item.none? { |subitem| subitem.equal?(item) } end # @api private def unreadable_io?(object) return false unless IO === object object.each {} # STDOUT is enumerable but raises an error false rescue IOError true end module_function :surface_descriptions_in, :should_enumerate?, :unreadable_io? # Wraps an item in order to surface its `description` via `inspect`. # @api private DescribableItem = Struct.new(:item) do # Inspectable version of the item description def inspect "(#{item.description})" end # A pretty printed version of the item description. def pretty_print(pp) pp.text "(#{item.description})" end end end end end rspec-expectations-3.13.0/lib/rspec/matchers/dsl.rb000066400000000000000000000537101455770000100222220ustar00rootroot00000000000000RSpec::Support.require_rspec_support "with_keywords_when_needed" module RSpec module Matchers # Defines the custom matcher DSL. module DSL # Defines a matcher alias. The returned matcher's `description` will be overridden # to reflect the phrasing of the new name, which will be used in failure messages # when passed as an argument to another matcher in a composed matcher expression. # # @example # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to # sum_to(3).description # => "sum to 3" # a_list_that_sums_to(3).description # => "a list that sums to 3" # # @example # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description| # description.sub("be sorted by", "a list sorted by") # end # # be_sorted_by(:age).description # => "be sorted by age" # a_list_sorted_by(:age).description # => "a list sorted by age" # # @param new_name [Symbol] the new name for the matcher # @param old_name [Symbol] the original name for the matcher # @param options [Hash] options for the aliased matcher # @option options [Class] :klass the ruby class to use as the decorator. (Not normally used). # @yield [String] optional block that, when given, is used to define the overridden # logic. The yielded arg is the original description or failure message. If no # block is provided, a default override is used based on the old and new names. # @see RSpec::Matchers def alias_matcher(new_name, old_name, options={}, &description_override) description_override ||= lambda do |old_desc| old_desc.gsub(EnglishPhrasing.split_words(old_name), EnglishPhrasing.split_words(new_name)) end klass = options.fetch(:klass) { AliasedMatcher } define_method(new_name) do |*args, &block| matcher = __send__(old_name, *args, &block) matcher.matcher_name = new_name if matcher.respond_to?(:matcher_name=) klass.new(matcher, description_override) end ruby2_keywords new_name if respond_to?(:ruby2_keywords, true) end # Defines a negated matcher. The returned matcher's `description` and `failure_message` # will be overridden to reflect the phrasing of the new name, and the match logic will # be based on the original matcher but negated. # # @example # RSpec::Matchers.define_negated_matcher :exclude, :include # include(1, 2).description # => "include 1 and 2" # exclude(1, 2).description # => "exclude 1 and 2" # # @param negated_name [Symbol] the name for the negated matcher # @param base_name [Symbol] the name of the original matcher that will be negated # @yield [String] optional block that, when given, is used to define the overridden # logic. The yielded arg is the original description or failure message. If no # block is provided, a default override is used based on the old and new names. # @see RSpec::Matchers def define_negated_matcher(negated_name, base_name, &description_override) alias_matcher(negated_name, base_name, :klass => AliasedNegatedMatcher, &description_override) end # Defines a custom matcher. # # @param name [Symbol] the name for the matcher # @yield [Object] block that is used to define the matcher. # The block is evaluated in the context of your custom matcher class. # When args are passed to your matcher, they will be yielded here, # usually representing the expected value(s). # @see RSpec::Matchers def define(name, &declarations) warn_about_block_args(name, declarations) define_method name do |*expected, &block_arg| RSpec::Matchers::DSL::Matcher.new(name, declarations, self, *expected, &block_arg) end end alias_method :matcher, :define private if Proc.method_defined?(:parameters) def warn_about_block_args(name, declarations) declarations.parameters.each do |type, arg_name| next unless type == :block RSpec.warning("Your `#{name}` custom matcher receives a block argument (`#{arg_name}`), " \ "but due to limitations in ruby, RSpec cannot provide the block. Instead, " \ "use the `block_arg` method to access the block") end end else # :nocov: def warn_about_block_args(*) # There's no way to detect block params on 1.8 since the method reflection APIs don't expose it end # :nocov: end RSpec.configure { |c| c.extend self } if RSpec.respond_to?(:configure) # Contains the methods that are available from within the # `RSpec::Matchers.define` DSL for creating custom matchers. module Macros # Stores the block that is used to determine whether this matcher passes # or fails. The block should return a boolean value. When the matcher is # passed to `expect(...).to` and the block returns `true`, then the expectation # passes. Similarly, when the matcher is passed to `expect(...).not_to` and the # block returns `false`, then the expectation passes. # # @example # # RSpec::Matchers.define :be_even do # match do |actual| # actual.even? # end # end # # expect(4).to be_even # passes # expect(3).not_to be_even # passes # expect(3).to be_even # fails # expect(4).not_to be_even # fails # # By default the match block will swallow expectation errors (e.g. # caused by using an expectation such as `expect(1).to eq 2`), if you # wish to allow these to bubble up, pass in the option # `:notify_expectation_failures => true`. # # @param [Hash] options for defining the behavior of the match block. # @yield [Object] actual the actual value (i.e. the value wrapped by `expect`) def match(options={}, &match_block) define_user_override(:matches?, match_block) do |actual| @actual = actual RSpec::Support.with_failure_notifier(RAISE_NOTIFIER) do begin super(*actual_arg_for(match_block)) rescue RSpec::Expectations::ExpectationNotMetError raise if options[:notify_expectation_failures] false end end end end # @private RAISE_NOTIFIER = Proc.new { |err, _opts| raise err } # Use this to define the block for a negative expectation (`expect(...).not_to`) # when the positive and negative forms require different handling. This # is rarely necessary, but can be helpful, for example, when specifying # asynchronous processes that require different timeouts. # # By default the match block will swallow expectation errors (e.g. # caused by using an expectation such as `expect(1).to eq 2`), if you # wish to allow these to bubble up, pass in the option # `:notify_expectation_failures => true`. # # @param [Hash] options for defining the behavior of the match block. # @yield [Object] actual the actual value (i.e. the value wrapped by `expect`) def match_when_negated(options={}, &match_block) define_user_override(:does_not_match?, match_block) do |actual| begin @actual = actual RSpec::Support.with_failure_notifier(RAISE_NOTIFIER) do super(*actual_arg_for(match_block)) end rescue RSpec::Expectations::ExpectationNotMetError raise if options[:notify_expectation_failures] false end end end # Use this instead of `match` when the block will raise an exception # rather than returning false to indicate a failure. # # @example # # RSpec::Matchers.define :accept_as_valid do |candidate_address| # match_unless_raises ValidationException do |validator| # validator.validate(candidate_address) # end # end # # expect(email_validator).to accept_as_valid("person@company.com") # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) def match_unless_raises(expected_exception=Exception, &match_block) define_user_override(:matches?, match_block) do |actual| @actual = actual begin super(*actual_arg_for(match_block)) rescue expected_exception => @rescued_exception false else true end end end # Customizes the failure message to use when this matcher is # asked to positively match. Only use this when the message # generated by default doesn't suit your needs. # # @example # # RSpec::Matchers.define :have_strength do |expected| # match { your_match_logic } # # failure_message do |actual| # "Expected strength of #{expected}, but had #{actual.strength}" # end # end # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) def failure_message(&definition) define_user_override(__method__, definition) end # Customize the failure message to use when this matcher is asked # to negatively match. Only use this when the message generated by # default doesn't suit your needs. # # @example # # RSpec::Matchers.define :have_strength do |expected| # match { your_match_logic } # # failure_message_when_negated do |actual| # "Expected not to have strength of #{expected}, but did" # end # end # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) def failure_message_when_negated(&definition) define_user_override(__method__, definition) end # Customize the description to use for one-liners. Only use this when # the description generated by default doesn't suit your needs. # # @example # # RSpec::Matchers.define :qualify_for do |expected| # match { your_match_logic } # # description do # "qualify for #{expected}" # end # end # # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`) def description(&definition) define_user_override(__method__, definition) end # Tells the matcher to diff the actual and expected values in the failure # message. def diffable define_method(:diffable?) { true } end # Declares that the matcher can be used in a block expectation. # Users will not be able to use your matcher in a block # expectation without declaring this. # (e.g. `expect { do_something }.to matcher`). def supports_block_expectations define_method(:supports_block_expectations?) { true } end # Convenience for defining methods on this matcher to create a fluent # interface. The trick about fluent interfaces is that each method must # return self in order to chain methods together. `chain` handles that # for you. If the method is invoked and the # `include_chain_clauses_in_custom_matcher_descriptions` config option # hash been enabled, the chained method name and args will be added to the # default description and failure message. # # In the common case where you just want the chained method to store some # value(s) for later use (e.g. in `match`), you can provide one or more # attribute names instead of a block; the chained method will store its # arguments in instance variables with those names, and the values will # be exposed via getters. # # @example # # RSpec::Matchers.define :have_errors_on do |key| # chain :with do |message| # @message = message # end # # match do |actual| # actual.errors[key] == @message # end # end # # expect(minor).to have_errors_on(:age).with("Not old enough to participate") def chain(method_name, *attr_names, &definition) unless block_given? ^ attr_names.any? raise ArgumentError, "You must pass either a block or some attribute names (but not both) to `chain`." end definition = assign_attributes(attr_names) if attr_names.any? define_user_override(method_name, definition) do |*args, &block| super(*args, &block) @chained_method_clauses.push([method_name, args]) self end end def assign_attributes(attr_names) attr_reader(*attr_names) private(*attr_names) lambda do |*attr_values| attr_names.zip(attr_values) do |attr_name, attr_value| instance_variable_set(:"@#{attr_name}", attr_value) end end end # assign_attributes isn't defined in the private section below because # that makes MRI 1.9.2 emit a warning about private attributes. private :assign_attributes private # Does the following: # # - Defines the named method using a user-provided block # in @user_method_defs, which is included as an ancestor # in the singleton class in which we eval the `define` block. # - Defines an overridden definition for the same method # usign the provided `our_def` block. # - Provides a default `our_def` block for the common case # of needing to call the user's definition with `@actual` # as an arg, but only if their block's arity can handle it. # # This compiles the user block into an actual method, allowing # them to use normal method constructs like `return` # (e.g. for an early guard statement), while allowing us to define # an override that can provide the wrapped handling # (e.g. assigning `@actual`, rescueing errors, etc) and # can `super` to the user's definition. def define_user_override(method_name, user_def, &our_def) @user_method_defs.__send__(:define_method, method_name, &user_def) our_def ||= lambda { super(*actual_arg_for(user_def)) } define_method(method_name, &our_def) end # Defines deprecated macro methods from RSpec 2 for backwards compatibility. # @deprecated Use the methods from {Macros} instead. module Deprecated # @deprecated Use {Macros#match} instead. def match_for_should(&definition) RSpec.deprecate("`match_for_should`", :replacement => "`match`") match(&definition) end # @deprecated Use {Macros#match_when_negated} instead. def match_for_should_not(&definition) RSpec.deprecate("`match_for_should_not`", :replacement => "`match_when_negated`") match_when_negated(&definition) end # @deprecated Use {Macros#failure_message} instead. def failure_message_for_should(&definition) RSpec.deprecate("`failure_message_for_should`", :replacement => "`failure_message`") failure_message(&definition) end # @deprecated Use {Macros#failure_message_when_negated} instead. def failure_message_for_should_not(&definition) RSpec.deprecate("`failure_message_for_should_not`", :replacement => "`failure_message_when_negated`") failure_message_when_negated(&definition) end end end # Defines default implementations of the matcher # protocol methods for custom matchers. You can # override any of these using the {RSpec::Matchers::DSL::Macros Macros} methods # from within an `RSpec::Matchers.define` block. module DefaultImplementations include BuiltIn::BaseMatcher::DefaultFailureMessages # @api private # Used internally by objects returns by `should` and `should_not`. def diffable? false end # The default description. def description english_name = EnglishPhrasing.split_words(name) expected_list = EnglishPhrasing.list(expected) "#{english_name}#{expected_list}#{chained_method_clause_sentences}" end # Matchers do not support block expectations by default. You # must opt-in. def supports_block_expectations? false end def supports_value_expectations? true end # Most matchers do not expect call stack jumps. def expects_call_stack_jump? false end private def chained_method_clause_sentences return '' unless Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions? @chained_method_clauses.map do |(method_name, method_args)| english_name = EnglishPhrasing.split_words(method_name) arg_list = EnglishPhrasing.list(method_args) " #{english_name}#{arg_list}" end.join end end # The class used for custom matchers. The block passed to # `RSpec::Matchers.define` will be evaluated in the context # of the singleton class of an instance, and will have the # {RSpec::Matchers::DSL::Macros Macros} methods available. class Matcher # Provides default implementations for the matcher protocol methods. include DefaultImplementations # Allows expectation expressions to be used in the match block. include RSpec::Matchers # Supports the matcher composability features of RSpec 3+. include Composable # Makes the macro methods available to an `RSpec::Matchers.define` block. extend Macros extend Macros::Deprecated # Exposes the value being matched against -- generally the object # object wrapped by `expect`. attr_reader :actual # Exposes the exception raised during the matching by `match_unless_raises`. # Could be useful to extract details for a failure message. attr_reader :rescued_exception # The block parameter used in the expectation attr_reader :block_arg # The name of the matcher. attr_reader :name # @api private def initialize(name, declarations, matcher_execution_context, *expected, &block_arg) @name = name @actual = nil @expected_as_array = expected @matcher_execution_context = matcher_execution_context @chained_method_clauses = [] @block_arg = block_arg klass = class << self # See `Macros#define_user_override` above, for an explanation. include(@user_method_defs = Module.new) self end RSpec::Support::WithKeywordsWhenNeeded.class_exec(klass, *expected, &declarations) end # Provides the expected value. This will return an array if # multiple arguments were passed to the matcher; otherwise it # will return a single value. # @see #expected_as_array def expected if expected_as_array.size == 1 expected_as_array[0] else expected_as_array end end # Returns the expected value as an an array. This exists primarily # to aid in upgrading from RSpec 2.x, since in RSpec 2, `expected` # always returned an array. # @see #expected attr_reader :expected_as_array # Adds the name (rather than a cryptic hex number) # so we can identify an instance of # the matcher in error messages (e.g. for `NoMethodError`) def inspect "#<#{self.class.name} #{name}>" end if RUBY_VERSION.to_f >= 1.9 # Indicates that this matcher responds to messages # from the `@matcher_execution_context` as well. # Also, supports getting a method object for such methods. def respond_to_missing?(method, include_private=false) super || @matcher_execution_context.respond_to?(method, include_private) end else # for 1.8.7 # :nocov: # Indicates that this matcher responds to messages # from the `@matcher_execution_context` as well. def respond_to?(method, include_private=false) super || @matcher_execution_context.respond_to?(method, include_private) end # :nocov: end private def actual_arg_for(block) block.arity.zero? ? [] : [@actual] end # Takes care of forwarding unhandled messages to the # `@matcher_execution_context` (typically the current # running `RSpec::Core::Example`). This is needed by # rspec-rails so that it can define matchers that wrap # Rails' test helper methods, but it's also a useful # feature in its own right. def method_missing(method, *args, &block) if @matcher_execution_context.respond_to?(method) @matcher_execution_context.__send__ method, *args, &block else super(method, *args, &block) end end # The method_missing method should be refactored to pass kw args in RSpec 4 # then this can be removed ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true) end end end end rspec-expectations-3.13.0/lib/rspec/matchers/english_phrasing.rb000066400000000000000000000035051455770000100247610ustar00rootroot00000000000000module RSpec module Matchers # Facilitates converting ruby objects to English phrases. module EnglishPhrasing # Converts a symbol into an English expression. # # split_words(:banana_creme_pie) #=> "banana creme pie" # def self.split_words(sym) sym.to_s.tr('_', ' ') end # @note The returned string has a leading space except # when given an empty list. # # Converts an object (often a collection of objects) # into an English list. # # list(['banana', 'kiwi', 'mango']) # #=> " \"banana\", \"kiwi\", and \"mango\"" # # Given an empty collection, returns the empty string. # # list([]) #=> "" # def self.list(obj) return " #{RSpec::Support::ObjectFormatter.format(obj)}" if !obj || Struct === obj || Hash === obj items = Array(obj).map { |w| RSpec::Support::ObjectFormatter.format(w) } case items.length when 0 "" when 1 " #{items[0]}" when 2 " #{items[0]} and #{items[1]}" else " #{items[0...-1].join(', ')}, and #{items[-1]}" end end if RUBY_VERSION == '1.8.7' # Not sure why, but on travis on 1.8.7 we have gotten these warnings: # lib/rspec/matchers/english_phrasing.rb:28: warning: default `to_a' will be obsolete # So it appears that `Array` can trigger that (e.g. by calling `to_a` on the passed object?) # So here we replace `Kernel#Array` with our own warning-free implementation for 1.8.7. # @private # rubocop:disable Naming/MethodName def self.Array(obj) case obj when Array then obj else [obj] end end # rubocop:enable Naming/MethodName end end end end rspec-expectations-3.13.0/lib/rspec/matchers/fail_matchers.rb000066400000000000000000000023631455770000100242370ustar00rootroot00000000000000require 'rspec/expectations' module RSpec module Matchers # Matchers for testing RSpec matchers. Include them with: # # require 'rspec/matchers/fail_matchers' # RSpec.configure do |config| # config.include RSpec::Matchers::FailMatchers # end # module FailMatchers # Matches if an expectation fails # # @example # expect { some_expectation }.to fail def fail(&block) raise_error(RSpec::Expectations::ExpectationNotMetError, &block) end # Matches if an expectation fails with the provided message # # @example # expect { some_expectation }.to fail_with("some failure message") # expect { some_expectation }.to fail_with(/some failure message/) def fail_with(message) raise_error(RSpec::Expectations::ExpectationNotMetError, message) end # Matches if an expectation fails including the provided message # # @example # expect { some_expectation }.to fail_including("portion of some failure message") def fail_including(*snippets) raise_error( RSpec::Expectations::ExpectationNotMetError, a_string_including(*snippets) ) end end end end rspec-expectations-3.13.0/lib/rspec/matchers/generated_descriptions.rb000066400000000000000000000022541455770000100261610ustar00rootroot00000000000000module RSpec module Matchers class << self # @private attr_accessor :last_matcher, :last_expectation_handler end # @api private # Used by rspec-core to clear the state used to generate # descriptions after an example. def self.clear_generated_description self.last_matcher = nil self.last_expectation_handler = nil end # @api private # Generates an an example description based on the last expectation. # Used by rspec-core's one-liner syntax. def self.generated_description return nil if last_expectation_handler.nil? "#{last_expectation_handler.verb} #{last_description}" end # @private def self.last_description last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE When you call a matcher in an example without a String, like this: specify { expect(object).to matcher } or this: it { is_expected.to matcher } RSpec expects the matcher to have a #description method. You should either add a String to the example this matcher is being used in, or give it a description method. Then you won't have to suffer this lengthy warning again. MESSAGE end end end rspec-expectations-3.13.0/lib/rspec/matchers/matcher_delegator.rb000066400000000000000000000033311455770000100251030ustar00rootroot00000000000000module RSpec module Matchers # Provides a base class with as little methods as possible, so that # most methods can be delegated via `method_missing`. # # On Ruby 2.0+ BasicObject could be used for this purpose, but it # introduce some extra complexity with constant resolution, so the # BlankSlate pattern was prefered. # @private class BaseDelegator kept_methods = [ # Methods that raise warnings if removed. :__id__, :__send__, :object_id, # Methods that are explicitly undefined in some subclasses. :==, :===, # Methods we keep on purpose. :class, :respond_to?, :__method__, :method, :dup, :clone, :initialize_dup, :initialize_copy, :initialize_clone, ] instance_methods.each do |method| unless kept_methods.include?(method.to_sym) undef_method(method) end end end # Provides the necessary plumbing to wrap a matcher with a decorator. # @private class MatcherDelegator < BaseDelegator include Composable attr_reader :base_matcher def initialize(base_matcher) @base_matcher = base_matcher end def method_missing(*args, &block) base_matcher.__send__(*args, &block) end if ::RUBY_VERSION.to_f > 1.8 def respond_to_missing?(name, include_all=false) super || base_matcher.respond_to?(name, include_all) end else # :nocov: def respond_to?(name, include_all=false) super || base_matcher.respond_to?(name, include_all) end # :nocov: end def initialize_copy(other) @base_matcher = @base_matcher.clone super end end end end rspec-expectations-3.13.0/lib/rspec/matchers/matcher_protocol.rb000066400000000000000000000117261455770000100250050ustar00rootroot00000000000000module RSpec module Matchers # rspec-expectations can work with any matcher object that implements this protocol. # # @note This class is not loaded at runtime by rspec-expectations. It exists # purely to provide documentation for the matcher protocol. class MatcherProtocol # @!group Required Methods # @!method matches?(actual) # @param actual [Object] The object being matched against. # @yield For an expression like `expect(x).to matcher do...end`, the `do/end` # block binds to `to`. It passes that block, if there is one, on to this method. # @return [Boolean] true if this matcher matches the provided object. # @!method failure_message # This will only be called if {#matches?} returns false. # @return [String] Explanation for the failure. # @!endgroup # @!group Optional Methods # @!method does_not_match?(actual) # In a negative expectation such as `expect(x).not_to foo`, RSpec will # call `foo.does_not_match?(x)` if this method is defined. If it's not # defined it will fall back to using `!foo.matches?(x)`. This allows you # to provide custom logic for the negative case. # # @param actual [Object] The object being matched against. # @yield For an expression like `expect(x).not_to matcher do...end`, the `do/end` # block binds to `not_to`. It passes that block, if there is one, on to this method. # @return [Boolean] true if this matcher does not match the provided object. # @!method failure_message_when_negated # This will only be called when a negative match fails. # @return [String] Explanation for the failure. # @note This method is listed as optional because matchers do not have to # support negation. But if your matcher does support negation, this is a # required method -- otherwise, you'll get a `NoMethodError`. # @!method description # The description is used for two things: # # * When using RSpec's one-liner syntax # (e.g. `it { is_expected.to matcher }`), the description # is used to generate the example's doc string since you # have not provided one. # * In a composed matcher expression, the description is used # as part of the failure message (and description) of the outer # matcher. # # @return [String] Description of the matcher. # @!method supports_block_expectations? # Indicates that this matcher can be used in a block expectation expression, # such as `expect { foo }.to raise_error`. Generally speaking, this is # only needed for matchers which operate on a side effect of a block, rather # than on a particular object. # @return [Boolean] true if this matcher can be used in block expressions. # @note If not defined, RSpec assumes a value of `false` for this method. # @!method supports_value_expectations? # Indicates that this matcher can be used in a value expectation expression, # such as `expect(foo).to eq(bar)`. # @return [Boolean] true if this matcher can be used in value expressions. # @note If not defined, RSpec assumes a value of `true` for this method. # @!method expects_call_stack_jump? # Indicates that when this matcher is used in a block expectation # expression, it expects the block to use a ruby construct that causes # a call stack jump (such as raising an error or throwing a symbol). # # This is used internally for compound block expressions, as matchers # which expect call stack jumps must be treated with care to work properly. # # @return [Boolean] true if the matcher expects a call stack jump # # @note This method is very rarely used or needed. # @note If not defined, RSpec assumes a value of `false` for this method. # @!method diffable? # @return [Boolean] true if `actual` and `expected` can be diffed. # Indicates that this matcher provides `actual` and `expected` attributes, # and that the values returned by these can be usefully diffed, which can # be included in the output. # @!method actual # @return [String, Object] If an object (rather than a string) is provided, # RSpec will use the `pp` library to convert it to multi-line output in # order to diff. # The actual value for the purposes of a diff. # @note This method is required if `diffable?` returns true. # @!method expected # @return [String, Object] If an object (rather than a string) is provided, # RSpec will use the `pp` library to convert it to multi-line output in # order to diff. # The expected value for the purposes of a diff. # @note This method is required if `diffable?` returns true. # @!endgroup end end end rspec-expectations-3.13.0/lib/rspec/matchers/multi_matcher_diff.rb000066400000000000000000000050441455770000100252620ustar00rootroot00000000000000module RSpec module Matchers # @api private # Handles list of expected and actual value pairs when there is a need # to render multiple diffs. Also can handle one pair. class MultiMatcherDiff # @private # Default diff label when there is only one matcher in diff # output DEFAULT_DIFF_LABEL = "Diff:".freeze # @private # Maximum readable matcher description length DESCRIPTION_MAX_LENGTH = 65 def initialize(expected_list) @expected_list = expected_list end # @api private # Wraps provided expected value in instance of # MultiMatcherDiff. If provided value is already an # MultiMatcherDiff then it just returns it. # @param [Any] expected value to be wrapped # @param [Any] actual value # @return [RSpec::Matchers::MultiMatcherDiff] def self.from(expected, actual) return expected if self === expected new([[expected, DEFAULT_DIFF_LABEL, actual]]) end # @api private # Wraps provided matcher list in instance of # MultiMatcherDiff. # @param [Array] matchers list of matchers to wrap # @return [RSpec::Matchers::MultiMatcherDiff] def self.for_many_matchers(matchers) new(matchers.map { |m| [m.expected, diff_label_for(m), m.actual] }) end # @api private # Returns message with diff(s) appended for provided differ # factory and actual value if there are any # @param [String] message original failure message # @param [Proc] differ # @return [String] def message_with_diff(message, differ) diff = diffs(differ) message = "#{message}\n#{diff}" unless diff.empty? message end private class << self private def diff_label_for(matcher) "Diff for (#{truncated(RSpec::Support::ObjectFormatter.format(matcher))}):" end def truncated(description) return description if description.length <= DESCRIPTION_MAX_LENGTH description[0...DESCRIPTION_MAX_LENGTH - 3] << "..." end end def diffs(differ) @expected_list.map do |(expected, diff_label, actual)| diff = differ.diff(actual, expected) next if diff.strip.empty? if diff == "\e[0m\n\e[0m" "#{diff_label}\n" \ " " else "#{diff_label}#{diff}" end end.compact.join("\n") end end end end rspec-expectations-3.13.0/maintenance-branch000066400000000000000000000000211455770000100210460ustar00rootroot000000000000003-13-maintenance rspec-expectations-3.13.0/rspec-expectations.gemspec000066400000000000000000000043421455770000100226050ustar00rootroot00000000000000$LOAD_PATH.unshift File.expand_path("../lib", __FILE__) require "rspec/expectations/version" Gem::Specification.new do |s| s.name = "rspec-expectations" s.version = RSpec::Expectations::Version::STRING s.platform = Gem::Platform::RUBY s.license = "MIT" s.authors = ["Steven Baker", "David Chelimsky", "Myron Marston"] s.email = "rspec@googlegroups.com" s.homepage = "https://github.com/rspec/rspec-expectations" s.summary = "rspec-expectations-#{RSpec::Expectations::Version::STRING}" s.description = "rspec-expectations provides a simple, readable API to express expected outcomes of a code example." s.metadata = { 'bug_tracker_uri' => 'https://github.com/rspec/rspec-expectations/issues', 'changelog_uri' => "https://github.com/rspec/rspec-expectations/blob/v#{s.version}/Changelog.md", 'documentation_uri' => 'https://rspec.info/documentation/', 'mailing_list_uri' => 'https://groups.google.com/forum/#!forum/rspec', 'source_code_uri' => 'https://github.com/rspec/rspec-expectations', } s.files = `git ls-files -- lib/*`.split("\n") s.files += %w[README.md LICENSE.md Changelog.md .yardopts .document] s.test_files = [] s.rdoc_options = ["--charset=UTF-8"] s.require_path = "lib" s.required_ruby_version = '>= 1.8.7' # rubocop:disable Gemspec/RequiredRubyVersion private_key = File.expand_path('~/.gem/rspec-gem-private_key.pem') if File.exist?(private_key) s.signing_key = private_key s.cert_chain = [File.expand_path('~/.gem/rspec-gem-public_cert.pem')] end if RSpec::Expectations::Version::STRING =~ /[a-zA-Z]+/ # pin to exact version for rc's and betas s.add_runtime_dependency "rspec-support", "= #{RSpec::Expectations::Version::STRING}" else # pin to major/minor ignoring patch s.add_runtime_dependency "rspec-support", "~> #{RSpec::Expectations::Version::STRING.split('.')[0..1].concat(['0']).join('.')}" end s.add_runtime_dependency "diff-lcs", ">= 1.2.0", "< 2.0" s.add_development_dependency "aruba", "~> 0.14.10" s.add_development_dependency 'cucumber', '>= 1.3' s.add_development_dependency 'minitest', '~> 5.2' s.add_development_dependency 'rake', '> 10.0.0' end rspec-expectations-3.13.0/script/000077500000000000000000000000001455770000100167215ustar00rootroot00000000000000rspec-expectations-3.13.0/script/ci_functions.sh000066400000000000000000000037631455770000100217510ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. # Taken from: # https://github.com/travis-ci/travis-build/blob/e9314616e182a23e6a280199cd9070bfc7cae548/lib/travis/build/script/templates/header.sh#L34-L53 ci_retry() { local result=0 local count=1 while [ $count -le 3 ]; do [ $result -ne 0 ] && { echo -e "\n\033[33;1mThe command \"$@\" failed. Retrying, $count of 3.\033[0m\n" >&2 } "$@" result=$? [ $result -eq 0 ] && break count=$(($count + 1)) sleep 1 done [ $count -eq 3 ] && { echo "\n\033[33;1mThe command \"$@\" failed 3 times.\033[0m\n" >&2 } return $result } # Taken from https://github.com/vcr/vcr/commit/fa96819c92b783ec0c794f788183e170e4f684b2 # and https://github.com/vcr/vcr/commit/040aaac5370c68cd13c847c076749cd547a6f9b1 nano_cmd="$(type -p gdate date | head -1)" nano_format="+%s%N" [ "$(uname -s)" != "Darwin" ] || nano_format="${nano_format/%N/000000000}" travis_time_start() { travis_timer_id=$(printf %08x $(( RANDOM * RANDOM ))) travis_start_time=$($nano_cmd -u "$nano_format") printf "travis_time:start:%s\r\e[0m" $travis_timer_id } travis_time_finish() { local travis_end_time=$($nano_cmd -u "$nano_format") local duration=$(($travis_end_time-$travis_start_time)) printf "travis_time:end:%s:start=%s,finish=%s,duration=%s\r\e[0m" \ $travis_timer_id $travis_start_time $travis_end_time $duration } fold() { local name="$1" local status=0 shift 1 if [ -n "$TRAVIS" ]; then printf "travis_fold:start:%s\r\e[0m" "$name" travis_time_start else echo "============= Starting $name ===============" fi "$@" status=$? [ -z "$TRAVIS" ] || travis_time_finish if [ "$status" -eq 0 ]; then if [ -n "$TRAVIS" ]; then printf "travis_fold:end:%s\r\e[0m" "$name" else echo "============= Ending $name ===============" fi else STATUS="$status" fi return $status } rspec-expectations-3.13.0/script/clone_all_rspec_repos000077500000000000000000000011101455770000100231740ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh if is_mri; then pushd .. clone_repo "rspec" clone_repo "rspec-core" clone_repo "rspec-expectations" clone_repo "rspec-mocks" clone_repo "rspec-rails" "6-1-maintenance" if rspec_support_compatible; then clone_repo "rspec-support" fi popd else echo "Not cloning all repos since we are not on MRI and they are only needed for the MRI build" fi rspec-expectations-3.13.0/script/cucumber.sh000077500000000000000000000003421455770000100210640ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh run_cukes rspec-expectations-3.13.0/script/functions.sh000066400000000000000000000140401455770000100212640ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $SCRIPT_DIR/ci_functions.sh source $SCRIPT_DIR/predicate_functions.sh # If JRUBY_OPTS isn't set, use these. # see https://docs.travis-ci.com/user/ci-environment/ export JRUBY_OPTS=${JRUBY_OPTS:-"--server -Xcompile.invokedynamic=false"} SPECS_HAVE_RUN_FILE=specs.out MAINTENANCE_BRANCH=`cat maintenance-branch` # Don't allow rubygems to pollute what's loaded. Also, things boot faster # without the extra load time of rubygems. Only works on MRI Ruby 1.9+ if is_mri_192_plus; then export RUBYOPT="--disable=gem" fi function clone_repo { if [ ! -d $1 ]; then # don't clone if the dir is already there if [ -z "$2" ]; then BRANCH_TO_CLONE="${MAINTENANCE_BRANCH?}"; else BRANCH_TO_CLONE="$2"; fi; ci_retry eval "git clone https://github.com/rspec/$1 --depth 1 --branch ${BRANCH_TO_CLONE?}" fi; } function run_specs_and_record_done { local rspec_bin=bin/rspec # rspec-core needs to run with a special script that loads simplecov first, # so that it can instrument rspec-core's code before rspec-core has been loaded. if [ -f script/rspec_with_simplecov ] && is_mri; then rspec_bin=script/rspec_with_simplecov fi; echo "${PWD}/bin/rspec" $rspec_bin spec --backtrace --format progress --profile --format progress --out $SPECS_HAVE_RUN_FILE } function run_cukes { if [ -d features ]; then # force jRuby to use client mode JVM or a compilation mode thats as close as possible, # idea taken from https://github.com/jruby/jruby/wiki/Improving-startup-time # # Note that we delay setting this until we run the cukes because we've seen # spec failures in our spec suite due to problems with this mode. export JAVA_OPTS='-client -XX:+TieredCompilation -XX:TieredStopAtLevel=1' echo "${PWD}/bin/cucumber" if is_mri_192; then # For some reason we get SystemStackError on 1.9.2 when using # the bin/cucumber approach below. That approach is faster # (as it avoids the bundler tax), so we use it on rubies where we can. bundle exec cucumber --strict elif is_jruby; then # For some reason JRuby doesn't like our improved bundler setup RUBYOPT="-I${PWD}/../bundle -rbundler/setup" \ PATH="${PWD}/bin:$PATH" \ bin/cucumber --strict else # Prepare RUBYOPT for scenarios that are shelling out to ruby, # and PATH for those that are using `rspec` or `rake`. RUBYOPT="${RUBYOPT} -I${PWD}/../bundle -rbundler/setup" \ PATH="${PWD}/bin:$PATH" \ bin/cucumber --strict fi fi } function run_specs_one_by_one { echo "Running each spec file, one-by-one..." for file in `find spec -iname '*_spec.rb'`; do echo "Running $file" bin/rspec $file -b --format progress done } function run_spec_suite_for { if [ ! -f ../$1/$SPECS_HAVE_RUN_FILE ]; then # don't rerun specs that have already run if [ -d ../$1 ]; then echo "Running specs for $1" pushd ../$1 unset BUNDLE_GEMFILE bundle_install_flags=`cat .github/workflows/ci.yml | grep "bundle install" | sed 's/.* bundle install//'` ci_retry eval "(unset RUBYOPT; exec bundle install $bundle_install_flags)" ci_retry eval "(unset RUBYOPT; exec bundle binstubs --all)" run_specs_and_record_done popd else echo "" echo "WARNING: The ../$1 directory does not exist. Usually the" echo "build cds into that directory and run the specs to ensure" echo "the specs still pass with your latest changes, but we are" echo "going to skip that step." echo "" fi; fi; } function check_binstubs { echo "Checking required binstubs" local success=0 local binstubs="" local gems="" if [ ! -x ./bin/rspec ]; then binstubs="$binstubs bin/rspec" gems="$gems rspec-core" success=1 fi if [ ! -x ./bin/rake ]; then binstubs="$binstubs bin/rake" gems="$gems rake" success=1 fi if [ -d features ]; then if [ ! -x ./bin/cucumber ]; then binstubs="$binstubs bin/cucumber" gems="$gems cucumber" success=1 fi fi if [ $success -eq 1 ]; then echo echo "Missing binstubs:$binstubs" echo "Install missing binstubs using one of the following:" echo echo " # Create the missing binstubs" echo " $ bundle binstubs$gems" echo echo " # To binstub all gems" echo " $ bundle binstubs --all" fi return $success } function check_documentation_coverage { echo "bin/yard stats --list-undoc" bin/yard stats --list-undoc | ruby -e " while line = gets has_warnings ||= line.start_with?('[warn]:') coverage ||= line[/([\d\.]+)% documented/, 1] puts line end unless Float(coverage) == 100 puts \"\n\nMissing documentation coverage (currently at #{coverage}%)\" exit(1) end if has_warnings puts \"\n\nYARD emitted documentation warnings.\" exit(1) end " # Some warnings only show up when generating docs, so do that as well. bin/yard doc --no-cache | ruby -e " while line = gets has_warnings ||= line.start_with?('[warn]:') has_errors ||= line.start_with?('[error]:') puts line end if has_warnings || has_errors puts \"\n\nYARD emitted documentation warnings or errors.\" exit(1) end " } function check_style_and_lint { echo "bin/rubocop lib" eval "(unset RUBYOPT; exec bin/rubocop lib)" } function run_all_spec_suites { fold "rspec-core specs" run_spec_suite_for "rspec-core" fold "rspec-expectations specs" run_spec_suite_for "rspec-expectations" fold "rspec-mocks specs" run_spec_suite_for "rspec-mocks" if rspec_rails_compatible; then if ! is_ruby_27_plus; then export RAILS_VERSION='~> 6.1.0' fi fold "rspec-rails specs" run_spec_suite_for "rspec-rails" fi if rspec_support_compatible; then fold "rspec-support specs" run_spec_suite_for "rspec-support" fi } rspec-expectations-3.13.0/script/legacy_setup.sh000077500000000000000000000007721455770000100217520ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh bundle install --standalone --binstubs --without coverage documentation if [ -x ./bin/rspec ]; then echo "RSpec bin detected" else if [ -x ./exe/rspec ]; then cp ./exe/rspec ./bin/rspec echo "RSpec restored from exe" else echo "No RSpec bin available" exit 1 fi fi rspec-expectations-3.13.0/script/predicate_functions.sh000066400000000000000000000055511455770000100233130ustar00rootroot00000000000000# This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. function is_mri { if ruby -e "exit(!defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby')"; then # RUBY_ENGINE only returns 'ruby' on MRI. # MRI 1.8.7 lacks the constant but all other rubies have it (including JRuby in 1.8 mode) return 0 else return 1 fi; } function is_ruby_head { # This checks for the presence of our CI's ruby-head env variable if [ -z ${RUBY_HEAD+x} ]; then return 1 else return 0 fi; } function supports_cross_build_checks { if is_mri; then # We don't run cross build checks on ruby-head if is_ruby_head; then return 1 else return 0 fi else return 1 fi } function is_jruby { if ruby -e "exit(defined?(RUBY_PLATFORM) && RUBY_PLATFORM == 'java')"; then # RUBY_ENGINE only returns 'ruby' on MRI. # MRI 1.8.7 lacks the constant but all other rubies have it (including JRuby in 1.8 mode) return 0 else return 1 fi; } function is_mri_192 { if is_mri; then if ruby -e "exit(RUBY_VERSION == '1.9.2')"; then return 0 else return 1 fi else return 1 fi } function is_mri_192_plus { if is_mri; then if ruby -e "exit(RUBY_VERSION.to_f > 1.8)"; then return 0 else return 1 fi else return 1 fi } function is_mri_2plus { if is_mri; then if ruby -e "exit(RUBY_VERSION.to_f > 2.0)"; then return 0 else return 1 fi else return 1 fi } function is_ruby_23_plus { if ruby -e "exit(RUBY_VERSION.to_f >= 2.3)"; then return 0 else return 1 fi } function is_ruby_25_plus { if ruby -e "exit(RUBY_VERSION.to_f >= 2.5)"; then return 0 else return 1 fi } function is_ruby_27_plus { if ruby -e "exit(RUBY_VERSION.to_f >= 2.7)"; then return 0 else return 1 fi } function is_ruby_31_plus { if ruby -e "exit(RUBY_VERSION.to_f >= 3.1)"; then return 0 else return 1 fi } function rspec_rails_compatible { if is_ruby_25_plus; then # TODO remove when RSpec-Rails build is 3.1 safe by default if is_ruby_31_plus; then return 1 else return 0 fi else return 1 fi } function rspec_support_compatible { if [ "$MAINTENANCE_BRANCH" != "2-99-maintenance" ] && [ "$MAINTENANCE_BRANCH" != "2-14-maintenance" ]; then return 0 else return 1 fi } function additional_specs_available { type run_additional_specs > /dev/null 2>&1 return $? } function documentation_enforced { if [ -x ./bin/yard ]; then if is_mri_2plus; then return 0 else return 1 fi else return 1 fi } function style_and_lint_enforced { if is_ruby_head; then return 1 else if [ -x ./bin/rubocop ]; then return 0 else return 1 fi fi } rspec-expectations-3.13.0/script/run_build000077500000000000000000000015171455770000100206360ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh # Allow repos to override the default functions and add their own if [ -f script/custom_build_functions.sh ]; then source script/custom_build_functions.sh fi fold "binstub check" check_binstubs fold "specs" run_specs_and_record_done if additional_specs_available; then fold "additional specs" run_additional_specs fi fold "cukes" run_cukes if documentation_enforced; then fold "doc check" check_documentation_coverage fi if supports_cross_build_checks; then fold "one-by-one specs" run_specs_one_by_one export NO_COVERAGE=true run_all_spec_suites else echo "Skipping the rest of the build on non-MRI rubies" fi rspec-expectations-3.13.0/script/run_rubocop000077500000000000000000000006361455770000100212110ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh # Allow repos to override the default functions and add their own if [ -f script/custom_build_functions.sh ]; then source script/custom_build_functions.sh fi fold "rubocop" check_style_and_lint rspec-expectations-3.13.0/script/update_rubygems_and_install_bundler000077500000000000000000000012251455770000100261310ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2023-12-25T16:07:49+00:00 from the rspec-dev repo. # DO NOT modify it by hand as your changes will get lost the next time it is generated. set -e source script/functions.sh if is_ruby_31_plus; then echo "Installing rubygems 3.3.6 / bundler 2.3.6" yes | gem update --system '3.3.6' yes | gem install bundler -v '2.3.6' elif is_ruby_23_plus; then echo "Installing rubygems 3.2.22 / bundler 2.2.22" yes | gem update --system '3.2.22' yes | gem install bundler -v '2.2.22' else echo "Warning installing older versions of Rubygems / Bundler" gem update --system '2.7.8' gem install bundler -v '1.17.3' fi rspec-expectations-3.13.0/spec/000077500000000000000000000000001455770000100163475ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/000077500000000000000000000000001455770000100174635ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/expectations/000077500000000000000000000000001455770000100221715ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/expectations/block_snippet_extractor_spec.rb000066400000000000000000000211061455770000100304570ustar00rootroot00000000000000require 'rspec/expectations/block_snippet_extractor' module RSpec::Expectations RSpec.describe BlockSnippetExtractor, :if => RSpec::Support::RubyFeatures.ripper_supported? do subject(:extractor) do BlockSnippetExtractor.new(proc_object, 'target_method') end let(:proc_object) do @proc_object end def target_method(*, &block) @proc_object = block end def another_method(*) end before do expression end describe '.try_extracting_single_line_body_of' do subject(:try_extracting_single_line_body) do BlockSnippetExtractor.try_extracting_single_line_body_of(proc_object, 'target_method') end context 'with a single line body block' do let(:expression) do target_method { 1.positive? } end it 'returns the body' do expect(try_extracting_single_line_body).to eq('1.positive?') end end context 'with a multiline body block' do let(:expression) do target_method do 1.positive? 2.negative? end end it 'returns nil' do expect(try_extracting_single_line_body).to be_nil end end context 'when the block snippet cannot be extracted due to ambiguity' do let(:expression) do target_method { 1.positive? }; dummy_object.target_method { 2.negative? } end let(:dummy_object) do double('dummy_object', :target_method => nil) end it 'returns nil' do expect(try_extracting_single_line_body).to be_nil end end end describe '#body_content_lines' do subject(:body_content_lines) do extractor.body_content_lines end context 'with `target_method {}`' do let(:expression) do target_method {} end it 'returns empty lines' do expect(body_content_lines).to eq([]) end end context 'with `target_method { body }`' do let(:expression) do target_method { 1.positive? } end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with `target_method do body end`' do let(:expression) do target_method do 1.positive? end end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with `target_method { |arg1, arg2| body }`' do let(:expression) do target_method { |_arg1, _arg2| 1.positive? } end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with `target_method(:arg1, :arg2) { body }`' do let(:expression) do target_method(:arg1, :arg2) { 1.positive? } end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with `target_method(:arg1,:arg2){|arg1,arg2|body}`' do let(:expression) do target_method(:arg1, :arg2) { |_arg1, _arg2|1.positive? } end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with a multiline block containing a single line body' do let(:expression) do target_method do 1.positive? end end it 'returns the body content lines' do expect(body_content_lines).to eq(['1.positive?']) end end context 'with a multiline body block' do let(:expression) do target_method do 1.positive? 2.negative? end end it 'returns the body content lines' do expect(body_content_lines).to eq([ '1.positive?', '2.negative?' ]) end end context 'with `target_method { { :key => "value" } }`' do let(:expression) do target_method { { :key => "value" } } end it 'does not confuse the hash curly with the block closer' do expect(body_content_lines).to eq(['{ :key => "value" }']) end end context 'with a do-end block containing another do-end block' do let(:expression) do target_method do 2.times do |index| puts index end end end it 'does not confuse the inner `end` with the outer `end`' do expect(body_content_lines).to eq([ '2.times do |index|', 'puts index', 'end' ]) end end context "when there's another method invocation on the same line before the target" do let(:expression) do another_method { 2.negative? }; target_method { 1.positive? } end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context "when there's another method invocation on the same line after the target" do let(:expression) do target_method { 1.positive? }; another_method { 2.negative? } end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context "when there's another method invocation with the same name on the same line before the target" do let(:expression) do dummy_object.target_method { 2.negative? }; target_method { 1.positive? } end let(:dummy_object) do double('dummy_object', :target_method => nil) end it 'raises AmbiguousTargetError' do expect { body_content_lines }.to raise_error(BlockSnippetExtractor::AmbiguousTargetError) end end context "when there's another method invocation with the same name on the same line after the target" do let(:expression) do target_method { 1.positive? }; dummy_object.target_method { 2.negative? } end let(:dummy_object) do double('dummy_object', :target_method => nil) end it 'raises AmbiguousTargetError' do expect { body_content_lines }.to raise_error(BlockSnippetExtractor::AmbiguousTargetError) end end context "when there's another method invocation with the same name without block on the same line before the target" do let(:expression) do dummy_object.target_method; target_method { 1.positive? } end let(:dummy_object) do double('dummy_object', :target_method => nil) end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context "when there's another method invocation with the same name without block on the same line after the target" do let(:expression) do target_method { 1.positive? }; dummy_object.target_method end let(:dummy_object) do double('dummy_object', :target_method => nil) end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context 'when a hash is given as an argument' do let(:expression) do target_method({ :key => "value" }) { 1.positive? } end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context 'when another method invocation with block is given as an argument' do let(:expression) do target_method(another_method { 2.negative? }) { 1.positive? } end it 'correctly extracts the target snippet' do expect(body_content_lines).to eq(['1.positive?']) end end context "when the block literal is described on different line with the method invocation" do let(:expression) do block = proc { 1.positive? } target_method(&block) end it 'raises TargetNotFoundError' do expect { body_content_lines }.to raise_error(BlockSnippetExtractor::TargetNotFoundError) end end context 'with &:symbol syntax' do let(:expression) do target_method(&:positive?) end it 'raises TargetNotFoundError' do expect { body_content_lines }.to raise_error(BlockSnippetExtractor::TargetNotFoundError) end end end end end rspec-expectations-3.13.0/spec/rspec/expectations/configuration_spec.rb000066400000000000000000000241411455770000100264010ustar00rootroot00000000000000module RSpec module Expectations RSpec.describe Configuration do let(:config) { Configuration.new } describe "#backtrace_formatter" do let(:original_backtrace) { %w[ clean-me/a.rb other/file.rb clean-me/b.rb ] } let(:cleaned_backtrace) { %w[ other/file.rb ] } let(:formatted_backtrace) do config.backtrace_formatter.format_backtrace(original_backtrace) end before do @old_patterns = RSpec.configuration.backtrace_exclusion_patterns @orig_full_backtrace = RSpec.configuration.full_backtrace? RSpec.configuration.full_backtrace = false RSpec.configuration.backtrace_exclusion_patterns = [/clean-me/] end after do RSpec.configuration.backtrace_exclusion_patterns = @old_patterns RSpec.configuration.full_backtrace = @orig_full_backtrace end it "defaults to rspec-core's backtrace formatter when rspec-core is loaded" do expect(config.backtrace_formatter).to be(RSpec.configuration.backtrace_formatter) expect(formatted_backtrace).to eq(cleaned_backtrace) end it "defaults to a null formatter when rspec-core is not loaded" do RSpec::Mocks.with_temporary_scope do rspec_dup = ::RSpec.dup class << rspec_dup; undef configuration; end stub_const("RSpec", rspec_dup) expect(formatted_backtrace).to eq(original_backtrace) end end it "can be set to another backtrace formatter" do config.backtrace_formatter = double(:format_backtrace => ['a']) expect(formatted_backtrace).to eq(['a']) end end context 'on an interpreter that does not provide BasicObject', :uses_should, :unless => defined?(::BasicObject) do def with_delegate in_sub_process_if_possible do require 'delegate' RSpec::Expectations::Syntax.disable_should(Delegator) yield end end let(:klass) do Class.new(SimpleDelegator) do def delegated?; true; end end end let(:instance) { klass.new(Object.new) } it 'provides a means to manually add it Delegator' do with_delegate do instance.should_not respond_to(:delegated?) # because #should is being delegated... config.add_should_and_should_not_to Delegator instance.should respond_to(:delegated?) # now it should work! end end end describe "#include_chain_clauses_in_custom_matcher_descriptions?" do it "is false by default" do expect(config.include_chain_clauses_in_custom_matcher_descriptions?).to be false end it "can be set to true" do config.include_chain_clauses_in_custom_matcher_descriptions = true expect(config.include_chain_clauses_in_custom_matcher_descriptions?).to be true end it "can be set back to false" do config.include_chain_clauses_in_custom_matcher_descriptions = true config.include_chain_clauses_in_custom_matcher_descriptions = false expect(config.include_chain_clauses_in_custom_matcher_descriptions?).to be false end end describe "#max_formatted_output_length=" do before do @orig_max_formatted_output_length = RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length end after do config.max_formatted_output_length = @orig_max_formatted_output_length end let(:object_with_large_inspect_string) { Struct.new(:value).new("a"*300) } it "sets the maximum object formatter length" do config.max_formatted_output_length = 10 expect(RSpec::Support::ObjectFormatter.format(object_with_large_inspect_string)).to eq("#") end it "formats the entire object when set to nil" do config.max_formatted_output_length = nil expect(RSpec::Support::ObjectFormatter.format(object_with_large_inspect_string)).to eq(object_with_large_inspect_string.inspect) end end describe "#warn_about_potential_false_positives?" do it "is true by default" do expect(config.warn_about_potential_false_positives?).to be true end it "can be set to false" do config.warn_about_potential_false_positives = false expect(config.warn_about_potential_false_positives?).to be false end it "can be set back to true" do config.warn_about_potential_false_positives = false config.warn_about_potential_false_positives = true expect(config.warn_about_potential_false_positives?).to be true end end describe '#on_potential_false_positives' do it 'is set to :warn by default' do expect(config.on_potential_false_positives).to eq :warn end it 'can be set to :nothing' do config.on_potential_false_positives = :nothing expect(config.on_potential_false_positives).to eq :nothing end it 'can be set back to :warn' do config.on_potential_false_positives = :nothing config.on_potential_false_positives = :warn expect(config.on_potential_false_positives).to eq :warn end it 'can be set to :raise' do config.on_potential_false_positives = :raise expect(config.on_potential_false_positives).to eq :raise end end shared_examples "configuring the expectation syntax" do before do @orig_syntax = RSpec::Matchers.configuration.syntax end after do configure_syntax(@orig_syntax) end it 'can limit the syntax to :should' do configure_syntax :should configured_syntax.should eq([:should]) 3.should eq(3) 3.should_not eq(4) lambda { expect(6).to eq(6) }.should raise_error(NameError) end it 'is a no-op when configured to :should twice' do configure_syntax :should method_added_count = 0 allow(Expectations::Syntax.default_should_host).to receive(:method_added) { method_added_count += 1 } configure_syntax :should method_added_count.should eq(0) end it 'can limit the syntax to :expect' do configure_syntax :expect expect(configured_syntax).to eq([:expect]) expect(3).to eq(3) expect { 3.should eq(3) }.to raise_error(NameError) expect { 3.should_not eq(3) }.to raise_error(NameError) end it 'is a no-op when configured to :expect twice' do allow(RSpec::Matchers).to receive(:method_added).and_raise("no methods should be added here") configure_syntax :expect configure_syntax :expect end describe "`:should` being enabled by default deprecation" do before { configure_default_syntax } it "warns when the should syntax is called by default" do expected_arguments = [ /Using.*without explicitly enabling/, { :replacement => "the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }`" } ] expect(RSpec).to receive(:deprecate).with(*expected_arguments) 3.should eq(3) end it "includes the call site in the deprecation warning by default" do expect_deprecation_with_call_site(__FILE__, __LINE__ + 1) 3.should eq(3) end it "does not warn when only the should syntax is explicitly configured" do configure_syntax(:should) RSpec.should_not receive(:deprecate) 3.should eq(3) end it "does not warn when both the should and expect syntaxes are explicitly configured" do configure_syntax([:should, :expect]) expect(RSpec).not_to receive(:deprecate) 3.should eq(3) end end it 'can re-enable the :should syntax' do configure_syntax :expect configure_syntax [:should, :expect] configured_syntax.should eq([:should, :expect]) 3.should eq(3) 3.should_not eq(4) expect(3).to eq(3) end it 'can re-enable the :expect syntax' do configure_syntax :should configure_syntax [:should, :expect] configured_syntax.should eq([:should, :expect]) 3.should eq(3) 3.should_not eq(4) expect(3).to eq(3) end end def configure_default_syntax RSpec::Matchers.configuration.reset_syntaxes_to_default end describe "configuring rspec-expectations directly" do it_behaves_like "configuring the expectation syntax" do def configure_syntax(syntax) RSpec::Matchers.configuration.syntax = syntax end def configured_syntax RSpec::Matchers.configuration.syntax end end end describe "configuring using the rspec-core config API" do it_behaves_like "configuring the expectation syntax" do def configure_syntax(syntax) RSpec.configure do |rspec| rspec.expect_with :rspec do |c| c.syntax = syntax end end end def configured_syntax RSpec.configure do |rspec| rspec.expect_with :rspec do |c| return c.syntax end end end end end it 'enables both syntaxes by default' do # This is kinda a hack, but since we want to enforce use of # the expect syntax within our specs here, we have modified the # config setting, which makes it hard to get at the original # default value. in spec_helper.rb we store the default value # in $default_expectation_syntax so we can use it here. expect($default_expectation_syntax).to contain_exactly(:expect, :should) # rubocop:disable Style/GlobalVars end end end end rspec-expectations-3.13.0/spec/rspec/expectations/expectation_target_spec.rb000066400000000000000000000113771455770000100274320ustar00rootroot00000000000000module RSpec module Expectations RSpec.describe ExpectationTarget do context 'when constructed via #expect' do it 'constructs a new instance targetting the given argument' do expect(expect(7).target).to eq(7) end it 'constructs a new instance targetting the given block' do block = lambda {} expect(expect(&block).target).to be(block) end it 'raises an ArgumentError when given an argument and a block' do expect { expect(7) {} }.to raise_error(ArgumentError) end it 'raises a wrong number of args ArgumentError when given two args' do expect { expect(1, 2) }.to raise_error(ArgumentError, /wrong number of arg/) end it 'raises an ArgumentError when given neither an argument nor a block' do expect { expect }.to raise_error(ArgumentError) end it 'can be passed nil' do expect(expect(nil).target).to be_nil end it 'passes a valid positive expectation' do expect(5).to eq(5) end it 'passes a valid negative expectation' do expect(5).not_to eq(4) end it 'passes a valid negative expectation with a split infinitive' do expect(5).to_not eq(4) end it 'fails an invalid positive expectation' do expect { expect(5).to eq(4) }.to fail_with(/expected: 4.*got: 5/m) end it 'fails an invalid negative expectation' do message = /expected 5 not to be a kind of Integer/ expect { expect(5).not_to be_an(Integer) }.to fail_with(message) end it 'fails an invalid negative expectation with a split infinitive' do message = /expected 5 not to be a kind of Integer/ expect { expect(5).to_not be_an(Integer) }.to fail_with(message) end it 'does not support operator matchers from #to' do expect { expect(3).to == 3 }.to raise_error(ArgumentError) end it 'does not support operator matchers from #not_to' do expect { expect(3).not_to == 4 }.to raise_error(ArgumentError) end end context "when passed a block" do it 'can be used with a block matcher' do expect {}.not_to raise_error end context 'when passed a value matcher' do not_a_block_matcher_error = /You must pass an argument rather than a block to `expect` to use the provided matcher/ it 'raises an error that directs the user to pass an arg rather than a block' do expect { expect {}.to be_an(Object) }.to fail_with(not_a_block_matcher_error) expect { expect {}.not_to be_nil }.to fail_with(not_a_block_matcher_error) expect { expect {}.to_not be_nil }.to fail_with(not_a_block_matcher_error) end it 'assumes a custom matcher that does not define `supports_block_expectations?` is not a block matcher (since it is relatively rare)' do custom_matcher = Module.new do def self.matches?(_value); true; end def self.description; "foo"; end end expect(3).to custom_matcher # to show the custom matcher can be used as a matcher expect { expect { 3 }.to custom_matcher }.to fail_with(not_a_block_matcher_error) end def new_non_dsl_matcher(&method_defs) Module.new do def self.matches?(object); end def self.failure_message; end module_eval(&method_defs) end end it "uses the matcher's `description` in the error message" do custom_matcher = new_non_dsl_matcher do def self.supports_block_expectations?; false; end def self.description; "matcher-description"; end end expect { expect {}.to custom_matcher }.to fail_with(/\(matcher-description\)/) end context 'when the matcher does not define `description` (since it is an optional part of the protocol)' do it 'uses `inspect` in the error message instead' do custom_matcher = new_non_dsl_matcher do def self.supports_block_expectations?; false; end def self.inspect; "matcher-inspect"; end end expect { expect {}.to custom_matcher }.to fail_with(/\(matcher-inspect\)/) end end end end end end end rspec-expectations-3.13.0/spec/rspec/expectations/extensions/000077500000000000000000000000001455770000100243705ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/expectations/extensions/kernel_spec.rb000066400000000000000000000047771455770000100272260ustar00rootroot00000000000000RSpec.describe Object, "#should" do before(:example) do @target = "target" @matcher = double("matcher", :supports_value_expectations? => true) allow(@matcher).to receive(:matches?).and_return(true) allow(@matcher).to receive(:failure_message) end it "accepts and interacts with a matcher" do expect(@matcher).to receive(:matches?).with(@target).and_return(true) expect(@target).to @matcher end it "asks for a failure_message when matches? returns false" do expect(@matcher).to receive(:matches?).with(@target).and_return(false) expect(@matcher).to receive(:failure_message).and_return("the failure message") expect { expect(@target).to @matcher }.to fail_with("the failure message") end context "on interpreters that have BasicObject", :if => defined?(BasicObject) do let(:proxy_class) do Class.new(BasicObject) do def initialize(target) @target = target end def proxied? true end def respond_to?(method, *args) method.to_sym == :proxied? || @target.respond_to?(symbol, *args) end def method_missing(name, *args) @target.send(name, *args) end end end it 'works properly on BasicObject-subclassed proxy objects' do expect(proxy_class.new(Object.new)).to be_proxied end it 'does not break the deprecation check on BasicObject-subclassed proxy objects' do begin should_enabled = RSpec::Expectations::Syntax.should_enabled? RSpec::Expectations::Syntax.enable_should unless should_enabled proxy_class.new(BasicObject.new).should be_proxied ensure RSpec::Expectations::Syntax.disable_should if should_enabled end end end end RSpec.describe Object, "#should_not" do before(:example) do @target = "target" @matcher = double("matcher", :supports_value_expectations? => true) end it "accepts and interacts with a matcher" do expect(@matcher).to receive(:matches?).with(@target).and_return(false) allow(@matcher).to receive(:failure_message_when_negated) expect(@target).not_to @matcher end it "asks for a failure_message_when_negated when matches? returns true" do expect(@matcher).to receive(:matches?).with(@target).and_return(true) expect(@matcher).to receive(:failure_message_when_negated).and_return("the failure message for should not") expect { expect(@target).not_to @matcher }.to fail_with("the failure message for should not") end end rspec-expectations-3.13.0/spec/rspec/expectations/fail_with_spec.rb000066400000000000000000000042711455770000100255020ustar00rootroot00000000000000RSpec.describe RSpec::Expectations, "#fail_with" do let(:differ) { double("differ") } before(:example) do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) allow(RSpec::Expectations).to receive(:differ) { differ } end it "includes a diff if expected and actual are diffable" do expect(differ).to receive(:diff).and_return("diff text") expect { RSpec::Expectations.fail_with "message", "abc", "def" }.to fail_with("message\nDiff:diff text") end it "does not include the diff if expected and actual are not diffable" do expect(differ).to receive(:diff).and_return("") expect { RSpec::Expectations.fail_with "message", "abc", "def" }.to fail_with("message") end it "raises an error if message is not present" do expect(differ).not_to receive(:diff) expect { RSpec::Expectations.fail_with nil }.to raise_error(ArgumentError, /Failure message is nil\./) end end RSpec.describe RSpec::Expectations, "#fail_with with matchers" do include RSpec::Support::Spec::DiffHelpers before do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) end it "uses matcher descriptions in place of matchers in diffs" do expected = [a_string_matching(/foo/), a_string_matching(/bar/)] actual = ["poo", "car"] expected_diff = dedent(<<-EOS) | |@@ #{one_line_header} @@ |-["poo", "car"] |+[(a string matching /foo/), (a string matching /bar/)] | EOS expect { RSpec::Expectations.fail_with "message", actual, expected }.to fail_with("message\nDiff:#{expected_diff}") end end RSpec.describe RSpec::Expectations, "#fail_with with --color" do include RSpec::Support::Spec::DiffHelpers before do allow(RSpec::Matchers.configuration).to receive_messages(:color? => true) end it "tells the differ to use color" do expected = "foo bar baz\n" actual = "foo bang baz\n" expected_diff = "\e[0m\n\e[0m\e[34m@@ #{one_line_header} @@\n\e[0m\e[31m-foo bang baz\n\e[0m\e[32m+foo bar baz\n\e[0m" expect { RSpec::Expectations.fail_with "message", actual, expected }.to fail_with("message\nDiff:#{expected_diff}") end end rspec-expectations-3.13.0/spec/rspec/expectations/failure_aggregator_spec.rb000066400000000000000000000423311455770000100273640ustar00rootroot00000000000000module RSpec::Expectations RSpec.describe FailureAggregator, "when used via `aggregate_failures`" do it 'does not raise an error when no expectations fail' do expect { aggregate_failures do expect(1).to be_odd expect(2).to be_even expect(3).to be_odd end }.not_to raise_error end it 'returns true when no expectations fail' do expect( aggregate_failures do expect(1).to be_odd expect(2).to be_even expect(3).to be_odd end ).to eq true end it 'aggregates multiple failures into one exception that exposes all the failures' do expect { aggregate_failures('block label', :some => :metadata) do expect(1).to be_even expect(2).to be_odd expect(3).to be_even end }.to raise_error(an_object_having_attributes( :class => MultipleExpectationsNotMetError, :failures => [ an_object_having_attributes(:message => "expected `1.even?` to return true, got false"), an_object_having_attributes(:message => "expected `2.odd?` to return true, got false"), an_object_having_attributes(:message => "expected `3.even?` to return true, got false") ], :other_errors => [], :aggregation_block_label => 'block label', :aggregation_metadata => { :some => :metadata } )) end it 'ensures the exposed failures have backtraces' do aggregation_line = __LINE__ + 2 expect { aggregate_failures do expect(1).to be_even expect(2).to be_odd expect(3).to be_even end }.to raise_error do |error| expect(error.failures.map(&:backtrace)).to match [ a_collection_including(a_string_including(__FILE__, (aggregation_line + 1).to_s)), a_collection_including(a_string_including(__FILE__, (aggregation_line + 2).to_s)), a_collection_including(a_string_including(__FILE__, (aggregation_line + 3).to_s)) ] end end def common_contiguous_frame_percent(failure, aggregate) failure_frames = failure.backtrace.reverse aggregate_frames = aggregate.backtrace.reverse first_differing_index = failure_frames.zip(aggregate_frames).index { |f, a| f != a } 100 * (first_differing_index / failure_frames.count.to_f) end it 'ensures the sub-failure backtraces are in a form that overlaps with the aggregated failure backtrace' do if RSpec::Support::Ruby.jruby? pending "This is broken on 9.2.x.x" unless RSpec::Support::Ruby.jruby_version < '9.2.0.0' end # On JRuby, `caller` and `raise` backtraces can differ significantly -- # I've seen one include java frames but not the other -- and as a result, # the backtrace truncation rspec-core does (based on the common part) fails # and produces undesirable output. This spec is a guard against that. expect { aggregate_failures do expect(1).to be_even expect(2).to be_odd end }.to raise_error do |error| failure_1, failure_2 = error.failures expect(common_contiguous_frame_percent(failure_1, error)).to be > 70 expect(common_contiguous_frame_percent(failure_2, error)).to be > 70 end end def notify_error_with(backtrace) exception = Exception.new exception.set_backtrace backtrace RSpec::Support.notify_failure(exception) end it 'does not stomp the backtrace on failures that have it' do backtrace = ["./foo.rb:13"] expect { aggregate_failures do notify_error_with(backtrace) notify_error_with(backtrace) end }.to raise_error do |error| expect(error.failures.map(&:backtrace)).to eq([backtrace, backtrace]) end end it 'supports nested `aggregate_failures` blocks' do expect { aggregate_failures("outer") do aggregate_failures("inner 2") do expect(2).to be_odd expect(3).to be_even end aggregate_failures("inner 1") do expect(1).to be_even end expect(1).to be_even end }.to raise_error do |error| aggregate_failures("failure expectations") do expect(error.failures.count).to eq(3) expect(error.failures[0]).to be_an_instance_of(RSpec::Expectations::MultipleExpectationsNotMetError) expect(error.failures[0].failures.count).to eq(2) expect(error.failures[1]).to be_an_instance_of(RSpec::Expectations::ExpectationNotMetError) expect(error.failures[2]).to be_an_instance_of(RSpec::Expectations::ExpectationNotMetError) end end end it 'raises a normal `ExpectationNotMetError` when only one expectation fails' do expect { aggregate_failures do expect(1).to be_odd expect(2).to be_odd expect(3).to be_odd end }.to fail_with("expected `2.odd?` to return true, got false") end context "when multiple exceptions are notified with the same `:source_id`" do it 'keeps only the first' do expect { aggregate_failures do RSpec::Support.notify_failure(StandardError.new("e1"), :source_id => "1") RSpec::Support.notify_failure(StandardError.new("e2"), :source_id => "2") RSpec::Support.notify_failure(StandardError.new("e3"), :source_id => "1") RSpec::Support.notify_failure(StandardError.new("e4"), :source_id => "1") end }.to raise_error do |e| expect(e.failures).to match [ an_object_having_attributes(:message => "e1"), an_object_having_attributes(:message => "e2") ] end end end context "when an error other than an expectation failure occurs" do def expect_error_included_in_aggregated_failure(error) expect { aggregate_failures do expect(2).to be_odd raise error end }.to raise_error(an_object_having_attributes( :class => MultipleExpectationsNotMetError, :failures => [an_object_having_attributes( :message => "expected `2.odd?` to return true, got false" )], :other_errors => [error] )) end it "includes the error in the raised aggregated failure when an expectation failed as well" do expect_error_included_in_aggregated_failure StandardError.new("boom") end it "handles direct `Exceptions` and not just `StandardError` and descendents" do expect_error_included_in_aggregated_failure Exception.new("boom") end it "allows the error to propagate as-is if there have been no expectation failures so far" do error = StandardError.new("boom") expect { aggregate_failures do raise error end }.to raise_error(error) end it "prevents later expectations from even running" do error = StandardError.new("boom") later_expectation_executed = false expect { aggregate_failures do raise error later_expectation_executed = true # rubocop:disable Lint/UnreachableCode expect(1).to eq(1) end }.to raise_error(error) expect(later_expectation_executed).to be false end it 'provides an `all_exceptions` array containing failures and other errors' do error = StandardError.new("boom") expect { aggregate_failures do expect(2).to be_odd raise error end }.to raise_error do |aggregate_error| expect(aggregate_error).to have_attributes( :class => MultipleExpectationsNotMetError, :all_exceptions => [ an_object_having_attributes(:message => "expected `2.odd?` to return true, got false"), error ] ) end end end context "when an expectation failure happens in another thread" do # On Ruby 2.5+, the new `report_on_exception` causes the errors in the threads # to print warnings, which our rspec-support test harness converts into a test # failure since we want to enforce warnings-free code. To prevent the warning, # we need to disable the setting here. if Thread.respond_to?(:report_on_exception) around do |example| orig = Thread.report_on_exception Thread.report_on_exception = false example.run Thread.report_on_exception = orig end end it "includes the failure in the failures array if there are other failures" do expect { aggregate_failures do expect(1).to be_even Thread.new { expect(2).to be_odd }.join end }.to raise_error(an_object_having_attributes( :class => MultipleExpectationsNotMetError, :failures => [ an_object_having_attributes(:message => "expected `1.even?` to return true, got false"), an_object_having_attributes(:message => "expected `2.odd?` to return true, got false") ], :other_errors => [] )) end it "propagates it as-is if there are no other failures or errors" do expect { aggregate_failures { Thread.new { expect(2).to be_odd }.join } }.to fail_with("expected `2.odd?` to return true, got false") end end describe 'with MockExpectationError' do it 'does not allow modifications of the failure list in the test example' do expect { aggregate_failures do dbl = double array = dbl.get(2) array << :foo end }.to raise_error( be_a(MultipleExpectationsNotMetError).and have_attributes( :failures => [ be_a(RSpec::Mocks::MockExpectationError) ], :other_errors => [ # Checking only the class name, not the full message, because the hehaviour differes bettern Ruby 2 and 3. # Ruby 3 uses #inspect in NoMethodError, while Ruby 2.x uses format that I can't override: # NoMethodError (undefined method `<<' for #) # even if I override #to_s be_a(NoMethodError).and(have_attributes(:message => /AggregatedFailure/)) ] ) ) end end describe "message formatting" do it "enumerates the failures with an index label, the path of each failure and a blank line in between" do expect { aggregate_failures do expect(1).to be_even expect(2).to be_odd expect(3).to be_even end }.to fail_including { dedent <<-EOS } | 1) expected `1.even?` to return true, got false | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 6}#{exception_complement(5)} | | 2) expected `2.odd?` to return true, got false | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 8}#{exception_complement(5)} | | 3) expected `3.even?` to return true, got false | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 10}#{exception_complement(5)} EOS end it 'mentions how many failures there are' do expect { aggregate_failures do expect(1).to be_even expect(2).to be_odd expect(3).to be_even end }.to fail_including { dedent <<-EOS } |Got 3 failures from failure aggregation block: | | 1) expected `1.even?` to return true, got false EOS end it 'allows the user to name the `aggregate_failures` block' do expect { aggregate_failures("testing odd vs even") do expect(1).to be_even expect(2).to be_odd expect(3).to be_even end }.to fail_including { dedent <<-EOS } |Got 3 failures from failure aggregation block "testing odd vs even": | | 1) expected `1.even?` to return true, got false EOS end context "when another error has occcured" do it 'includes it in the failure message' do expect { aggregate_failures do expect(1).to be_even raise "boom" end }.to fail_including { dedent <<-EOS } |Got 1 failure and 1 other error from failure aggregation block: | | 1) expected `1.even?` to return true, got false | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 7}#{exception_complement(6)} | | 2) RuntimeError: boom | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 9}#{exception_complement(6)} EOS end end context "when the failure messages have multiple lines" do RSpec::Matchers.define :fail_with_multiple_lines do match { false } failure_message do |actual| "line 1\n#{actual}\nline 3" end end it "indents them appropriately so that they still line up" do expect { aggregate_failures do expect(:a).to fail_with_multiple_lines expect(:b).to fail_with_multiple_lines end }.to fail_including { dedent <<-EOS } | 1) line 1 | a | line 3 | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 7}#{exception_complement(6)} | | 2) line 1 | b | line 3 | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 11}#{exception_complement(6)} EOS end it 'accounts for the width of the index when indenting' do expect { aggregate_failures do 1.upto(10) do |i| expect(i).to fail_with_multiple_lines end end }.to fail_including { dedent <<-EOS } | 9) line 1 | 9 | line 3 | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 7}#{exception_complement(7)} | | 10) line 1 | 10 | line 3 | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 12}#{exception_complement(7)} EOS end end context "when the failure messages starts and ends with line breaks (as the `eq` failure message does)" do before do expect { expect(1).to eq(2) }.to fail_with( a_string_starting_with("\n") & ending_with("\n") ) end it 'strips the excess line breaks so that it formats well' do expect { aggregate_failures do expect(1).to eq 2 expect(1).to eq 3 expect(1).to eq 4 end }.to fail_including { dedent <<-EOS } | 1) expected: 2 | got: 1 | | (compared using ==) | | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 10}#{exception_complement(6)} | | 2) expected: 3 | got: 1 | | (compared using ==) | | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 16}#{exception_complement(6)} | | 3) expected: 4 | got: 1 | | (compared using ==) | | ./spec/rspec/expectations/failure_aggregator_spec.rb:#{__LINE__ - 22}#{exception_complement(6)} EOS end end # Use a normal `expect(...).to include` expectation rather than # a composed matcher here. This provides better failure output # because `MultipleExpectationsNotMetError#message` is lazily # computed (rather than being computed in `initialize` and passed # to `super`), which causes the `inspect` output of the exception # to not include the message for some reason. def fail_including fail { |e| expect(e.message).to include(yield) } end # Each Ruby version return a different exception complement. # This method gets the current version and return the # right complement. if RSpec::Support::Ruby.mri? && RUBY_VERSION > "1.8.7" def exception_complement(block_levels) ":in `block (#{block_levels} levels) in '" end elsif RSpec::Support::Ruby.mri? def exception_complement(block_levels) "" end elsif RSpec::Support::Ruby.truffleruby? def exception_complement(block_levels) ":in `block (#{block_levels} levels) in '" end elsif RUBY_VERSION > "2.0.0" def exception_complement(block_levels) ":in `block in Expectations'" end else def exception_complement(block_levels) ":in `Expectations'" end end end end end rspec-expectations-3.13.0/spec/rspec/expectations/handler_spec.rb000066400000000000000000000225721455770000100251550ustar00rootroot00000000000000module ExampleExpectations class ArbitraryMatcher def initialize(*args, &block) if args.last.is_a? Hash @expected = args.last[:expected] end @expected = yield if block @block = block end def matches?(target) @target = target return @expected == target end def with(new_value) @expected = new_value self end def failure_message "expected #{@expected}, got #{@target}" end def failure_message_when_negated "expected not #{@expected}, got #{@target}" end end class PositiveOnlyMatcher < ArbitraryMatcher undef failure_message_when_negated rescue nil end def arbitrary_matcher(*args, &block) ArbitraryMatcher.new(*args, &block) end def positive_only_matcher(*args, &block) PositiveOnlyMatcher.new(*args, &block) end end module RSpec module Expectations RSpec.describe PositiveExpectationHandler do include ExampleExpectations it "handles submitted args" do expect(5).to arbitrary_matcher(:expected => 5) expect(5).to arbitrary_matcher(:expected => "wrong").with(5) expect { expect(5).to arbitrary_matcher(:expected => 4) }.to fail_with("expected 4, got 5") expect { expect(5).to arbitrary_matcher(:expected => 5).with(4) }.to fail_with("expected 4, got 5") expect(5).not_to arbitrary_matcher(:expected => 4) expect(5).not_to arbitrary_matcher(:expected => 5).with(4) expect { expect(5).not_to arbitrary_matcher(:expected => 5) }.to fail_with("expected not 5, got 5") expect { expect(5).not_to arbitrary_matcher(:expected => 4).with(5) }.to fail_with("expected not 5, got 5") end it "handles the submitted block" do expect(5).to arbitrary_matcher { 5 } expect(5).to arbitrary_matcher(:expected => 4) { 5 } expect(5).to arbitrary_matcher(:expected => 4).with(5) { 3 } end describe "#handle_matcher" do it "asks the matcher if it matches" do matcher = double("matcher") actual = Object.new expect(matcher).to receive(:matches?).with(actual).and_return(true) RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher) end it "returns the match value" do matcher = double("matcher") actual = Object.new expect(matcher).to receive(:matches?).with(actual).and_return(:this_value) expect(RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher)).to eq :this_value end it "calls failure_message if the matcher implements it" do matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("message") RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher) end it "calls fail if matcher.diffable?" do matcher = double("matcher", :diffable? => true, :failure_message => "message", :matches? => false, :expected => 1, :actual => 2 ) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("message", 1, 2) RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher) end it "calls failure_message if the matcher does not implement failure_message" do matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("message") RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher) end it "uses the custom failure message when one is provided" do matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("custom") RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher, "custom") end it "uses the custom failure message when one is provided as a callable object" do matcher = double("matcher", :failure_message => "message", :matches? => false) actual = Object.new failure_message = double("failure message", :call => "custom") expect(::RSpec::Expectations).to receive(:fail_with).with("custom") RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher, failure_message) end it "add custom failure message to mock matcher if there is one" do error_generator = instance_double("RSpec::Mocks::ErrorGenerator", :opts => { :message => {} }) verifying_message_expectation = instance_double( "RSpec::Mocks::VerifyingMessageExpectation", :error_generator => error_generator ) matcher = double("matcher", :failure_message => "message", :matches? => verifying_message_expectation) actual = Object.new handle_matcher_result = RSpec::Expectations::PositiveExpectationHandler.handle_matcher(actual, matcher, "custom") expect(handle_matcher_result.error_generator.opts).to eq({ :message => "custom" }) end end end RSpec.describe NegativeExpectationHandler do describe "#handle_matcher" do context "when the matcher responds to `does_not_match?`" do it "returns true when `does_not_match?` returns true" do matcher = double("matcher") actual = Object.new expect(matcher).to receive(:does_not_match?).with(actual).and_return(true) expect(RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher)).to be_truthy end it "raises an expectation failure when `does_not_match?` returns false" do matcher = double("matcher", :failure_message_when_negated => "Error!") actual = Object.new expect(matcher).to receive(:does_not_match?).with(actual).and_return(false) expect { RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, "Error!") end end context "when the matcher does not respond to `does_not_match?`" do it "returns true when `matches?` returns false" do matcher = double("matcher") actual = Object.new expect(matcher).to receive(:matches?).with(actual).and_return(false) expect(RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher)).to be_truthy end it "raises an expectation failure when `matches?` returns true" do matcher = double("matcher", :failure_message_when_negated => "Error!") actual = Object.new expect(matcher).to receive(:matches?).with(actual).and_return(true) expect { RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) }.to raise_error(RSpec::Expectations::ExpectationNotMetError, "Error!") end end it "calls fail if matcher.diffable?" do matcher = double("matcher", :diffable? => true, :failure_message_when_negated => "message", :matches? => true, :expected => 1, :actual => 2 ) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("message", 1, 2) RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher) end it "uses the custom failure message when one is provided" do matcher = double("matcher", :failure_message_when_negated => "message", :matches? => true) actual = Object.new expect(::RSpec::Expectations).to receive(:fail_with).with("custom") RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher, "custom") end it "uses the custom failure message when one is provided as a callable object" do matcher = double("matcher", :failure_message_when_negated => "message", :matches? => true) actual = Object.new failure_message = double("failure message", :call => "custom") expect(::RSpec::Expectations).to receive(:fail_with).with("custom") RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher, failure_message) end it "add custom failure message to mock matcher if there is one" do error_generator = instance_double("RSpec::Mocks::ErrorGenerator", :opts => { :message => {} }) verifying_message_expectation = instance_double( "RSpec::Mocks::VerifyingMessageExpectation", :error_generator => error_generator ) matcher = double( "matcher", :failure_message_when_negated => "custom", :does_not_match? => verifying_message_expectation ) actual = Object.new handle_matcher_result = RSpec::Expectations::NegativeExpectationHandler.handle_matcher(actual, matcher, "custom") expect(handle_matcher_result.error_generator.opts).to eq({ :message => "custom" }) end end end end end rspec-expectations-3.13.0/spec/rspec/expectations/minitest_integration_spec.rb000066400000000000000000000011331455770000100277650ustar00rootroot00000000000000module RSpec RSpec.describe Matchers do let(:sample_matchers) do [:be, :be_instance_of, :be_kind_of] end context "once required", :slow do include MinitestIntegration it "includes itself in Minitest::Test, and sets up our exceptions to be counted as assertion failures" do with_minitest_loaded do minitest_case = ::Minitest::Test.allocate expect(minitest_case).to respond_to(*sample_matchers) expect(RSpec::Expectations::ExpectationNotMetError).to be ::Minitest::Assertion end end end end end rspec-expectations-3.13.0/spec/rspec/expectations/syntax_spec.rb000066400000000000000000000062271455770000100250650ustar00rootroot00000000000000module RSpec module Expectations RSpec.describe Syntax do context "when passing a message to an expectation" do let(:warner) { ::Kernel } let(:string_like_object) do Struct.new(:to_str, :to_s).new(*(["Ceci n'est pas une Chaine."]*2)) end let(:insufficiently_string_like_object) do Struct.new(:to_s).new("Ceci n'est pas une Chaine.") end let(:callable_object) do Struct.new(:call).new("Ceci n'est pas une Chaine.") end describe "expect(...).to" do it "prints a warning when the message object isn't a String" do expect(warner).to receive(:warn).with(/ignoring.*message/) expect(3).to eq(3), :not_a_string end it "doesn't print a warning when message is a String" do expect(warner).not_to receive(:warn) expect(3).to eq(3), "a string" end it "doesn't print a warning when message responds to to_str" do expect(warner).not_to receive(:warn) expect(3).to eq(3), string_like_object end it "prints a warning when the message object handles to_s but not to_str" do expect(warner).to receive(:warn).with(/ignoring.*message/) expect(3).to eq(3), insufficiently_string_like_object end it "doesn't print a warning when message responds to call" do expect(warner).not_to receive(:warn) expect(3).to eq(3), callable_object end end describe "expect(...).not_to" do it "prints a warning when the message object isn't a String" do expect(warner).to receive(:warn).with(/ignoring.*message/) expect(3).not_to eq(4), :not_a_string end it "doesn't print a warning when message is a String" do expect(warner).not_to receive(:warn) expect(3).not_to eq(4), "a string" end it "doesn't print a warning when message responds to to_str" do expect(warner).not_to receive(:warn) expect(3).not_to eq(4), string_like_object end it "prints a warning when the message object handles to_s but not to_str" do expect(warner).to receive(:warn).with(/ignoring.*message/) expect(3).not_to eq(4), insufficiently_string_like_object end it "doesn't print a warning when message responds to call" do expect(warner).not_to receive(:warn) expect(3).not_to eq(4), callable_object end end end describe "enabling the should syntax on something other than the default syntax host" do include_context "with the default expectation syntax" it "continues to warn about the should syntax" do my_host = Class.new expect(RSpec).to receive(:deprecate) Syntax.enable_should(my_host) 3.should eq 3 end end end end RSpec.describe Expectations do it "does not inadvertently define BasicObject on 1.8", :if => RUBY_VERSION.to_f < 1.9 do expect(defined?(::BasicObject)).to be nil end end end rspec-expectations-3.13.0/spec/rspec/expectations_spec.rb000066400000000000000000000016441455770000100235350ustar00rootroot00000000000000require 'rspec/support/spec/library_wide_checks' RSpec.describe "RSpec::Expectations" do allowed_loaded_features = [ /stringio/, # Used by `output` matcher. Can't be easily avoided. /rbconfig/ # required by rspec-support ] # Truffleruby cext files allowed_loaded_features << /\/truffle\/cext/ if RSpec::Support::Ruby.truffleruby? it_behaves_like "library wide checks", "rspec-expectations", :preamble_for_lib => [ # We define minitest constants because rspec/expectations/minitest_integration # expects these constants to already be defined. "module Minitest; class Assertion; end; module Test; end; end", 'require "rspec/expectations"' ], :allowed_loaded_feature_regexps => allowed_loaded_features it 'does not allow expectation failures to be caught by a bare rescue' do expect { expect(2).to eq(3) rescue nil }.to fail_including("expected: 3") end end rspec-expectations-3.13.0/spec/rspec/matchers/000077500000000000000000000000001455770000100212715ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/matchers/aliased_matcher_spec.rb000066400000000000000000000117321455770000100257410ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe AliasedMatcher do RSpec::Matchers.define :my_base_matcher do match { |actual| actual == foo } def foo 13 end def description "my base matcher description" end end RSpec::Matchers.alias_matcher :alias_of_my_base_matcher, :my_base_matcher it_behaves_like "an RSpec value matcher", :valid_value => 13, :invalid_value => nil do let(:matcher) { alias_of_my_base_matcher } end shared_examples "making a copy" do |copy_method| context "when making a copy via `#{copy_method}`" do it "uses a copy of the base matcher" do base_matcher = include(3) aliased = AliasedMatcher.new(base_matcher, Proc.new {}) copy = aliased.__send__(copy_method) expect(copy).not_to equal(aliased) expect(copy.base_matcher).not_to equal(base_matcher) expect(copy.base_matcher).to be_a(RSpec::Matchers::BuiltIn::Include) expect(copy.base_matcher.expected).to eq([3]) end it "copies custom matchers properly so they can work even though they have singleton behavior" do base_matcher = my_base_matcher aliased = AliasedMatcher.new(base_matcher, Proc.new { |a| a }) copy = aliased.__send__(copy_method) expect(copy).not_to equal(aliased) expect(copy.base_matcher).not_to equal(base_matcher) expect(13).to copy expect { expect(15).to copy }.to fail_with(/expected 15/) end end end include_examples "making a copy", :dup include_examples "making a copy", :clone it 'can get a method object for delegated methods', :if => (RUBY_VERSION.to_f > 1.8) do matcher = my_base_matcher decorated = AliasedMatcher.new(matcher, Proc.new {}) expect(decorated.method(:foo).call).to eq(13) end it 'can get a method object for `description`' do matcher = my_base_matcher decorated = AliasedMatcher.new(matcher, Proc.new { "overridden description" }) expect(decorated.method(:description).call).to eq("overridden description") end RSpec::Matchers.alias_matcher :my_overridden_matcher, :my_base_matcher do |desc| desc + " (overridden)" end it 'overrides the description with the provided block' do matcher = my_overridden_matcher expect(matcher.description).to eq("my base matcher description (overridden)") end RSpec::Matchers.alias_matcher :my_blockless_override, :my_base_matcher it 'provides a default description override based on the old and new games' do matcher = my_blockless_override expect(matcher.description).to eq("my blockless override description") end it 'works properly with a chained method off a negated matcher' do expect {}.to avoid_outputting.to_stdout expect { expect { $stdout.puts "a" }.to avoid_outputting.to_stdout }.to fail end if RSpec::Support::RubyFeatures.kw_args_supported? eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 class MyKeywordMatcher def initialize(**kwargs); end def matches?(other); true === other; end end RUBY if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash? eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 def my_keyword_matcher(...) = MyKeywordMatcher.new(...) RUBY else eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 def my_keyword_matcher(**kw); MyKeywordMatcher.new(**kw); end RUBY end eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 RSpec::Matchers.alias_matcher :my_keyword_override, :my_keyword_matcher RSpec::Matchers.define_negated_matcher :not_keyword_override, :my_keyword_matcher it 'works properly with a keyword arguments matcher' do expect(true).to my_keyword_override(some: :arg) end it 'works properly with a negated keyword arguments matcher' do expect(false).to not_keyword_override(some: :arg) end RUBY end context "when negating a matcher that does not define `description` (which is an optional part of the matcher protocol)" do def matcher_without_description matcher = Object.new def matcher.matches?(v); v; end def matcher.failure_message; "match failed"; end def matcher.chained; self; end expect(RSpec::Matchers.is_a_matcher?(matcher)).to be true matcher end RSpec::Matchers.define_negated_matcher :negation_of_matcher_without_description, :matcher_without_description it 'works properly' do expect(true).to matcher_without_description.chained expect(false).to negation_of_matcher_without_description.chained end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/aliases_spec.rb000066400000000000000000000251451455770000100242600ustar00rootroot00000000000000module RSpec RSpec.describe Matchers, "aliases", :order => :defined do matcher :be_aliased_to do |old_matcher| chain :with_description do |desc| @expected_desc = desc end match do |aliased_matcher| @actual_desc = aliased_matcher.description @actual_desc == @expected_desc && aliased_matcher.base_matcher.class == old_matcher.class end failure_message do |aliased_matcher| "expected #{aliased_matcher} to be aliased to #{old_matcher} with " \ "description: #{@expected_desc.inspect}, but got #{@actual_desc.inspect}" end description do |_aliased_matcher| "have an alias for #{old_matcher.description.inspect} with description: #{@expected_desc.inspect}" end end specify do expect(a_truthy_value).to be_aliased_to(be_truthy).with_description("a truthy value") end specify do expect(a_falsey_value).to be_aliased_to(be_falsey).with_description("a falsey value") end specify do expect(be_falsy).to be_aliased_to(be_falsey).with_description("be falsy") end specify do expect(a_falsy_value).to be_aliased_to(be_falsey).with_description("a falsy value") end specify do expect(a_nil_value).to be_aliased_to(be_nil).with_description("a nil value") end specify do expect(a_value > 3).to be_aliased_to(be > 3).with_description("a value > 3") end specify do expect(a_value < 3).to be_aliased_to(be < 3).with_description("a value < 3") end specify do expect(a_value <= 3).to be_aliased_to(be <= 3).with_description("a value <= 3") end specify do expect(a_value == 3).to be_aliased_to(be == 3).with_description("a value == 3") end specify do expect(a_value === 3).to be_aliased_to(be === 3).with_description("a value === 3") end specify do expect( an_instance_of(Integer) ).to be_aliased_to( be_an_instance_of(Integer) ).with_description("an instance of Integer") end specify do expect( a_kind_of(Integer) ).to be_aliased_to( be_a_kind_of(Integer) ).with_description("a kind of Integer") end specify do expect( a_value_between(1, 10) ).to be_aliased_to( be_between(1, 10) ).with_description("a value between 1 and 10 (inclusive)") end specify do expect( a_value_within(0.1).of(3) ).to be_aliased_to( be_within(0.1).of(3) ).with_description("a value within 0.1 of 3") end specify do expect( within(0.1).of(3) ).to be_aliased_to( be_within(0.1).of(3) ).with_description("within 0.1 of 3") end specify do expect(a_block_changing).to be_aliased_to(change).with_description("a block changing result") end specify do expect(changing).to be_aliased_to(change).with_description("changing result") end specify do expect( a_collection_containing_exactly(1, 2) ).to be_aliased_to( contain_exactly(1, 2) ).with_description("a collection containing exactly 1 and 2") end specify do expect( containing_exactly(1, 2) ).to be_aliased_to( contain_exactly(1, 2) ).with_description("containing exactly 1 and 2") end specify do expect( a_range_covering(1, 2) ).to be_aliased_to( cover(1, 2) ).with_description("a range covering 1 and 2") end specify do expect( covering(1, 2) ).to be_aliased_to( cover(1, 2) ).with_description("covering 1 and 2") end specify do expect( ending_with(23) ).to be_aliased_to( end_with(23) ).with_description("ending with 23") end specify do expect( a_collection_ending_with(23) ).to be_aliased_to( end_with(23) ).with_description("a collection ending with 23") end specify do expect( a_string_ending_with("z") ).to be_aliased_to( end_with("z") ).with_description('a string ending with "z"') end specify do expect( an_object_eq_to(3) ).to be_aliased_to(eq 3).with_description("an object eq to 3") end specify do expect( eq_to(3) ).to be_aliased_to(eq 3).with_description("eq to 3") end specify do expect( an_object_eql_to(3) ).to be_aliased_to(eql 3).with_description("an object eql to 3") end specify do expect( eql_to(3) ).to be_aliased_to(eql 3).with_description("eql to 3") end specify do expect( an_object_equal_to(3) ).to be_aliased_to(equal 3).with_description("an object equal to 3") end specify do expect( equal_to(3) ).to be_aliased_to(equal 3).with_description("equal to 3") end specify do expect( an_object_existing ).to be_aliased_to(exist).with_description("an object existing") end specify do expect(existing).to be_aliased_to(exist).with_description("existing") end specify do expect( an_object_having_attributes(:age => 32) ).to be_aliased_to( have_attributes(:age => 32) ).with_description("an object having attributes {:age => 32}") end specify do expect( having_attributes(:age => 32) ).to be_aliased_to( have_attributes(:age => 32) ).with_description("having attributes {:age => 32}") end specify do expect( a_string_including("a") ).to be_aliased_to( include("a") ).with_description('a string including "a"') end specify do expect( a_collection_including("a") ).to be_aliased_to( include("a") ).with_description('a collection including "a"') end specify do expect( a_hash_including(:a => 5) ).to be_aliased_to( include(:a => 5) ).with_description('a hash including {:a => 5}') end specify do expect( including(3) ).to be_aliased_to( include(3) ).with_description('including 3') end specify do expect( a_string_matching(/foo/) ).to be_aliased_to( match(/foo/) ).with_description('a string matching /foo/') end specify do expect( an_object_matching(/foo/) ).to be_aliased_to( match(/foo/) ).with_description('an object matching /foo/') end specify do expect( match_regex(/foo/) ).to be_aliased_to( match(/foo/) ).with_description('match regex /foo/') end specify do expect( matching(/foo/) ).to be_aliased_to( match(/foo/) ).with_description('matching /foo/') end specify do expect( an_array_matching([1, 2]) ).to be_aliased_to( match_array([1, 2]) ).with_description('an array containing exactly 1 and 2') end specify do expect( a_block_outputting('foo').to_stdout ).to be_aliased_to( output('foo').to_stdout ).with_description('a block outputting "foo" to stdout') end specify do expect( a_block_outputting('foo').to_stderr ).to be_aliased_to( output('foo').to_stderr ).with_description('a block outputting "foo" to stderr') end specify do expect( a_block_raising(ArgumentError) ).to be_aliased_to( raise_error(ArgumentError) ).with_description('a block raising ArgumentError') end specify do expect( raising(ArgumentError) ).to be_aliased_to( raise_error(ArgumentError) ).with_description("raising ArgumentError") end specify do expect( an_object_responding_to(:foo) ).to be_aliased_to( respond_to(:foo) ).with_description("an object responding to #foo") end specify do expect( responding_to(:foo) ).to be_aliased_to( respond_to(:foo) ).with_description("responding to #foo") end specify do expect( an_object_satisfying {} ).to be_aliased_to( satisfy {} ).with_description("an object satisfying block") end specify do expect( satisfying {} ).to be_aliased_to( satisfy {} ).with_description("satisfying block") end specify do expect( a_collection_starting_with(23) ).to be_aliased_to( start_with(23) ).with_description("a collection starting with 23") end specify do expect( a_string_starting_with("z") ).to be_aliased_to( start_with("z") ).with_description('a string starting with "z"') end specify do expect( starting_with("d") ).to be_aliased_to( start_with("d") ).with_description('starting with "d"') end specify do expect( a_block_throwing(:foo) ).to be_aliased_to( throw_symbol(:foo) ).with_description("a block throwing :foo") end specify do expect( throwing(:foo) ).to be_aliased_to( throw_symbol(:foo) ).with_description("throwing :foo") end specify do expect( a_block_yielding_control ).to be_aliased_to( yield_control ).with_description("a block yielding control") end specify do expect( yielding_control ).to be_aliased_to( yield_control ).with_description("yielding control") end specify do expect( a_block_yielding_with_no_args ).to be_aliased_to( yield_with_no_args ).with_description("a block yielding with no args") end specify do expect( yielding_with_no_args ).to be_aliased_to( yield_with_no_args ).with_description("yielding with no args") end specify do expect( a_block_yielding_with_args ).to be_aliased_to( yield_with_args ).with_description("a block yielding with args") end specify do expect( yielding_with_args ).to be_aliased_to( yield_with_args ).with_description("yielding with args") end specify do expect( a_block_yielding_successive_args ).to be_aliased_to( yield_successive_args ).with_description("a block yielding successive args()") end specify do expect( yielding_successive_args ).to be_aliased_to( yield_successive_args ).with_description("yielding successive args()") end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/000077500000000000000000000000001455770000100230765ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/rspec/matchers/built_in/all_spec.rb000066400000000000000000000177731455770000100252240ustar00rootroot00000000000000module RSpec::Matchers::BuiltIn RSpec.describe All do it_behaves_like 'an RSpec value matcher', :valid_value => ['A', 'A', 'A'], :invalid_value => ['A', 'A', 'B'], :disallows_negation => true do let(:matcher) { all( eq('A') ) } end describe 'description' do it 'provides a description' do matcher = all( eq('A') ) expect(matcher.description).to eq 'all eq "A"' end end context 'when single matcher is given' do describe 'expect(...).to all(expected)' do it 'can pass' do expect(['A', 'A', 'A']).to all( eq('A') ) end describe 'failure message' do context 'when the matcher has single-line failure message' do it 'returns the index of the failed object' do expect { expect(['A', 'A', 'A', 5, 'A']).to all( be_a(String) ) }.to fail_with(dedent <<-EOS) |expected ["A", "A", "A", 5, "A"] to all be a kind of String | | object at index 3 failed to match: | expected 5 to be a kind of String EOS end it 'returns the indexes of all failed objects, not just the first one' do expect { expect(['A', 'A', 'A', 5, 6]).to all( be_a(String) ) }.to fail_with(dedent <<-EOS) |expected ["A", "A", "A", 5, 6] to all be a kind of String | | object at index 3 failed to match: | expected 5 to be a kind of String | | object at index 4 failed to match: | expected 6 to be a kind of String EOS end end context 'when the matcher has multi-line failure message' do it 'returns the index of the failed object' do expect { expect(['A', 'A', 'A', 'C', 'A']).to all( eq('A') ) }.to fail_with(dedent <<-EOS) |expected ["A", "A", "A", "C", "A"] to all eq "A" | | object at index 3 failed to match: | expected: "A" | got: "C" | | (compared using ==) EOS end it 'returns the indexes of all failed objects, not just the first one' do expect { expect(['A', 'B', 'A', 'C', 'A']).to all( eq('A') ) }.to fail_with(dedent <<-EOS) |expected ["A", "B", "A", "C", "A"] to all eq "A" | | object at index 1 failed to match: | expected: "A" | got: "B" | | (compared using ==) | | object at index 3 failed to match: | expected: "A" | got: "C" | | (compared using ==) EOS end end end end end context 'when composed matcher is given' do describe 'expect(...).to all(expected)' do it 'can pass' do expect([3, 4, 7, 8]).to all( be_between(2, 5).or be_between(6, 9) ) end end describe 'failure message' do context 'when a single object fails' do it 'returns the index of the failed object for the composed matcher' do expect { expect([3, 4, 7, 28]).to all( be_between(2, 5).or be_between(6, 9) ) }.to fail_with(dedent <<-EOS) |expected [3, 4, 7, 28] to all be between 2 and 5 (inclusive) or be between 6 and 9 (inclusive) | | object at index 3 failed to match: | expected 28 to be between 2 and 5 (inclusive) | | ...or: | | expected 28 to be between 6 and 9 (inclusive) EOS end end context 'when a multiple objects fails' do it 'returns the indexes of the failed objects for the composed matcher, not just the first one' do expect { expect([3, 4, 27, 22]).to all( be_between(2, 5).or be_between(6, 9) ) }.to fail_with(dedent <<-EOS) |expected [3, 4, 27, 22] to all be between 2 and 5 (inclusive) or be between 6 and 9 (inclusive) | | object at index 2 failed to match: | expected 27 to be between 2 and 5 (inclusive) | | ...or: | | expected 27 to be between 6 and 9 (inclusive) | | object at index 3 failed to match: | expected 22 to be between 2 and 5 (inclusive) | | ...or: | | expected 22 to be between 6 and 9 (inclusive) EOS end end end end context 'when composed in another matcher' do it 'returns the indexes of the failed objects only' do expect { expect([[false], [true]]).to all( all( be(true) ) ) }.to fail_with(dedent <<-EOS) |expected [[false], [true]] to all all equal true | | object at index 0 failed to match: | expected [false] to all equal true | | object at index 0 failed to match: | expected true | got false EOS end end shared_examples "making a copy" do |copy_method| context "when making a copy via `#{copy_method}`" do let(:base_matcher) { eq(3) } let(:all_matcher) { all( base_matcher ) } let(:copied_matcher) { all_matcher.__send__(copy_method) } it "uses a copy of the base matcher" do expect(copied_matcher).not_to equal(all_matcher) expect(copied_matcher.matcher).not_to equal(base_matcher) expect(copied_matcher.matcher).to be_a(base_matcher.class) expect(copied_matcher.matcher.expected).to eq(3) end context 'when using a custom matcher' do let(:base_matcher) { custom_include(3) } it 'copies custom matchers properly so they can work even though they have singleton behavior' do expect(copied_matcher).not_to equal(all_matcher) expect(copied_matcher.matcher).not_to equal(base_matcher) expect([[3]]).to copied_matcher expect { expect([[4]]).to copied_matcher }.to fail_including("expected [4]") end end end end include_examples 'making a copy', :clone include_examples 'making a copy', :dup context "when using a matcher instance that memoizes state multiple times in a composed expression" do it "works properly in spite of the memoization" do expect { expect(["foo", "bar", "a"]).to all( have_string_length(3) ) }.to fail end context "when passing a compound expression" do it "works properly in spite of the memoization" do expect { expect(["foo", "bar", "a"]).to all( have_string_length(2).or have_string_length(3) ) }.to fail end end end context 'when the actual data does not define #each_with_index' do let(:actual) { 5 } it 'returns a failure message' do expect { expect(actual).to all(be_a(String)) }.to fail_with("expected #{actual.inspect} to all be a kind of String, but was not iterable") end end context 'when the actual data does not include enumerable but defines #each_with_index' do let(:actual) do obj = Object.new def obj.each_with_index(&_block); [5].each_with_index { |o, i| yield(o, i) }; end obj end it 'passes properly' do expect(actual).to all(be_a(Integer)) end it 'fails properly' do expect { expect(actual).to all(be_even) }.to fail_with(/to all be even/) end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/base_matcher_spec.rb000066400000000000000000000113421455770000100270530ustar00rootroot00000000000000module RSpec::Matchers::BuiltIn RSpec.describe BaseMatcher do describe "#match_unless_raises" do let(:matcher) do Class.new(BaseMatcher).new end it "returns true if there are no errors" do expect(matcher.match_unless_raises {}).to be_truthy end it "returns false if there is an error" do expect(matcher.match_unless_raises { raise }).to be_falsey end it "returns false if the only submitted error is raised" do expect(matcher.match_unless_raises(RuntimeError) { raise "foo" }).to be_falsey end it "returns false if any of several errors submitted is raised" do expect(matcher.match_unless_raises(RuntimeError, ArgumentError, NameError) { raise "foo" }).to be_falsey expect(matcher.match_unless_raises(RuntimeError, ArgumentError, NameError) { raise ArgumentError.new('') }).to be_falsey expect(matcher.match_unless_raises(RuntimeError, ArgumentError, NameError) { raise NameError.new('') }).to be_falsey end it "re-raises any error other than one of those specified" do expect do matcher.match_unless_raises(ArgumentError) { raise "foo" } end.to raise_error "foo" end it "stores the rescued exception for use in messages" do matcher.match_unless_raises(RuntimeError) { raise "foo" } expect(matcher.rescued_exception).to be_a(RuntimeError) expect(matcher.rescued_exception.message).to eq("foo") end end describe "#failure_message" do context "when the parameter to .new is omitted" do it "describes what was expected" do matcher_class = Class.new(BaseMatcher) do def match(_expected, _actual) false end end stub_const("Foo::Bar::BeSomething", matcher_class) matcher = matcher_class.new matcher.matches?("foo") expect(matcher.failure_message).to eq('expected "foo" to be something') end end end describe "#===" do it "responds the same way as matches?" do matcher = Class.new(BaseMatcher) do def initialize(expected) @expected = expected end def matches?(actual) (@actual = actual) == @expected end end expect(matcher.new(3).matches?(3)).to be_truthy expect(matcher.new(3)).to be === 3 expect(matcher.new(3).matches?(4)).to be_falsey expect(matcher.new(3)).not_to be === 4 end end describe "default failure message detection" do def has_default_failure_messages?(matcher) BaseMatcher::DefaultFailureMessages.has_default_failure_messages?(matcher) end shared_examples_for "detecting default failure message" do context "that has no failure message overrides" do it "indicates that it has default failure messages" do matcher = build_matcher expect(has_default_failure_messages?(matcher)).to be true end end context "that overrides `failure_message`" do it "indicates that it lacks default failure messages" do matcher = build_matcher { def failure_message; end } expect(has_default_failure_messages?(matcher)).to be false end end context "that overrides `failure_message_when_negated`" do it "indicates that it lacks default failure messages" do matcher = build_matcher { def failure_message_when_negated; end } expect(has_default_failure_messages?(matcher)).to be false end end end context "for a DSL-defined custom matcher" do include_examples "detecting default failure message" do def build_matcher(&block) definition = Proc.new do match {} module_exec(&block) if block end RSpec::Matchers::DSL::Matcher.new(:matcher_name, definition, self) end end end context "for a matcher that subclasses `BaseMatcher`" do include_examples "detecting default failure message" do def build_matcher(&block) Class.new(RSpec::Matchers::BuiltIn::BaseMatcher, &block).new end end end context "for a custom matcher that lacks `failure_message_when_negated` (documented as an optional part of the matcher protocol" do it "indicates that it lacks default failure messages" do matcher = Class.new(RSpec::Matchers::BuiltIn::BaseMatcher) { undef failure_message_when_negated }.new expect(RSpec::Support.is_a_matcher?(matcher)).to be true expect(has_default_failure_messages?(matcher)).to be false end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/be_between_spec.rb000066400000000000000000000116161455770000100265410ustar00rootroot00000000000000module RSpec::Matchers::BuiltIn RSpec.describe BeBetween do class SizeMatters include Comparable attr_reader :str def <=>(other) str.size <=> other.str.size end def initialize(str) @str = str end def inspect @str end end shared_examples "be_between" do |mode| it "passes if target is between min and max" do expect(5).to matcher(1, 10) end it "fails if target is not between min and max" do expect { # It does not go to 11 expect(11).to matcher(1, 10) }.to fail_with("expected 11 to be between 1 and 10 (#{mode})") end it "works with strings" do expect("baz").to matcher("bar", "foo") expect { expect("foo").to matcher("bar", "baz") }.to fail_with("expected \"foo\" to be between \"bar\" and \"baz\" (#{mode})") end it "works with other Comparable objects" do expect(SizeMatters.new("--")).to matcher(SizeMatters.new("-"), SizeMatters.new("---")) expect { expect(SizeMatters.new("---")).to matcher(SizeMatters.new("-"), SizeMatters.new("--")) }.to fail_with("expected --- to be between - and -- (#{mode})") end end shared_examples "not_to be_between" do |mode| it "passes if target is not between min and max" do expect(11).not_to matcher(1, 10) end it "fails if target is between min and max" do expect { expect(5).not_to matcher(1, 10) }.to fail_with("expected 5 not to be between 1 and 10 (#{mode})") end end shared_examples "composing with other matchers" do |mode| it "passes when the matchers both match" do expect([nil, 3]).to include(matcher(2, 4), a_nil_value) end it "works with mixed types" do expect(["baz", Math::PI]).to include(matcher(3.1, 3.2), matcher("bar", "foo")) expect { expect(["baz", 2.14]).to include(matcher(3.1, 3.2), matcher("bar", "foo") ) }.to fail_with("expected [\"baz\", 2.14] to include (a value between 3.1 and 3.2 (#{mode}))") end it "provides a description" do description = include(matcher(2, 4), an_instance_of(Float)).description expect(description).to eq("include (a value between 2 and 4 (#{mode})) and (an instance of Float)") end it "fails with a clear error message when the matchers do not match" do expect { expect([nil, 1]).to include(matcher(2, 4), a_nil_value) }.to fail_with("expected [nil, 1] to include (a value between 2 and 4 (#{mode}))") end end it_behaves_like "an RSpec value matcher", :valid_value => (10), :invalid_value => (11) do let(:matcher) { be_between(1, 10) } end describe "expect(...).to be_between(min, max) (inclusive)" do it_behaves_like "be_between", :inclusive do def matcher(min, max) be_between(min, max) end end it "is inclusive" do expect(1).to be_between(1, 10) expect(10).to be_between(1, 10) end it "indicates it was not comparable if it does not respond to `<=` and `>=`" do expect { expect(nil).to be_between(0, 10) }.to fail_with("expected nil to be between 0 and 10 (inclusive), but it does not respond to `<=` and `>=`") end end describe "expect(...).to be_between(min, max) (exclusive)" do it_behaves_like "be_between", :exclusive do def matcher(min, max) be_between(min, max).exclusive end end it "indicates it was not comparable if it does not respond to `<` and `>`" do expect { expect(nil).to be_between(0, 10).exclusive }.to fail_with("expected nil to be between 0 and 10 (exclusive), but it does not respond to `<` and `>`") end it "is exclusive" do expect { expect(1).to be_between(1, 10).exclusive }.to fail expect { expect(10).to be_between(1, 10).exclusive }.to fail end end describe "expect(...).not_to be_between(min, max) (inclusive)" do it_behaves_like "not_to be_between", :inclusive do def matcher(min, max) be_between(min, max) end end end describe "expect(...).not_to be_between(min, max) (exclusive)" do it_behaves_like "not_to be_between", :exclusive do def matcher(min, max) be_between(min, max).exclusive end end end describe "composing with other matchers (inclusive)" do it_behaves_like "composing with other matchers", :inclusive do def matcher(min, max) a_value_between(min, max) end end end describe "composing with other matchers (exclusive)" do it_behaves_like "composing with other matchers", :exclusive do def matcher(min, max) a_value_between(min, max).exclusive end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/be_instance_of_spec.rb000066400000000000000000000062531455770000100274010ustar00rootroot00000000000000module RSpec module Matchers [:be_an_instance_of, :be_instance_of].each do |method| RSpec.describe "expect(actual).to #{method}(expected)" do it_behaves_like "an RSpec value matcher", :valid_value => "a", :invalid_value => 5 do let(:matcher) { send(method, String) } end it "passes if actual is instance of expected class" do expect("a").to send(method, String) end it "fails if actual is instance of subclass of expected class" do expect { expect(5).to send(method, Numeric) }.to fail_with("expected 5 to be an instance of Numeric") end it "fails with failure message for should unless actual is instance of expected class" do expect { expect("foo").to send(method, Array) }.to fail_with('expected "foo" to be an instance of Array') end it "provides a description" do matcher = be_an_instance_of(Integer) matcher.matches?(Numeric) expect(matcher.description).to eq "be an instance of Integer" end context "when expected provides an expanded inspect, e.g. AR::Base" do let(:user_klass) do Class.new do def self.inspect "User(id: integer, name: string)" end end end before { stub_const("User", user_klass) } it "provides a description including only the class name" do matcher = be_an_instance_of(User) expect(matcher.description).to eq "be an instance of User" end end context "when the actual object does not respond to #instance_of? method" do let(:klass) { Class.new { undef_method :instance_of? } } let(:actual_object) { klass.new } it "raises ArgumentError" do message = "The be_an_instance_of matcher requires that "\ "the actual object responds to #instance_of? method " \ "but a `NoMethodError` was encountered instead." expect { expect(actual_object).to send(method, klass) }.to raise_error ::ArgumentError, message end end end RSpec.describe "expect(actual).not_to #{method}(expected)" do it "fails with failure message for should_not if actual is instance of expected class" do expect { expect("foo").not_to send(method, String) }.to fail_with('expected "foo" not to be an instance of String') end context "when the actual object does not respond to #instance_of? method" do let(:klass) { Class.new { undef_method :instance_of? } } let(:actual_object) { klass.new } it "raises ArgumentError" do message = "The be_an_instance_of matcher requires that "\ "the actual object responds to #instance_of? method " \ "but a `NoMethodError` was encountered instead." expect { expect(actual_object).not_to send(method, klass) }.to raise_error ::ArgumentError, message end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/be_kind_of_spec.rb000066400000000000000000000064551455770000100265260ustar00rootroot00000000000000module RSpec module Matchers [:be_a_kind_of, :be_kind_of].each do |method| RSpec.describe "expect(actual).to #{method}(expected)" do it_behaves_like "an RSpec value matcher", :valid_value => 5, :invalid_value => "a" do let(:matcher) { send(method, Integer) } end it "passes if actual is instance of expected class" do expect("string").to send(method, String) end it "passes if actual is instance of subclass of expected class" do expect(5).to send(method, Numeric) end it "fails with failure message for should unless actual is kind of expected class" do expect { expect("foo").to send(method, Array) }.to fail_with('expected "foo" to be a kind of Array') end it "provides a description" do matcher = be_a_kind_of(String) matcher.matches?("this") expect(matcher.description).to eq "be a kind of String" end context "when the actual object does not respond to #kind_of? method" do let(:actual_object) do Class.new { undef_method :kind_of? }.new end it "raises ArgumentError" do message = "The be_a_kind_of matcher requires that " \ "the actual object responds to #kind_of? method " \ "but a `NoMethodError` was encountered instead." expect { expect(actual_object).to send(method, actual_object.class) }.to raise_error ::ArgumentError, message expect { expect(actual_object).to send(method, Object) }.to raise_error ::ArgumentError, message end end context "when the actual object does not respond to #is_a? method" do let(:actual_object) do Class.new { undef_method :is_a? }.new end it "provides correct result" do expect(actual_object).to send(method, actual_object.class) expect(actual_object).to send(method, Object) end end end RSpec.describe "expect(actual).not_to #{method}(expected)" do it "fails with failure message for should_not if actual is kind of expected class" do expect { expect("foo").not_to send(method, String) }.to fail_with('expected "foo" not to be a kind of String') end context "when the actual object does not respond to #kind_of? method" do let(:actual_object) do Class.new { undef_method :kind_of? }.new end it "raises ArgumentError" do message = "The be_a_kind_of matcher requires that " \ "the actual object responds to #kind_of? method " \ "but a `NoMethodError` was encountered instead." expect { expect(actual_object).not_to send(method, String) }.to raise_error ArgumentError, message end end context "when the actual object does not respond to #is_a? method" do let(:actual_object) do Class.new { undef_method :is_a? }.new end it "provides correct result" do expect(actual_object).not_to send(method, String) end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/be_spec.rb000066400000000000000000000673141455770000100250360ustar00rootroot00000000000000RSpec.describe "expect(...).to be_predicate" do it "passes when actual returns true for :predicate?" do actual = double("actual", :happy? => true) expect(actual).to be_happy end it 'allows composable aliases to be defined' do RSpec::Matchers.alias_matcher :a_user_who_is_happy, :be_happy actual = double("actual", :happy? => true) expect(actual).to a_user_who_is_happy expect(a_user_who_is_happy.description).to eq("a user who is happy") RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin actual = double("actual", :admin? => true) expect(actual).to a_user_who_is_an_admin expect(a_user_who_is_an_admin.description).to eq("a user who is an admin") RSpec::Matchers.alias_matcher :an_animal_that_is_a_canine, :be_a_canine actual = double("actual", :canine? => true) expect(actual).to an_animal_that_is_a_canine expect(an_animal_that_is_a_canine.description).to eq("an animal that is a canine") end it 'composes gracefully' do RSpec::Matchers.alias_matcher :a_happy_object, :be_happy expect([ double, double(:happy? => false), double(:happy? => true), ]).to include a_happy_object end it "passes when actual returns true for :predicates? (present tense)" do actual = double("actual", :exists? => true, :exist? => true) expect(actual).to be_exist end context "when actual returns false for :predicate?" do it "fails when actual returns false for :predicate?" do actual = double("actual", :happy? => false) expect { expect(actual).to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to return true, got false") end it "only calls :predicate? once" do actual = double "actual", :happy? => false expect(actual).to receive(:happy?).once expect { expect(actual).to be_happy }.to fail end end it "fails when actual returns nil for :predicate?" do actual = double("actual", :happy? => nil) expect { expect(actual).to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to return true, got nil") end context "when strict_predicate_matchers is set to true" do it "fails when actual returns 42 for :predicate?" do actual = double("actual", :happy? => 42) expect { expect(actual).to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to return true, got 42") end end context "when strict_predicate_matchers is set to false" do around do |example| RSpec::Expectations.configuration.strict_predicate_matchers = false example.run RSpec::Expectations.configuration.strict_predicate_matchers = true end it "passes when actual returns truthy value for :predicate?" do actual = double("actual", :happy? => 42) expect(actual).to be_happy end it "states actual predicate used when it fails" do actual = double("actual", :happy? => false) expect { expect(actual).to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to be truthy, got false") end end it "fails when actual does not respond to :predicate?" do expect { expect(Object.new).to be_happy }.to fail_including("to respond to `happy?`") end it "indicates when a predicate was attempted to be matched against an unexpected `nil`" do expect { expect(nil).to be_happy }.to fail_including("expected nil to respond to `happy?`") end it 'handles arguments to the predicate' do object = Object.new def object.predicate?(return_val); return_val; end expect(object).to be_predicate(true) expect(object).to_not be_predicate(false) expect { expect(object).to be_predicate }.to raise_error(ArgumentError) expect { expect(object).to be_predicate(false) }.to fail expect { expect(object).not_to be_predicate(true) }.to fail end it 'handles arguments to the predicate implementing to_hash' do object = Object.new def object.predicate?(value); value.to_return; end hash_a_like = Class.new do def to_hash {:to_return => true} end def to_return true end end expect(object).to be_predicate(hash_a_like.new) end it 'handles keyword arguments to the predicate', :if => RSpec::Support::RubyFeatures.required_kw_args_supported? do object = Object.new binding.eval(<<-CODE, __FILE__, __LINE__) def object.predicate?(returns:); returns; end expect(object).to be_predicate(returns: true) expect(object).to_not be_predicate(returns: false) expect { expect(object).to be_predicate(returns: false) }.to fail expect { expect(object).to_not be_predicate(returns: true) }.to fail CODE expect { expect(object).to be_predicate }.to raise_error(ArgumentError) expect { expect(object).to be_predicate(true) }.to raise_error(ArgumentError) end it 'falls back to a present-tense form of the predicate when needed' do mouth = Object.new def mouth.frowns?(return_val); return_val; end expect(mouth).to be_frown(true) end it 'fails when :predicate? is private' do privately_happy = Class.new do private def happy? true end end expect { expect(privately_happy.new).to be_happy }.to fail_with(/private/) end it 'does not call :private_methods when the object publicly responds to the message' do publicly_happy = double('happy') expect(publicly_happy).to receive(:happy?) { true } expect(publicly_happy).not_to receive(:private_methods) expect(publicly_happy).to be_happy end it "fails on error other than NameError" do actual = double("actual") expect(actual).to receive(:foo?).and_raise("aaaah") expect { expect(actual).to be_foo }.to raise_error(/aaaah/) end it 'raises an error when :predicate? exists but raises NameError' do actual_class = Class.new do def foo? raise NameError, "aaaah" end end expect { expect(actual_class.new).to be_foo }.to raise_error(NameError, /aaaah/) end it "fails on error other than NameError (with the present tense predicate)" do actual = double expect(actual).to receive(:foos?).and_raise("aaaah") expect { expect(actual).to be_foo }.to raise_error(/aaaah/) end it "does not support operator chaining like a basic `be` matcher does" do matcher = be_happy value = double(:happy? => false) expect(matcher == value).to be false end it "indicates `be true` or `be_truthy` when using `be_true`" do actual = double("actual") expect { expect(actual).to be_true }.to fail_with(/or perhaps you meant `be true` or `be_truthy`/) end it "shows no message if actual responds to `true?` when using `be_true`" do actual = double("actual", :true? => true) expect { expect(actual).to be_true }.not_to raise_error end it "indicates `be false` or `be_falsey` when using `be_false`" do actual = double("actual") expect { expect(actual).to be_false }.to fail_with(/or perhaps you meant `be false` or `be_falsey`/) end it "shows no message if actual responds to `false?` when using `be_false`" do actual = double("actual", :false? => true) expect { expect(actual).to be_false }.not_to raise_error end end RSpec.describe "expect(...).not_to be_predicate" do let(:strict_predicate_matchers) { true } around do |example| default = RSpec::Expectations.configuration.strict_predicate_matchers? RSpec::Expectations.configuration.strict_predicate_matchers = strict_predicate_matchers example.run RSpec::Expectations.configuration.strict_predicate_matchers = default end it "passes when actual returns false for :sym?" do actual = double("actual", :happy? => false) expect(actual).not_to be_happy end context "when strict_predicate_matchers is set to true" do it "fails when actual returns nil for :sym?" do actual = double("actual", :happy? => nil) expect { expect(actual).not_to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to return false, got nil") end end context "when strict_predicate_matchers is set to false" do around do |example| RSpec::Expectations.configuration.strict_predicate_matchers = false example.run RSpec::Expectations.configuration.strict_predicate_matchers = true end it "passes when actual returns nil for :sym?" do actual = double("actual", :happy? => nil) expect(actual).not_to be_happy end it "shows actual comparison made when it fails" do actual = double("actual", :happy? => 42) expect { expect(actual).not_to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to be falsey, got 42") end end it "fails when actual returns true for :sym?" do actual = double("actual", :happy? => true) expect { expect(actual).not_to be_happy }.to fail_with("expected `#{actual.inspect}.happy?` to return false, got true") end it "fails when actual does not respond to :sym?" do expect { expect(Object.new).not_to be_happy }.to fail_including("to respond to `happy?`") end end RSpec.describe "expect(...).to be_predicate(*args)" do it "passes when actual returns true for :predicate?(*args)" do actual = double("actual") expect(actual).to receive(:older_than?).with(3).and_return(true) expect(actual).to be_older_than(3) end it "fails when actual returns false for :predicate?(*args)" do actual = double("actual") expect(actual).to receive(:older_than?).with(3).and_return(false) expect { expect(actual).to be_older_than(3) }.to fail_with("expected `#{actual.inspect}.older_than?(3)` to return true, got false") end it "fails when actual does not respond to :predicate?" do expect { expect(Object.new).to be_older_than(3) }.to fail_including("to respond to `older_than?`") end end RSpec.describe "expect(...).not_to be_predicate(*args)" do it "passes when actual returns false for :predicate?(*args)" do actual = double("actual") expect(actual).to receive(:older_than?).with(3).and_return(false) expect(actual).not_to be_older_than(3) end it "fails when actual returns true for :predicate?(*args)" do actual = double("actual") expect(actual).to receive(:older_than?).with(3).and_return(true) expect { expect(actual).not_to be_older_than(3) }.to fail_with("expected `#{actual.inspect}.older_than?(3)` to return false, got true") end it "fails when actual does not respond to :predicate?" do expect { expect(Object.new).not_to be_older_than(3) }.to fail_including("to respond to `older_than?`") end end RSpec.describe "expect(...).to be_predicate(&block)" do it "passes when actual returns true for :predicate?(&block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:happy?).and_yield expect(delegate).to receive(:check_happy).and_return(true) expect(actual).to be_happy { delegate.check_happy } end it "fails when actual returns false for :predicate?(&block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:happy?).and_yield expect(delegate).to receive(:check_happy).and_return(false) expect { expect(actual).to be_happy { delegate.check_happy } }.to fail_with("expected `#{actual.inspect}.happy?` to return true, got false") end it "fails when actual does not respond to :predicate?" do delegate = double("delegate", :check_happy => true) expect { expect(Object.new).to be_happy { delegate.check_happy } }.to fail_including("to respond to `happy?`") end it 'passes the block on to the present-tense predicate form' do mouth = Object.new def mouth.frowns?; yield; end expect(mouth).to be_frown { true } expect(mouth).not_to be_frown { false } end it 'works with a do..end block for either predicate form' do mouth1 = Object.new def mouth1.frown?; yield; end mouth2 = Object.new def mouth2.frowns?; yield; end expect(mouth1).to be_frown do true end expect(mouth1).not_to be_frown do false end expect(mouth2).to be_frown do true end expect(mouth2).not_to be_frown do false end end it 'prefers a { ... } block to a do/end block because it binds more tightly' do mouth1 = Object.new def mouth1.frown?; yield; end mouth2 = Object.new def mouth2.frowns?; yield; end expect(mouth1).to be_frown { true } do false end expect(mouth1).not_to be_frown { false } do true end expect(mouth2).to be_frown { true } do false end expect(mouth2).not_to be_frown { false } do true end end end RSpec.describe "expect(...).not_to be_predicate(&block)" do it "passes when actual returns false for :predicate?(&block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:happy?).and_yield expect(delegate).to receive(:check_happy).and_return(false) expect(actual).not_to be_happy { delegate.check_happy } end it "fails when actual returns true for :predicate?(&block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:happy?).and_yield expect(delegate).to receive(:check_happy).and_return(true) expect { expect(actual).not_to be_happy { delegate.check_happy } }.to fail_with("expected `#{actual.inspect}.happy?` to return false, got true") end it "fails when actual does not respond to :predicate?" do delegate = double("delegate", :check_happy => true) expect { expect(Object.new).not_to be_happy { delegate.check_happy } }.to fail_including("to respond to `happy?`") end end RSpec.describe "expect(...).to be_predicate(*args, &block)" do it "passes when actual returns true for :predicate?(*args, &block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:older_than?).with(3).and_yield(3) expect(delegate).to receive(:check_older_than).with(3).and_return(true) expect(actual).to be_older_than(3) { |age| delegate.check_older_than(age) } end it "fails when actual returns false for :predicate?(*args, &block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:older_than?).with(3).and_yield(3) expect(delegate).to receive(:check_older_than).with(3).and_return(false) expect { expect(actual).to be_older_than(3) { |age| delegate.check_older_than(age) } }.to fail_with("expected `#{actual.inspect}.older_than?(3)` to return true, got false") end it "fails when actual does not respond to :predicate?" do delegate = double("delegate", :check_older_than => true) expect { expect(Object.new).to be_older_than(3) { |age| delegate.check_older_than(age) } }.to fail_including("to respond to `older_than?`") end end RSpec.describe "expect(...).not_to be_predicate(*args, &block)" do it "passes when actual returns false for :predicate?(*args, &block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:older_than?).with(3).and_yield(3) expect(delegate).to receive(:check_older_than).with(3).and_return(false) expect(actual).not_to be_older_than(3) { |age| delegate.check_older_than(age) } end it "fails when actual returns true for :predicate?(*args, &block)" do actual = double("actual") delegate = double("delegate") expect(actual).to receive(:older_than?).with(3).and_yield(3) expect(delegate).to receive(:check_older_than).with(3).and_return(true) expect { expect(actual).not_to be_older_than(3) { |age| delegate.check_older_than(age) } }.to fail_with("expected `#{actual.inspect}.older_than?(3)` to return false, got true") end it "fails when actual does not respond to :predicate?" do delegate = double("delegate", :check_older_than => true) expect { expect(Object.new).not_to be_older_than(3) { |age| delegate.check_older_than(age) } }.to fail_including("to respond to `older_than?`") end end RSpec.describe "expect(...).to be_truthy" do it "passes when actual equal?(true)" do expect(true).to be_truthy end it "passes when actual is 1" do expect(1).to be_truthy end it "fails when actual equal?(false)" do expect { expect(false).to be_truthy }.to fail_with("expected: truthy value\n got: false") end end RSpec.describe "expect(...).to be_falsey" do it "passes when actual equal?(false)" do expect(false).to be_falsey end it "passes when actual equal?(nil)" do expect(nil).to be_falsey end it "fails when actual equal?(true)" do expect { expect(true).to be_falsey }.to fail_with("expected: falsey value\n got: true") end end RSpec.describe "expect(...).to be_falsy" do it "passes when actual equal?(false)" do expect(false).to be_falsy end it "passes when actual equal?(nil)" do expect(nil).to be_falsy end it "fails when actual equal?(true)" do expect { expect(true).to be_falsy }.to fail_with("expected: falsey value\n got: true") end end RSpec.describe "expect(...).to be_nil" do it "passes when actual is nil" do expect(nil).to be_nil end it "fails when actual is not nil" do expect { expect(:not_nil).to be_nil }.to fail_with(/^expected: nil/) end end RSpec.describe "expect(...).not_to be_nil" do it "passes when actual is not nil" do expect(:not_nil).not_to be_nil end it "fails when actual is nil" do expect { expect(nil).not_to be_nil }.to fail_with(/^expected: not nil/) end end RSpec.describe "expect(...).to be <" do it "passes when < operator returns true" do expect(3).to be < 4 expect('a').to be < 'b' end it "fails when < operator returns false" do expect { expect(3).to be < 3 }.to fail_with("expected: < 3\n got: 3") expect { expect('a').to be < 'a' }.to fail_with(%(expected: < "a"\n got: "a")) end it "fails when < operator raises ArgumentError" do expect { expect('a').to be < 1 }.to fail_with(%(expected: < 1\n got: "a")) end it 'fails when < operator is not defined' do expect { expect(nil).to be < 1 }.to fail_with(%(expected: < 1\n got: nil)) end it "describes itself" do expect(be.<(4).description).to eq "be < 4" end it 'does not lie and say that it is equal to a number' do matcher = (be < 3) expect(5 == matcher).to be false end end RSpec.describe "expect(...).to be <=" do it "passes when <= operator returns true" do expect(3).to be <= 4 expect(4).to be <= 4 expect('a').to be <= 'b' expect('a').to be <= 'a' end it "fails when <= operator returns false" do expect { expect(3).to be <= 2 }.to fail_with("expected: <= 2\n got: 3") expect { expect('c').to be <= 'a' }.to fail_with(%(expected: <= "a"\n got: "c")) end it "fails when <= operator raises ArgumentError" do expect { expect('a').to be <= 1 }.to fail_with(%(expected: <= 1\n got: "a")) end it 'fails when <= operator is not defined' do expect { expect(nil).to be <= 1 }.to fail_with(%(expected: <= 1\n got: nil)) end end RSpec.describe "expect(...).to be >=" do it "passes when >= operator returns true" do expect(4).to be >= 4 expect(5).to be >= 4 end it "fails when >= operator returns false" do expect { expect(3).to be >= 4 }.to fail_with("expected: >= 4\n got: 3") expect { expect('a').to be >= 'c' }.to fail_with(%(expected: >= "c"\n got: "a")) end it "fails when >= operator raises ArgumentError" do expect { expect('a').to be >= 1 }.to fail_with(%(expected: >= 1\n got: "a")) end it 'fails when >= operator is not defined' do expect { expect(nil).to be >= 1 }.to fail_with(%(expected: >= 1\n got: nil)) end end RSpec.describe "expect(...).to be >" do it "passes when > operator returns true" do expect(5).to be > 4 end it "fails when > operator returns false" do expect { expect(3).to be > 4 }.to fail_with("expected: > 4\n got: 3") expect { expect('a').to be > 'a' }.to fail_with(%(expected: > "a"\n got: "a")) end it "fails when > operator raises ArgumentError" do expect { expect('a').to be > 1 }.to fail_with(%(expected: > 1\n got: "a")) end it 'fails when > operator is not defined' do expect { expect(nil).to be > 1 }.to fail_with(%(expected: > 1\n got: nil)) end end RSpec.describe "expect(...).to be ==" do it "passes when == operator returns true" do expect(5).to be == 5 end it "fails when == operator returns false" do expect { expect(3).to be == 4 }.to fail_with("expected: == 4\n got: 3") expect { expect('a').to be == 'c' }.to fail_with(%(expected: == "c"\n got: "a")) end it "fails when == operator raises ArgumentError" do failing_equality_klass = Class.new do def inspect "" end def ==(other) raise ArgumentError end end expect { expect(failing_equality_klass.new).to be == 1 }.to fail_with(%(expected: == 1\n got: )) end it 'works when the target overrides `#send`' do klass = Struct.new(:message) do def send :message_sent end end msg_1 = klass.new("hello") msg_2 = klass.new("hello") expect(msg_1).to be == msg_2 end end RSpec.describe "expect(...).to be =~" do it "passes when =~ operator returns true" do expect("a string").to be =~ /str/ end it "fails when =~ operator returns false" do expect { expect("a string").to be =~ /blah/ }.to fail_with(%(expected: =~ /blah/\n got: "a string")) end end RSpec.describe "should be =~", :uses_should do it "passes when =~ operator returns true" do "a string".should be =~ /str/ end it "fails when =~ operator returns false" do expect { "a string".should be =~ /blah/ }.to fail_with(%(expected: =~ /blah/\n got: "a string")) end end RSpec.describe "expect(...).to be ===" do it "passes when === operator returns true" do expect(Hash).to be === {} end it "fails when === operator returns false" do expect { expect(Hash).to be === "not a hash" }.to fail_with(%(expected: === "not a hash"\n got: Hash)) end end RSpec.describe "expect(...).not_to with comparison operators" do it "coaches user to stop using operators with expect().not_to with numerical comparison operators" do expect { expect(5).not_to be < 6 }.to fail_with("`expect(5).not_to be < 6` not only FAILED, it is a bit confusing.") expect { expect(5).not_to be <= 6 }.to fail_with("`expect(5).not_to be <= 6` not only FAILED, it is a bit confusing.") expect { expect(6).not_to be > 5 }.to fail_with("`expect(6).not_to be > 5` not only FAILED, it is a bit confusing.") expect { expect(6).not_to be >= 5 }.to fail_with("`expect(6).not_to be >= 5` not only FAILED, it is a bit confusing.") end it "coaches users to stop using negation with string comparison operators" do expect { expect("foo").not_to be > "bar" }.to fail_with('`expect("foo").not_to be > "bar"` not only FAILED, it is a bit confusing.') end it "handles ArgumentError as a failure" do [:<, :<=, :>=, :>].each do |operator| expect { expect('a').to_not be.send(operator, 1) }.to fail_with(%(`expect("a").not_to be #{operator} 1` not only FAILED, it is a bit confusing.)) end end it "handles NameError as a failure" do [:<, :<=, :>=, :>].each do |operator| expect { expect( Class.new do def inspect '' end define_method(operator) { |arg| self.non_existent_attribute == operator } end.new ).to_not be.send(operator, 1) }.to fail_with(%(`expect().not_to be #{operator} 1` not only FAILED, it is a bit confusing.)) end end end RSpec.describe "expect(...).not_to with equality operators" do it "raises normal error with expect().not_to with equality operators" do expect { expect(6).not_to be == 6 }.to fail_with("`expect(6).not_to be == 6`") expect { expect(String).not_to be === "Hello" }.to fail_with('`expect(String).not_to be === "Hello"`') end it "handles ArgumentError as a failure" do failing_equality_klass = Class.new do def inspect "" end def ==(other) raise ArgumentError end end expect { expect(failing_equality_klass.new).not_to be == 1 }.to fail_with(%(`expect().not_to be == 1`)) expect { expect(failing_equality_klass.new).not_to be === 1 }.to fail_with(%(`expect().not_to be === 1`)) end it "handles NameError as a failure" do failing_equality_klass = Class.new do def inspect "" end undef == end expect { expect(failing_equality_klass.new).not_to be == 1 }.to fail_with(%(`expect().not_to be == 1`)) expect { expect(failing_equality_klass.new).not_to be === 1 }.to fail_with(%(`expect().not_to be === 1`)) end end RSpec.describe "expect(...).to be" do it "passes if actual is truthy" do expect(true).to be expect(1).to be end it "fails if actual is false" do expect { expect(false).to be }.to fail_with("expected false to evaluate to true") end it "fails if actual is nil" do expect { expect(nil).to be }.to fail_with("expected nil to evaluate to true") end it "describes itself" do expect(be.description).to eq "be" end end RSpec.describe "expect(...).not_to be" do it "passes if actual is falsy" do expect(false).not_to be expect(nil).not_to be end it "fails on true" do expect { expect(true).not_to be }.to fail_with("expected true to evaluate to false") end end RSpec.describe "expect(...).to be(value)" do it "delegates to equal" do matcher = equal(5) expect(self).to receive(:equal).with(5).and_return(matcher) expect(5).to be(5) end end RSpec.describe "expect(...).not_to be(value)" do it "delegates to equal" do matcher = equal(4) expect(self).to receive(:equal).with(4).and_return(matcher) expect(5).not_to be(4) end end RSpec.describe "'expect(...).to be' with operator" do it "includes 'be' in the description" do expect((be > 6).description).to match(/be > 6/) expect((be >= 6).description).to match(/be >= 6/) expect((be <= 6).description).to match(/be <= 6/) expect((be < 6).description).to match(/be < 6/) end end RSpec.describe "arbitrary predicate with DelegateClass" do it "accesses methods defined in the delegating class (LH[#48])" do in_sub_process_if_possible do require 'delegate' class ArrayDelegate < DelegateClass(Array) def initialize(array) @internal_array = array super(@internal_array) end def large? @internal_array.size >= 5 end end delegate = ArrayDelegate.new([1, 2, 3, 4, 5, 6]) expect(delegate).to be_large end end end RSpec.describe "be_a, be_an" do it "passes when class matches" do expect("foobar").to be_a(String) expect([1, 2, 3]).to be_an(Array) end it "fails when class does not match" do expect("foobar").not_to be_a(Hash) expect([1, 2, 3]).not_to be_an(Integer) end end RSpec.describe "be_an_instance_of" do it "passes when direct class matches" do expect("string").to be_an_instance_of(String) end it "fails when class is higher up hierarchy" do expect(5).not_to be_an_instance_of(Numeric) end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/be_within_spec.rb000066400000000000000000000124411455770000100264070ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe "expect(actual).to be_within(delta).of(expected)" do it_behaves_like "an RSpec value matcher", :valid_value => 5, :invalid_value => -5 do let(:matcher) { be_within(2).of(4.0) } end it "passes when actual == expected" do expect(5.0).to be_within(0.5).of(5.0) end it "passes when actual < (expected + delta)" do expect(5.49).to be_within(0.5).of(5.0) end it "passes when actual > (expected - delta)" do expect(4.51).to be_within(0.5).of(5.0) end it "passes when actual == (expected - delta)" do expect(4.5).to be_within(0.5).of(5.0) end it "passes when actual == (expected + delta)" do expect(5.5).to be_within(0.5).of(5.0) end it "passes with integer arguments that are near each other" do expect(1.0001).to be_within(5).percent_of(1) end it "passes with negative arguments" do expect(-1.0001).to be_within(5).percent_of(-1) end it "fails when actual < (expected - delta)" do expect { expect(4.49).to be_within(0.5).of(5.0) }.to fail_with("expected 4.49 to be within 0.5 of 5.0") end it "fails when actual > (expected + delta)" do expect { expect(5.51).to be_within(0.5).of(5.0) }.to fail_with("expected 5.51 to be within 0.5 of 5.0") end it "works with Time" do expect(Time.now).to be_within(0.1).of(Time.now) end it "provides a description" do matcher = be_within(0.5).of(5.0) matcher.matches?(5.1) expect(matcher.description).to eq "be within 0.5 of 5.0" end it "formats expected within description" do klass = Class.new { def inspect; "5"; end } matcher = be_within(0.5).of(klass.new) expect(matcher.description).to eq "be within 0.5 of 5" end it "raises an error if no expected value is given" do expect { expect(5.1).to be_within(0.5) }.to raise_error(ArgumentError, /must set an expected value using #of/) end it "fails if the actual is not numeric" do expect { expect(nil).to be_within(0.1).of(0) }.to fail_with("expected nil to be within 0.1 of 0, but it could not be treated as a numeric value") end end RSpec.describe "expect(actual).to be_within(delta).percent_of(expected)" do it "passes when actual is within the given percent variance" do expect(9.0).to be_within(10).percent_of(10.0) expect(10.0).to be_within(10).percent_of(10.0) expect(11.0).to be_within(10).percent_of(10.0) end it "fails when actual is outside the given percent variance" do expect { expect(8.9).to be_within(10).percent_of(10.0) }.to fail_with("expected 8.9 to be within 10% of 10.0") expect { expect(11.1).to be_within(10).percent_of(10.0) }.to fail_with("expected 11.1 to be within 10% of 10.0") end it "provides a description" do matcher = be_within(0.5).percent_of(5.0) matcher.matches?(5.1) expect(matcher.description).to eq "be within 0.5% of 5.0" end it "works with custom measure objects" do weight_class = Struct.new(:val) do include Comparable def <=>(other); val <=> other.val; end def -(other); self.class.new(val - other.val); end def abs; self.class.new(val.abs); end def *(numeric); self.class.new(val * numeric); end def /(numeric); self.class.new(val / numeric); end end expect(weight_class.new(99)).to be_within(2).percent_of(weight_class.new(100)) expect { expect(weight_class.new(90)).to be_within(2).percent_of(weight_class.new(100)) }.to fail_with(/expected # to be within 2% of #/) end end RSpec.describe "expect(actual).not_to be_within(delta).of(expected)" do it "passes when actual < (expected - delta)" do expect(4.49).not_to be_within(0.5).of(5.0) end it "passes when actual > (expected + delta)" do expect(5.51).not_to be_within(0.5).of(5.0) end it "fails when actual == expected" do expect { expect(5.0).not_to be_within(0.5).of(5.0) }.to fail_with("expected 5.0 not to be within 0.5 of 5.0") end it "fails when actual < (expected + delta)" do expect { expect(5.49).not_to be_within(0.5).of(5.0) }.to fail_with("expected 5.49 not to be within 0.5 of 5.0") end it "fails when actual > (expected - delta)" do expect { expect(4.51).not_to be_within(0.5).of(5.0) }.to fail_with("expected 4.51 not to be within 0.5 of 5.0") end it "fails when actual == (expected - delta)" do expect { expect(4.5).not_to be_within(0.5).of(5.0) }.to fail_with("expected 4.5 not to be within 0.5 of 5.0") end it "fails when actual == (expected + delta)" do expect { expect(5.5).not_to be_within(0.5).of(5.0) }.to fail_with("expected 5.5 not to be within 0.5 of 5.0") end it "passes if the actual is not numeric" do expect(nil).not_to be_within(0.1).of(0) end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/captures_spec.rb000066400000000000000000000062251455770000100262700ustar00rootroot00000000000000RSpec.describe "expect(regex).to match(string).with_captures" do context "with a string target" do it "does match a regex with a missing capture" do expect("a123a").to match(/(a)(b)?/).with_captures("a", nil) end it "does not match a regex with an incorrect match" do expect("a123a").not_to match(/(a)/).with_captures("b") end it "matches a regex without named captures" do expect("a123a").to match(/(a)/).with_captures("a") end it "uses the match description if the regex doesn't match" do expect { expect(/(a)/).to match("123").with_captures }.to fail_with(/expected \/\(a\)\/ to match "123"/) end if RUBY_VERSION != "1.8.7" it "matches a regex with named captures" do expect("a123a").to match(Regexp.new("(?123)")).with_captures(:num => "123") end it "matches a regex with a nested matcher" do expect("a123a").to match(Regexp.new("(?123)(asdf)?")).with_captures(a_hash_including(:num => "123")) end it "does not match a regex with an incorrect named group match" do expect("a123a").not_to match(Regexp.new("(?a)")).with_captures(:name => "b") end it "has a sensible failure description with a hash including matcher" do expect { expect("a123a").not_to match(Regexp.new("(?123)(asdf)?")).with_captures(a_hash_including(:num => "123")) }.to fail_with(/num => "123"/) end it "matches named captures when not passing a hash" do expect("a123a").to match(Regexp.new("(?123)")).with_captures("123") end end end context "with a regex target" do it "does match a regex with a missing capture" do expect(/(a)(b)?/).to match("a123a").with_captures("a", nil) end it "does not match a regex with an incorrect match" do expect(/(a)/).not_to match("a123a").with_captures("b") end it "matches a regex without named captures" do expect(/(a)/).to match("a123a").with_captures("a") end it "uses the match description if the regex doesn't match" do expect { expect(/(a)/).to match("123").with_captures }.to fail_with(/expected \/\(a\)\/ to match "123"/) end if RUBY_VERSION != "1.8.7" it "matches a regex with named captures" do expect(Regexp.new("(?123)")).to match("a123a").with_captures(:num => "123") end it "matches a regex with a nested matcher" do expect(Regexp.new("(?123)(asdf)?")).to match("a123a").with_captures(a_hash_including(:num => "123")) end it "does not match a regex with an incorrect named group match" do expect(Regexp.new("(?a)")).not_to match("a123a").with_captures(:name => "b") end it "has a sensible failure description with a hash including matcher" do expect { expect(Regexp.new("(?123)(asdf)?")).not_to match("a123a").with_captures(a_hash_including(:num => "123")) }.to fail_with(/num => "123"/) end it "matches named captures when not passing a hash" do expect(Regexp.new("(?123)")).to match("a123a").with_captures("123") end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/change_spec.rb000066400000000000000000001070221455770000100256640ustar00rootroot00000000000000class SomethingExpected attr_accessor :some_value end value_pattern = /(?:result|`.+?`)/ RSpec.describe "expect { ... }.to change ..." do context "with a numeric value" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when actual is modified by the block" do expect { @instance.some_value = 6.0 }.to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail_with("expected `SomethingExpected#some_value` to have changed, but is still 5") end it "provides a #description" do expect(change(@instance, :some_value).description).to eq "change `SomethingExpected#some_value`" end end it "can specify the change of a variable's class" do val = nil expect { val = "string" }.to change { val.class }.from(NilClass).to(String) expect { expect { val = :symbol }.to change { val.class }.from(String).to(NilClass) }.to fail_with(/but is now Symbol/) end context "with boolean values" do before(:example) do @instance = SomethingExpected.new @instance.some_value = true end it "passes when actual is modified by the block" do expect { @instance.some_value = false }.to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail_with("expected `SomethingExpected#some_value` to have changed, but is still true") end end context "with set values" do it "passes when it should" do in_sub_process_if_possible do require 'set' set = Set.new([1]) expect { set << 2 }.to change { set }.from([1].to_set).to([2, 1].to_set) end end it "fails when it should" do in_sub_process_if_possible do require 'set' expect { set = Set.new([1]) expect { set << 2 }.to change { set }.from([1].to_set).to([2, 1, 3].to_set) }.to fail_with(/expected #{value_pattern} to have changed to #{Regexp.escape([2, 1, 3].to_set.inspect)}, but is now #{Regexp.escape([1, 2].to_set.inspect)}/) end end end context "with an IO stream" do it "fails when the stream does not change" do expect { k = STDOUT expect {}.to change { k } }.to fail_with(/expected #{value_pattern} to have changed/) end end it 'correctly detects a change that both mutates and replaces an object' do obj = Struct.new(:x).new([]) expect { obj.x << 1 # mutate it obj.x = [1] # replace it }.to change { obj.x } end it 'does not detect changes in an object that updates its hash upon comparison' do obj = Class.new do def ==(another) @hash = rand # (^ '=')^ # object_id == another.object_id end def hash @hash ||= super end end.new expect {}.not_to change { obj } end context "with nil value" do before(:example) do @instance = SomethingExpected.new @instance.some_value = nil end it "passes when actual is modified by the block" do expect { @instance.some_value = false }.to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail_with("expected `SomethingExpected#some_value` to have changed, but is still nil") end end context "with a deeply nested object graph" do it "passes when a leaf is changed" do data = [{ :a => [1, 2] }] expect { data[0][:a] << 3 }.to change { data } end it 'fails when no part of it is changed' do data = [{ :a => [1, 2] }] failure_msg = /expected #{value_pattern} to have changed, but is still #{regexp_inspect data}/ expect { expect { data.to_s }.to change { data } }.to fail_with(failure_msg) end it "passes when correctly specifying the exact mutation of a leaf" do data = [{ :a => [1, 2] }] expect { data[0][:a] << 3 }.to change { data }. from([{ :a => [1, 2] }]). to([{ :a => [1, 2, 3] }]) end it "fails when wrongly specifying the `from` value" do data = [{ :a => [1, 2] }] expected_initial = [{ :a => [1] }] failure_msg = /expected #{value_pattern} to have initially been #{regexp_inspect expected_initial}, but was #{regexp_inspect data}/ expect { expect { data[0][:a] << 3 }.to change { data }. from(expected_initial). to([{ :a => [1, 2, 3] }]) }.to fail_with(failure_msg) end it "fails when wrongly specifying the `to` value" do data = [{ :a => [1, 2] }] expected_final = [{ :a => [1] }] failure_msg = /expected #{value_pattern} to have changed to #{regexp_inspect expected_final}, but is now #{regexp_inspect [{ :a => [1, 2, 3] }]}/ expect { expect { data[0][:a] << 3 }.to change { data }. from([{ :a => [1, 2] }]). to(expected_final) }.to fail_with(failure_msg) end def regexp_inspect(object) Regexp.escape(object.inspect) end end context "with an array" do before(:example) do @instance = SomethingExpected.new @instance.some_value = [] end it "passes when actual is modified by the block" do expect { @instance.some_value << 1 }.to change(@instance, :some_value) end it "fails when a predicate on the actual fails" do expect do expect { @instance.some_value << 1 }.to change { @instance.some_value }.to be_empty end.to fail_with(/#{value_pattern} to have changed to/) end it "passes when a predicate on the actual passes" do @instance.some_value = [1] expect { @instance.some_value.pop }.to change { @instance.some_value }.to be_empty end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail_with("expected `SomethingExpected#some_value` to have changed, but is still []") end end context "with a hash" do before(:example) do @instance = SomethingExpected.new @instance.some_value = { :a => 'a' } end it "passes when actual is modified by the block" do expect { @instance.some_value[:a] = 'A' }.to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail end end context "with a string" do it "passes when actual is modified by the block" do string = "ab".dup expect { string << "c" }.to change { string } end it 'fails when actual is not modified by the block' do string = "ab" expect { expect {}.to change { string } }.to fail_with(/to have changed/) end end context "with an arbitrary enumerable" do before(:example) do @instance = SomethingExpected.new # rubocop:disable Layout/EmptyLinesAroundArguments This is a RuboCop bug, and it's fixed in 0.65.0 @instance.some_value = Class.new do include Enumerable attr_reader :elements def initialize(*elements) @elements = elements.dup end def <<(element) elements << element end def dup self.class.new(*elements) end def ==(other) elements == other.elements end def hash elements.hash end end.new # rubocop:enable Layout/EmptyLinesAroundArguments end it "passes when actual is modified by the block" do expect { @instance.some_value << 1 }.to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect {}.to change(@instance, :some_value) end.to fail_with(/^expected `SomethingExpected#some_value` to have changed, but is still/) end end end RSpec.describe "expect { ... }.to change(actual, message)" do it 'provides a #description with `SomeClass#some_message` notation' do expect(change('instance', :some_value).description).to eq 'change `String#some_value`' end context "when the receiver is an instance of anonymous class" do let(:klass) do Class.new(SomethingExpected) end it "can handle it" do expect(change(klass.new, :some_value).description).to match(/change `##some_value`/) end end context 'when the receiver is an object that does not respond to #class such as BasicObject' do let(:basic_object) do basic_object_class.new end let(:basic_object_class) do defined?(BasicObject) ? BasicObject : fake_basic_object_class end let(:fake_basic_object_class) do Class.new do def self.to_s 'BasicObject' end undef class, inspect, respond_to? end end it 'can properly extract the class name' do expect(change(basic_object, :__id__).description).to eq 'change `BasicObject#__id__`' end end context "when the receiver is a Module" do it "provides a #description with `SomeModule.some_message` notation" do expect(change(SomethingExpected, :some_value).description).to match(/change `SomethingExpected.some_value`/) end end context "with a missing message" do it "fails with an ArgumentError" do expect do expect {}.to change(:receiver) end.to raise_error(ArgumentError, /^`change` requires either an object and message/) end end end RSpec.describe "expect { ... }.not_to change(actual, message)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when actual is not modified by the block" do expect {}.not_to change(@instance, :some_value) end it "fails when actual is not modified by the block" do expect do expect { @instance.some_value = 6 }.not_to change(@instance, :some_value) end.to fail_with("expected `SomethingExpected#some_value` not to have changed, but did change from 5 to 6") end end RSpec.describe "expect { ... }.to change { block }" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when actual is modified by the block" do expect { @instance.some_value = 6 }.to change { @instance.some_value } end it "fails when actual is not modified by the block" do expect do expect {}.to change { @instance.some_value } end.to fail_with(/expected #{value_pattern} to have changed, but is still 5/) end it "warns if passed a block using do/end instead of {}" do expect do expect {}.to change do; end end.to raise_error(SyntaxError, /Block not received by the `change` matcher/) end context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do context 'when the block body fits into a single line' do it "provides a #description with the block snippet" do expect(change { @instance.some_value }.description).to eq "change `@instance.some_value`" end end context 'when the block body spans multiple lines' do before do def @instance.reload end end let(:matcher) do change { @instance.reload @instance.some_value } end it "provides a #description with the block snippet" do expect(matcher.description).to eq "change result" end end context 'when used with an alias name' do alias_matcher :modify, :change it 'can extract the block snippet' do expect(modify { @instance.some_value }.description).to eq "modify `@instance.some_value`" end end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description without the block snippet" do expect(change { @instance.some_value }.description).to eq "change result" end end end RSpec.describe "expect { ... }.not_to change { block }" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when actual is modified by the block" do expect {}.not_to change { @instance.some_value } end it "fails when actual is not modified by the block" do expect do expect { @instance.some_value = 6 }.not_to change { @instance.some_value } end.to fail_with(/expected #{value_pattern} not to have changed, but did change from 5 to 6/) end it "warns if passed a block using do/end instead of {}" do expect do expect {}.not_to change do; end end.to raise_error(SyntaxError, /Block not received by the `change` matcher/) end context "with an IO stream" do it "passes when the stream does not change" do k = STDOUT expect {}.not_to change { k } end end context "with a deeply nested object graph" do it "passes when the object is changed" do data = [{ :a => [1, 2] }] expect { data.to_s }.not_to change { data } end it 'fails when part of it is changed' do data = [{ :a => [1, 2] }] failure_msg = /expected #{value_pattern} not to have changed, but did change from #{regexp_inspect data} to #{regexp_inspect [{ :a=>[1, 2, 3] }]}/ expect { expect { data[0][:a] << 3 }.not_to change { data } }.to fail_with(failure_msg) end it "passes when correctly specifying the exact mutation of a leaf" do data = [{ :a => [1, 2] }] expect { data[0][:a] << 3 }.to change { data }. from([{ :a => [1, 2] }]). to([{ :a => [1, 2, 3] }]) end def regexp_inspect(object) Regexp.escape(object.inspect) end end end RSpec.describe "expect { ... }.not_to change { }.from" do context 'when the value starts at the from value' do it 'passes when the value does not change' do k = 5 expect {}.not_to change { k }.from(5) end it 'fails when the value does change' do expect { k = 5 expect { k += 1 }.not_to change { k }.from(5) }.to fail_with(/but did change from 5 to 6/) end end context 'when the value starts at a different value' do it 'fails when the value does not change' do expect { k = 6 expect {}.not_to change { k }.from(5) }.to fail_with(/expected #{value_pattern} to have initially been 5/) end it 'fails when the value does change' do expect { k = 6 expect { k += 1 }.not_to change { k }.from(5) }.to fail_with(/expected #{value_pattern} to have initially been 5/) end end end RSpec.describe "expect { ... }.not_to change { }.to" do it 'is not supported' do expect { expect {}.not_to change {}.to(3) }.to raise_error(NotImplementedError) end it 'is not supported when it comes after `from`' do expect { expect {}.not_to change {}.from(nil).to(3) }.to raise_error(NotImplementedError) end end RSpec.describe "expect { ... }.not_to change { }.by" do it 'is not supported' do expect { expect {}.not_to change {}.by(3) }.to raise_error(NotImplementedError) end end RSpec.describe "expect { ... }.not_to change { }.by_at_least" do it 'is not supported' do expect { expect {}.not_to change {}.by_at_least(3) }.to raise_error(NotImplementedError) end end RSpec.describe "expect { ... }.not_to change { }.by_at_most" do it 'is not supported' do expect { expect {}.not_to change {}.by_at_most(3) }.to raise_error(NotImplementedError) end end RSpec.describe "expect { ... }.to change(actual, message).by(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by expected amount" do expect { @instance.some_value += 1 }.to change(@instance, :some_value).by(1) end it "passes when attribute is not changed and expected amount is 0" do expect { @instance.some_value += 0 }.to change(@instance, :some_value).by(0) end it "fails when the attribute is changed by unexpected amount" do expect do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by(1) end.to fail_with("expected `SomethingExpected#some_value` to have changed by 1, but was changed by 2") end it "fails when the attribute is changed by unexpected amount in the opposite direction" do expect do expect { @instance.some_value -= 1 }.to change(@instance, :some_value).by(1) end.to fail_with("expected `SomethingExpected#some_value` to have changed by 1, but was changed by -1") end it "provides a #description" do expect(change(@instance, :some_value).by(3).description).to eq "change `SomethingExpected#some_value` by 3" end end RSpec.describe "expect { ... }.to change { block }.by(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by expected amount" do expect { @instance.some_value += 1 }.to change { @instance.some_value }.by(1) end it "fails when the attribute is changed by unexpected amount" do expect do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by(1) end.to fail_with(/expected #{value_pattern} to have changed by 1, but was changed by 2/) end it "fails when the attribute is changed by unexpected amount in the opposite direction" do expect do expect { @instance.some_value -= 1 }.to change { @instance.some_value }.by(1) end.to fail_with(/expected #{value_pattern} to have changed by 1, but was changed by -1/) end context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description with the block snippet" do expect(change { @instance.some_value }.by(3).description).to eq "change `@instance.some_value` by 3" end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description without the block snippet" do expect(change { @instance.some_value }.by(3).description).to eq "change result by 3" end end end RSpec.describe "expect { ... }.to change(actual, message).by_at_least(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by greater than the expected amount" do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_least(1) end it "passes when attribute is changed by the expected amount" do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_least(2) end it "fails when the attribute is changed by less than the expected amount" do expect do expect { @instance.some_value += 1 }.to change(@instance, :some_value).by_at_least(2) end.to fail_with("expected `SomethingExpected#some_value` to have changed by at least 2, but was changed by 1") end it "provides a #description" do expect(change(@instance, :some_value).by_at_least(3).description).to eq "change `SomethingExpected#some_value` by at least 3" end end RSpec.describe "expect { ... }.to change { block }.by_at_least(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by greater than expected amount" do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by_at_least(1) end it "passes when attribute is changed by the expected amount" do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by_at_least(2) end it "fails when the attribute is changed by less than the unexpected amount" do expect do expect { @instance.some_value += 1 }.to change { @instance.some_value }.by_at_least(2) end.to fail_with(/expected #{value_pattern} to have changed by at least 2, but was changed by 1/) end context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description with the block snippet" do expect(change { @instance.some_value }.by_at_least(3).description).to eq "change `@instance.some_value` by at least 3" end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description without the block snippet" do expect(change { @instance.some_value }.by_at_least(3).description).to eq "change result by at least 3" end end end RSpec.describe "expect { ... }.to change(actual, message).by_at_most(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by less than the expected amount" do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_most(3) end it "passes when attribute is changed by the expected amount" do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_most(2) end it "fails when the attribute is changed by greater than the expected amount" do expect do expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_most(1) end.to fail_with("expected `SomethingExpected#some_value` to have changed by at most 1, but was changed by 2") end it "provides a #description" do expect(change(@instance, :some_value).by_at_most(3).description).to eq "change `SomethingExpected#some_value` by at most 3" end end RSpec.describe "expect { ... }.to change { block }.by_at_most(expected)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 5 end it "passes when attribute is changed by less than expected amount" do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by_at_most(3) end it "passes when attribute is changed by the expected amount" do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by_at_most(2) end it "fails when the attribute is changed by greater than the unexpected amount" do expect do expect { @instance.some_value += 2 }.to change { @instance.some_value }.by_at_most(1) end.to fail_with(/expected #{value_pattern} to have changed by at most 1, but was changed by 2/) end context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description with the block snippet" do expect(change { @instance.some_value }.by_at_most(3).description).to eq "change `@instance.some_value` by at most 3" end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description without the block snippet" do expect(change { @instance.some_value }.by_at_most(3).description).to eq "change result by at most 3" end end end RSpec.describe "expect { ... }.to change(actual, message).from(old)" do context "with boolean values" do before(:example) do @instance = SomethingExpected.new @instance.some_value = true end it "passes when attribute is == to expected value before executing block" do expect { @instance.some_value = false }.to change(@instance, :some_value).from(true) end it "fails when attribute is not == to expected value before executing block" do expect do expect { @instance.some_value = 'foo' }.to change(@instance, :some_value).from(false) end.to fail_with("expected `SomethingExpected#some_value` to have initially been false, but was true") end end context "with non-boolean values" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end it "passes when attribute matches expected value before executing block" do expect { @instance.some_value = "astring" }.to change(@instance, :some_value).from("string") end it "fails when attribute does not match expected value before executing block" do expect do expect { @instance.some_value = "knot" }.to change(@instance, :some_value).from("cat") end.to fail_with("expected `SomethingExpected#some_value` to have initially been \"cat\", but was \"string\"") end it "provides a #description" do expect(change(@instance, :some_value).from(3).description).to eq "change `SomethingExpected#some_value` from 3" end end end RSpec.describe "expect { ... }.to change { block }.from(old)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end it "passes when attribute matches expected value before executing block" do expect { @instance.some_value = "astring" }.to change { @instance.some_value }.from("string") end it "fails when attribute does not match expected value before executing block" do expect do expect { @instance.some_value = "knot" }.to change { @instance.some_value }.from("cat") end.to fail_with(/expected #{value_pattern} to have initially been "cat", but was "string"/) end it "fails when attribute does not change" do expect do expect {}.to change { @instance.some_value }.from("string") end.to fail_with(/expected #{value_pattern} to have changed from "string", but did not change/) end context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description with the block snippet" do expect(change { @instance.some_value }.from(3).description).to eq "change `@instance.some_value` from 3" end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "provides a #description without the block snippet" do expect(change { @instance.some_value }.from(3).description).to eq "change result from 3" end end it "provides a #description" do expect(change {}.from(3).description).to eq "change result from 3" end end RSpec.describe "expect { ... }.to change(actual, message).to(new)" do context "with boolean values" do before(:example) do @instance = SomethingExpected.new @instance.some_value = true end it "passes when attribute is == to expected value after executing block" do expect { @instance.some_value = false }.to change(@instance, :some_value).to(false) end it "fails when attribute is not == to expected value after executing block" do expect do expect { @instance.some_value = 1 }.to change(@instance, :some_value).from(true).to(false) end.to fail_with("expected `SomethingExpected#some_value` to have changed to false, but is now 1") end end context "with non-boolean values" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end it "passes when attribute matches expected value after executing block" do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).to("cat") end it "fails when attribute does not match expected value after executing block" do expect do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("string").to("dog") end.to fail_with("expected `SomethingExpected#some_value` to have changed to \"dog\", but is now \"cat\"") end it "fails with a clear message when it ends with the right value but did not change" do expect { expect {}.to change(@instance, :some_value).to("string") }.to fail_with('expected `SomethingExpected#some_value` to have changed to "string", but did not change') end end end RSpec.describe "expect { ... }.to change { block }.to(new)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end it "passes when attribute matches expected value after executing block" do expect { @instance.some_value = "cat" }.to change { @instance.some_value }.to("cat") end it "fails when attribute does not match expected value after executing block" do expect do expect { @instance.some_value = "cat" }.to change { @instance.some_value }.from("string").to("dog") end.to fail_with(/expected #{value_pattern} to have changed to "dog", but is now "cat"/) end it "provides a #description" do expect(change {}.to(3).description).to eq "change result to 3" end end RSpec.describe "expect { ... }.to change(actual, message).from(old).to(new)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end it "passes when #to comes before #from" do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).to("cat").from("string") end it "passes when #from comes before #to" do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("string").to("cat") end it "shows the correct messaging when #after and #to are different" do expect do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("string").to("dog") end.to fail_with("expected `SomethingExpected#some_value` to have changed to \"dog\", but is now \"cat\"") end it "shows the correct messaging when #before and #from are different" do expect do expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("not_string").to("cat") end.to fail_with("expected `SomethingExpected#some_value` to have initially been \"not_string\", but was \"string\"") end end RSpec.describe "expect { ... }.to change { block }.from(old).to(new)" do before(:example) do @instance = SomethingExpected.new @instance.some_value = 'string' end context "when #to comes before #from" do it "passes" do expect { @instance.some_value = "cat" }.to change { @instance.some_value }.to("cat").from("string") end it "provides a #description" do expect(change {}.to(1).from(3).description).to eq "change result to 1 from 3" end end context "when #from comes before #to" do it "passes" do expect { @instance.some_value = "cat" }.to change { @instance.some_value }.from("string").to("cat") end it "provides a #description" do expect(change {}.from(1).to(3).description).to eq "change result from 1 to 3" end end end RSpec.describe "Composing a matcher with `change`" do describe "expect { ... }.to change { ... }" do context ".from(matcher).to(matcher)" do it 'passes when the matchers match the from and to values' do k = 0.51 expect { k += 1 }.to change { k }. from( a_value_within(0.1).of(0.5) ). to( a_value_within(0.1).of(1.5) ) end it 'fails with a clear message when the `from` does not match' do expect { k = 0.51 expect { k += 1 }.to change { k }. from( a_value_within(0.1).of(0.7) ). to( a_value_within(0.1).of(1.5) ) }.to fail_with(/expected #{value_pattern} to have initially been a value within 0.1 of 0.7, but was 0.51/) end it 'fails with a clear message when the `to` does not match' do expect { k = 0.51 expect { k += 1 }.to change { k }. from( a_value_within(0.1).of(0.5) ). to( a_value_within(0.1).of(2.5) ) }.to fail_with(/expected #{value_pattern} to have changed to a value within 0.1 of 2.5, but is now 1.51/) end it 'provides a description' do expect(change(nil, :foo). from( a_value_within(0.1).of(0.5) ). to( a_value_within(0.1).of(1.5) ).description ).to eq("change `NilClass#foo` from a value within 0.1 of 0.5 to a value within 0.1 of 1.5") end end context ".to(matcher).from(matcher)" do it 'passes when the matchers match the from and to values' do k = 0.51 expect { k += 1 }.to change { k }. to( a_value_within(0.1).of(1.5) ). from( a_value_within(0.1).of(0.5) ) end it 'fails with a clear message when the `from` does not match' do expect { k = 0.51 expect { k += 1 }.to change { k }. to( a_value_within(0.1).of(1.5) ). from( a_value_within(0.1).of(0.7) ) }.to fail_with(/expected #{value_pattern} to have initially been a value within 0.1 of 0.7, but was 0.51/) end it 'fails with a clear message when the `to` does not match' do expect { k = 0.51 expect { k += 1 }.to change { k }. to( a_value_within(0.1).of(2.5) ). from( a_value_within(0.1).of(0.5) ) }.to fail_with(/expected #{value_pattern} to have changed to a value within 0.1 of 2.5, but is now 1.51/) end it 'provides a description' do expect(change(nil, :foo). to( a_value_within(0.1).of(0.5) ). from( a_value_within(0.1).of(1.5) ).description ).to eq("change `NilClass#foo` to a value within 0.1 of 0.5 from a value within 0.1 of 1.5") end end context ".by(matcher)" do it "passes when the matcher matches" do k = 0.5 expect { k += 1.05 }.to change { k }.by( a_value_within(0.1).of(1) ) end it 'fails with a clear message when the `by` does not match' do expect { k = 0.5 expect { k += 1.05 }.to change { k }.by( a_value_within(0.1).of(0.5) ) }.to fail_with(/expected #{value_pattern} to have changed by a value within 0.1 of 0.5, but was changed by 1.05/) end it 'provides a description' do expect(change(nil, :foo). by( a_value_within(0.1).of(0.5) ).description ).to eq("change `NilClass#foo` by a value within 0.1 of 0.5") end end end describe "expect { ... }.not_to change { ... }.from(matcher).to(matcher)" do it 'passes when the matcher matches the `from` value and it does not change' do k = 0.51 expect {}.not_to change { k }.from( a_value_within(0.1).of(0.5) ) end it 'fails with a clear message when the `from` matcher does not match' do expect { k = 0.51 expect {}.not_to change { k }.from( a_value_within(0.1).of(1.5) ) }.to fail_with(/expected #{value_pattern} to have initially been a value within 0.1 of 1.5, but was 0.51/) end end end RSpec.describe RSpec::Matchers::BuiltIn::Change do it "works when the receiver has implemented #send" do @instance = SomethingExpected.new @instance.some_value = "string" def @instance.send(*_args); raise "DOH! Library developers shouldn't use #send!" end expect { expect { @instance.some_value = "cat" }.to change(@instance, :some_value) }.not_to raise_error end it_behaves_like "an RSpec block-only matcher" do let(:matcher) { change { @k } } before { @k = 1 } def valid_block @k += 1 end def invalid_block end end end RSpec.describe RSpec::Matchers::BuiltIn::ChangeRelatively do it_behaves_like "an RSpec block-only matcher", :disallows_negation => true, :skip_deprecation_check => true do let(:matcher) { change { @k }.by(1) } before { @k = 0 } def valid_block @k += 1 end def invalid_block @k += 2 end end end RSpec.describe RSpec::Matchers::BuiltIn::ChangeFromValue do it_behaves_like "an RSpec block-only matcher" do let(:matcher) { change { @k }.from(0) } before { @k = 0 } def valid_block @k += 1 end def invalid_block end end end RSpec.describe RSpec::Matchers::BuiltIn::ChangeToValue do it_behaves_like "an RSpec block-only matcher", :disallows_negation => true do let(:matcher) { change { @k }.to(2) } before { @k = 0 } def valid_block @k = 2 end def invalid_block @k = 3 end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/compound_spec.rb000066400000000000000000000726301455770000100262710ustar00rootroot00000000000000module RSpec::Matchers::BuiltIn RSpec.describe Compound do let(:matcher_without_diffable) { include("foo") } before do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) allow(matcher_without_diffable).to receive(:diffable?).and_raise(NoMethodError) end shared_examples "making a copy" do |compound_method, copy_method| context "when making a copy via `#{copy_method}`" do it "uses a copy of the base matchers" do matcher_1 = include(3) matcher_2 = include(4) compound = matcher_1.__send__(compound_method, matcher_2) copy = compound.__send__(copy_method) expect(copy).not_to equal(compound) expect(copy.matcher_1).not_to equal(matcher_1) expect(copy.matcher_1).to be_a(RSpec::Matchers::BuiltIn::Include) expect(copy.matcher_1.expected).to eq([3]) expect(copy.matcher_2).not_to equal(matcher_2) expect(copy.matcher_2).to be_a(RSpec::Matchers::BuiltIn::Include) expect(copy.matcher_2.expected).to eq([4]) end it "copies custom matchers properly so they can work even though they have singleton behavior" do matcher_1 = custom_include(3) matcher_2 = custom_include(3) compound = matcher_1.__send__(compound_method, matcher_2) copy = compound.__send__(copy_method) expect(copy).not_to equal(compound) expect(copy.matcher_1).not_to equal(matcher_1) expect(copy.matcher_2).not_to equal(matcher_2) expect([3]).to copy expect { expect([4]).to copy }.to fail_including("expected [4]") end end end shared_examples "handles blocks properly" do |meth| define_method :combine do |m1, m2| m1.__send__(meth, m2) end context "when used with a block matcher" do it 'executes the block only once, regardless of how many matchers are compounded' do w, x, y, z = 0, 0, 0, 0 expect { w += 1; x += 2; y += 3; z += 4 }.to( combine( change { w }.to(1), combine( change { x }.to(2), combine( change { y }.to(3), change { z }.to(4) ) ) ) ) end context "does not work when combined with another non-block matcher" do example "with the block matcher first" do expect { x = 0 expect { x += 2 }.to combine(change { x }.to(2), be_a(Proc)) }.to fail_with(/supports_block_expectations/) end example "with the block matcher last" do expect { x = 0 expect { x += 2 }.to combine(be_a(Proc), change { x }.to(2)) }.to fail_with(/supports_block_expectations/) end end context "indicates block expectations are not supported when combined with a custom matcher that does not define `supports_block_expectations?" do let(:non_block_matcher) do Class.new do include ::RSpec::Matchers::Composable def matches?(*); true; end end.new end example "with the block matcher first" do compound = combine(change {}.to(2), non_block_matcher) expect(compound.supports_block_expectations?).to be false end example "with the block matcher last" do compound = combine(non_block_matcher, change {}.to(2)) expect(compound.supports_block_expectations?).to be false end end context "forwards on any matcher block arguments as needed (such as for `yield_with_args`)" do obj = Object.new def obj.foo(print_bar=true) yield "bar" print "printing bar" if print_bar end example "with the matcher that passes block args first" do call_count = 0 expect { |probe| call_count += 1 obj.foo(&probe) }.to combine(yield_with_args(/bar/), output("printing bar").to_stdout) expect(call_count).to eq(1) end example "with the matcher that passes block args last" do call_count = 0 expect { |probe| call_count += 1 obj.foo(&probe) }.to combine(output("printing bar").to_stdout, yield_with_args("bar")) expect(call_count).to eq(1) end it "does not support two matchers that both pass arguments to the block" do expect { expect { |probe| obj.foo(false, &probe) }.to combine(yield_with_args(/bar/), yield_with_args("bar")) }.to raise_error(/cannot be combined/) end end context "when used with `raise_error` (which cannot match against a wrapped block)" do it 'does not work when combined with `throw_symbol` (which also cannot match against a wrapped block)' do expect { expect {}.to combine(raise_error("boom"), throw_symbol(:foo)) }.to raise_error(/cannot be combined/) end it 'works when `raise_error` is first' do x = 0 expect { x += 2 raise "boom" }.to combine(raise_error("boom"), change { x }.to(2)) end it 'works when `raise_error` is last' do x = 0 expect { x += 2 raise "boom" }.to combine(change { x }.to(2), raise_error("boom")) end context "with nested compound matchers" do if meth == :or def expect_block @x = 0 expect do print "a" # for or we need `raise "boom"` and one other # to be wrong, so that only the `output("a").to_stdout` # is correct for these specs to cover the needed # behavior. @x += 3 raise "bom" end end else def expect_block @x = 0 expect do print "a" @x += 2 raise "boom" end end end it 'works when `raise_error` is first in the first compound matcher' do matcher = combine( combine(raise_error("boom"), change { @x }.to(2)), output("a").to_stdout ) expect_block.to matcher end it 'works when `raise_error` is last in the first compound matcher' do matcher = combine( combine(change { @x }.to(2), raise_error("boom")), output("a").to_stdout ) expect_block.to matcher end it 'works when `raise_error` is first in the last compound matcher' do matcher = combine( change { @x }.to(2), combine(raise_error("boom"), output("a").to_stdout) ) expect_block.to matcher end it 'works when `raise_error` is last in the last compound matcher' do matcher = combine( change { @x }.to(2), combine(output("a").to_stdout, raise_error("boom")) ) expect_block.to matcher end end end end context "when given a proc and non block matchers" do it 'does not treat it as a block expectation expression' do p = lambda {} expect(p).to combine(be_a(Proc), be(p)) expect { expect(p).to combine(be_a(Integer), eq(3)) }.to fail_including("expected: 3") end end end context "when used as a composable matcher" do it 'can pass' do expect(["food", "barn"]).to include( a_string_starting_with("f").and(ending_with("d")), a_string_starting_with("b").and(ending_with("n")) ) end it 'can fail' do expect { expect(["foo", "bar"]).to include( a_string_starting_with("f").and(ending_with("d")), a_string_starting_with("b").and(ending_with("n")) ) }.to fail_including('expected ["foo", "bar"] to include (a string starting with "f" and ending with "d") and (a string starting with "b" and ending with "n")') end it 'provides a description' do matcher = include( a_string_starting_with("f").and(ending_with("d")), a_string_starting_with("b").and(ending_with("n")) ) expect(matcher.description).to eq('include (a string starting with "f" and ending with "d") and (a string starting with "b" and ending with "n")') end end describe "expect(...).to matcher.and(other_matcher)" do it_behaves_like "an RSpec value matcher", :valid_value => 3, :invalid_value => 4, :disallows_negation => true do let(:matcher) { eq(3).and be <= 3 } end context 'when using boolean AND `&` alias' do it_behaves_like "an RSpec value matcher", :valid_value => 3, :invalid_value => 4, :disallows_negation => true do let(:matcher) { eq(3) & be_a(Integer) } end end include_examples "making a copy", :and, :dup include_examples "making a copy", :and, :clone it_behaves_like "handles blocks properly", :and context 'when both matchers pass' do it 'passes' do expect(3).to eq(3).and be >= 2 end end it 'has a description composed of both matcher descriptions' do matcher = eq(3).and be >= 2 expect(3).to matcher expect(matcher.description).to eq("eq 3 and be >= 2") end context 'when only the first matcher fails' do it "fails with the first matcher's failure message" do expect { expect(3).to eq(4).and be >= 2 }.to fail_with(dedent <<-EOS) | |expected: 4 | got: 3 | |(compared using ==) | EOS end end context 'when only the second matcher fails' do it "fails with the second matcher's failure message" do expect { expect(3).to be_kind_of(Integer).and eq(4) }.to fail_with(dedent <<-EOS) | |expected: 4 | got: 3 | |(compared using ==) | EOS end end context "when both matchers fail" do context "when both matchers have multi-line failure messages" do it 'fails with a well formatted message containing both sub-messages' do expect { expect(3).to eq(4).and be >= 8 }.to fail_with(dedent <<-EOS) | | expected: 4 | got: 3 | | (compared using ==) | |...and: | | expected: >= 8 | got: 3 EOS end end context "when both matchers have single-line failure messages" do it 'still fails with a multi-line failure message because it reads better than keeping it on a single line' do expect { expect("foo").to start_with("a").and end_with("z") }.to fail_with(dedent <<-EOS) | expected "foo" to start with "a" | |...and: | | expected "foo" to end with "z" EOS end end context "when the first matcher has a multi-line failure message" do it 'fails with a well formatted message containing both sub-messages' do expect { expect("foo").to eq(4).and end_with("z") }.to fail_with(dedent <<-EOS) | | expected: 4 | got: "foo" | | (compared using ==) | |...and: | | expected "foo" to end with "z" EOS end end context "when the second matcher has a multi-line failure message" do it 'fails with a well formatted message containing both sub-messages' do expect { expect("foo").to end_with("z").and eq(4) }.to fail_with(dedent <<-EOS) | expected "foo" to end with "z" | |...and: | | expected: 4 | got: "foo" | | (compared using ==) | EOS end end context "when the first matcher is diffable" do subject { include("foo").and be_a(String) } it 'is diffable' do expect(subject).to be_diffable end context "when only first matcher fails" do it 'fails with a message containing a diff for first matcher' do expected_failure = dedent(<<-EOS) |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bar EOS expect { expect(dedent(<<-EOS)).to subject |baz |bar EOS }.to fail_including(expected_failure) end end context "when only second matcher fails" do subject { include("baz").and be_an(Integer) } it 'fails with a message not containing a diff for first matcher' do expect { expect(dedent(<<-EOS)).to subject |baz |bar EOS }.to fail_with(a_string_excluding "Diff") end end context "when both matcher fail" do subject { include("foo").and eq(35) } it "fails with a message containing a diff with first matcher" do expected_failure = dedent(<<-EOS) | expected "baz\\nbar" to include "foo" | |...and: | | expected: 35 | got: "baz\\nbar" | | (compared using ==) | |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bar EOS expect { expect(dedent(<<-EOS)).to subject |baz |bar EOS }.to fail_including(expected_failure) end end end context "when the first matcher does not implement #diffable?" do subject { matcher_without_diffable.and exist } it 'is not diffable' do expect(subject).not_to be_diffable end end context "when the second matcher does not implement #diffable?" do subject { exist.and matcher_without_diffable } it 'is not diffable' do expect(subject).not_to be_diffable end end context "when the second matcher is diffable" do subject { eq(35).and include("foo") } it 'is diffable' do expect(subject).to be_diffable end it 'fails with a message containing a diff for second matcher' do expected_failure = dedent(<<-EOS) | expected: 35 | got: "baz\\nbar" | | (compared using ==) | |...and: | | expected "baz\\nbar" to include "foo" |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bar EOS expect { expect(dedent(<<-EOS)).to subject |baz |bar EOS }.to fail_including(expected_failure) end end context "when both matchers are diffable" do subject { include("bar").and include("foo") } it 'is diffable' do expect(subject).to be_diffable end it 'fails with a message containing diffs for both matcher' do expected_failure = dedent(<<-EOS) | expected "baz\\nbug" to include "bar" | |...and: | | expected "baz\\nbug" to include "foo" |Diff for (include "bar"): |@@ -1,2 +1,3 @@ |-bar |+baz |+bug | |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bug EOS expect { expect(dedent(<<-EOS)).to subject |baz |bug EOS }.to fail do |error| expect(error.message).to include(expected_failure) end end context 'when matcher transforms the actual' do context 'when the matcher redefines `actual`' do matcher :eq_downcase do |expected| match do |actual| @matcher_internal_actual = actual.downcase values_match? expected, @matcher_internal_actual end def actual @matcher_internal_actual end diffable end it 'shows the redefined value in diff' do expected_failure = dedent(<<-EOS) | expected "HELLO\\nWORLD" to eq downcase "bonjour\\nmonde" | |...and: | | expected "HELLO\\nWORLD" to eq downcase "hola\\nmon" |Diff for (eq downcase "bonjour\\nmonde"): |@@ -1,3 +1,3 @@ |-bonjour |-monde |+hello |+world | |Diff for (eq downcase "hola\\nmon"): |@@ -1,3 +1,3 @@ |-hola |-mon |+hello |+world EOS expect { expect( "HELLO\nWORLD" ).to eq_downcase("bonjour\nmonde").and eq_downcase("hola\nmon") }.to fail do |error| expect(error.message).to include(expected_failure) end end end context 'when the matcher reassigns `@actual`' do matcher :eq_downcase do |expected| match do |actual| @actual = actual.downcase values_match? expected, @actual end diffable end it 'shows the reassigned value in diff' do expected_failure = dedent(<<-EOS) | expected "hello\\nworld" to eq downcase "bonjour\\nmonde" | |...and: | | expected "hello\\nworld" to eq downcase "hola\\nmon" |Diff for (eq downcase "bonjour\\nmonde"): |@@ -1,3 +1,3 @@ |-bonjour |-monde |+hello |+world | |Diff for (eq downcase "hola\\nmon"): |@@ -1,3 +1,3 @@ |-hola |-mon |+hello |+world EOS expect { expect( "HELLO\nWORLD" ).to eq_downcase("bonjour\nmonde").and eq_downcase("hola\nmon") }.to fail do |error| expect(error.message).to include(expected_failure) end end end end end context "when both matchers are not diffable" do subject { be_a(String).and be_truthy } it 'is not diffable' do expect(subject).not_to be_diffable end it 'fails with a message not containing any diff' do expect { expect(35).to subject }.to fail_with(a_string_excluding "Diff") end end end end describe "expect(...).not_to matcher.and(other_matcher)" do it "is not supported" do expect { expect(3).not_to eq(2).and be > 2 }.to raise_error(NotImplementedError, /matcher.and matcher` is not supported/) end end describe "expect(...).to matcher.or(other_matcher)" do it_behaves_like "an RSpec value matcher", :valid_value => 3, :invalid_value => 5, :disallows_negation => true do let(:matcher) { eq(3).or eq(4) } end context 'when using boolean OR `|` alias' do it_behaves_like "an RSpec value matcher", :valid_value => 3, :invalid_value => 5, :disallows_negation => true do let(:matcher) { eq(3) | eq(4) } end end include_examples "making a copy", :or, :dup include_examples "making a copy", :or, :clone it_behaves_like "handles blocks properly", :or it 'has a description composed of both matcher descriptions' do matcher = eq(3).or eq(4) expect(3).to matcher expect(matcher.description).to eq("eq 3 or eq 4") end context 'when both matchers pass' do it 'passes' do expect("foo").to start_with("f").or end_with("o") end end context 'when only the first matcher passes' do it 'passes' do expect("foo").to start_with("f").or end_with("z") end end context 'when only the last matcher passes' do it 'passes' do expect("foo").to start_with("a").or end_with("o") end end context 'when both matchers fail' do context "when both matchers have multi-line failure messages" do it 'fails with a well formatted message containing both sub-messages' do expect { expect(3).to eq(4).or be >= 8 }.to fail_with(dedent <<-EOS) | | expected: 4 | got: 3 | | (compared using ==) | |...or: | | expected: >= 8 | got: 3 EOS end end context "when both matchers have single-line failure messages" do it 'still fails with a multi-line failure message because it reads better than keeping it on a single line' do expect { expect("foo").to start_with("a").or end_with("z") }.to fail_with(dedent <<-EOS) | expected "foo" to start with "a" | |...or: | | expected "foo" to end with "z" EOS end end context "when the first matcher has a multi-line failure message" do it 'fails with a well formatted message containing both sub-messages' do expect { expect("foo").to eq(4).or end_with("z") }.to fail_with(dedent <<-EOS) | | expected: 4 | got: "foo" | | (compared using ==) | |...or: | | expected "foo" to end with "z" EOS end end context "when the second matcher has a multi-line failure message" do it 'fails with a well formatted message containing both sub-messages' do expect { expect("foo").to end_with("z").or eq(4) }.to fail_with(dedent <<-EOS) | expected "foo" to end with "z" | |...or: | | expected: 4 | got: "foo" | | (compared using ==) | EOS end end end context "when first matcher is diffable" do subject { include("foo").or eq(35) } it "is diffable" do expect(subject).to be_diffable end it 'fails with a message containing diff for first matcher' do expected_failure = dedent(<<-EOS) | expected "baz\\nbug" to include "foo" | |...or: | | expected: 35 | got: "baz\\nbug" | | (compared using ==) | |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bug EOS expect { expect(dedent(<<-EOS)).to subject |baz |bug EOS }.to fail_including(expected_failure) end end context "when second matcher is diffable" do subject { eq(35).or include("foo") } it "is diffable" do expect(subject).to be_diffable end it 'fails with a message containing diff for second matcher' do expected_failure = dedent(<<-EOS) | expected: 35 | got: "baz\\nbug" | | (compared using ==) | |...or: | | expected "baz\\nbug" to include "foo" |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bug EOS expect { expect(dedent(<<-EOS)).to subject |baz |bug EOS }.to fail_including(expected_failure) end end context "when both matchers are diffable" do subject { include("foo").or include("buzz") } it "is diffable" do expect(subject).to be_diffable end it 'fails with a message containing diffs for both matcher' do expected_failure = dedent(<<-EOS) | expected "baz\\nbug" to include "foo" | |...or: | | expected "baz\\nbug" to include "buzz" |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+baz |+bug | |Diff for (include "buzz"): |@@ -1,2 +1,3 @@ |-buzz |+baz |+bug EOS expect { expect(dedent(<<-EOS)).to subject |baz |bug EOS }.to fail_including(expected_failure) end end context "when both matchers are not diffable" do subject { be_a(String).or be_an(Integer) } it "is not diffable" do expect(subject).not_to be_diffable end it 'fails with a message containing diffs for both matcher' do expect { expect(true).to subject }.to fail_with(a_string_excluding "Diff") end end end context "when chaining many matchers together" do it 'can pass appropriately' do matcher = start_with("f").and end_with("z").or end_with("o") expect("foo").to matcher expect(matcher.description).to eq('start with "f" and end with "z" or end with "o"') end it 'fails with complete diffs if its matchers are diffable' do matcher = include("bar").and include("buzz").or include("foo") expected_failure = dedent(<<-EOS) | expected "bug\\nsquash" to include "bar" | |...and: | | expected "bug\\nsquash" to include "buzz" | | ...or: | | expected "bug\\nsquash" to include "foo" |Diff for (include "bar"): |@@ -1,2 +1,3 @@ |-bar |+bug |+squash | |Diff for (include "buzz"): |@@ -1,2 +1,3 @@ |-buzz |+bug |+squash | |Diff for (include "foo"): |@@ -1,2 +1,3 @@ |-foo |+bug |+squash EOS expect { expect(dedent(<<-EOS)).to matcher |bug |squash EOS }.to fail do |error| expect(error.message).to include(expected_failure) end end it 'fails with a complete message' do expect { expect(3).to eq(1).and eq(2).and eq(3).and eq(4) }.to fail_with(dedent <<-EOS) | | expected: 1 | got: 3 | | (compared using ==) | |...and: | | expected: 2 | got: 3 | | (compared using ==) | | ...and: | | expected: 4 | got: 3 | | (compared using ==) | EOS end end describe "expect(...).not_to matcher.or(other_matcher)" do it "is not supported" do expect { expect(3).not_to eq(2).or be > 2 }.to raise_error(NotImplementedError, /matcher.or matcher` is not supported/) end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/contain_exactly_spec.rb000066400000000000000000000474641455770000100276400ustar00rootroot00000000000000class UnsortableObject def initialize(id) @id = id end def inspect @id.to_s end def ==(_other) false end end # AR::Relation is meant to act like a collection, but does # not include `Enumerable`. It does implement `to_ary`. class FakeActiveRecordRelation def initialize(records) @records = records end def to_ary @records end end RSpec.describe "should =~ array", :uses_should do it "passes a valid positive expectation" do [1, 2].should =~ [2, 1] end it "fails an invalid positive expectation" do expect { [1, 2, 3].should =~ [2, 1] }.to fail_with(/expected collection contained/) end context "when the array defines a `=~` method" do it 'delegates to that method rather than using the contain_exactly matcher' do array = [] def array.=~(other) other == :foo end array.should =~ :foo expect { array.should =~ :bar }.to fail_with(/expected: :bar/) end end context 'when the array defines a `send` method' do it 'still works' do array = [1, 2] def array.send; :sent; end array.should =~ array end end context "when the array undefines `=~`" do it 'still works' do array_klass = Class.new(Array) { undef =~ if respond_to?(:=~) } array = array_klass.new([1, 2]) array.should =~ [1, 2] expect { array.should =~ [0, 1, 2] }.to fail_with(/expected collection contained/) end end end RSpec.describe "should_not =~ [:with, :multiple, :args]", :uses_should do it "fails when the arrays match" do expect { [1, 2, 3].should_not =~ [1, 2, 3] }.to fail_with "expected [1, 2, 3] not to contain exactly 1, 2, and 3" end it "fails when the arrays match in a different order" do expect { [1, 3, 2].should_not =~ [1, 2, 3] }.to fail_with "expected [1, 3, 2] not to contain exactly 1, 2, and 3" end it "passes when there are extra elements in the array" do [1, 3].should_not =~ [1, 2, 3] end it "passes when there are elements missing from the array" do [1, 2, 3, 4].should_not =~ [1, 2, 3] end end RSpec.describe "using contain_exactly with expect" do it "passes a valid positive expectation" do expect([1, 2]).to contain_exactly(2, 1) end it "fails an invalid positive expectation" do expect { expect([1, 2, 3]).to contain_exactly(2, 1) }.to fail_with(/expected collection contained/) end it "passes for an out of order valid positive expectation with hashes" do expect([ { :a => 10 }, { :a => -10 } ]).to contain_exactly( { :a => (a_value < 0) }, { :a => (a_value > 0) } ) end it "passes for an in order valid positive expectation with hashes" do expect([ { :a => 10 }, { :a => -10 } ]).to contain_exactly( { :a => (a_value > 0) }, { :a => (a_value < 0) } ) end it 'works with strict test doubles (which have not defined `<=>`)' do dbl_1 = double("1") dbl_2 = double("2") expect([dbl_1, dbl_2]).to contain_exactly(dbl_2, dbl_1) expect { expect([dbl_1, dbl_2]).to contain_exactly(dbl_1) }.to fail end it "does not support strings (which have no standard way to be enumerated: bytes, chars or lines)" do expect { expect("abcd").to contain_exactly("d", "c", "a", "b") }.to fail_with('expected a collection that can be converted to an array with `#to_ary` or `#to_a`, but got "abcd"') end it "supports ranges" do expect(1..3).to contain_exactly(1, 2, 3) end end RSpec.describe "expect(array).to contain_exactly(*other_array)" do it_behaves_like "an RSpec value matcher", :valid_value => [1, 2], :invalid_value => [1] do let(:matcher) { contain_exactly(2, 1) } end it 'is also exposed as `match_array` (with unsplatted args)' do expect([1, 2, 3]).to match_array([3, 2, 1]) end it "passes if target contains all items" do expect([1, 2, 3]).to contain_exactly(1, 2, 3) end it "passes if target contains all items out of order" do expect([1, 3, 2]).to contain_exactly(1, 2, 3) end it 'fails if the expected array is empty and the actual array is non-empty' do expect { expect([1]).to contain_exactly # no arguments passed to the matcher }.to fail_with(<<-MESSAGE) expected collection contained: [] actual collection contained: [1] the extra elements were: [1] MESSAGE end it 'fails if the actual array is empty and the expected array is non-empty' do expect { expect([]).to contain_exactly(1) }.to fail_with(<<-MESSAGE) expected collection contained: [1] actual collection contained: [] the missing elements were: [1] MESSAGE end def timeout_if_not_debugging(time) in_sub_process_if_possible do require 'timeout' return yield if defined?(::Debugger) Timeout.timeout(time) { yield } end end it 'fails a match of 11 items with duplicates in a reasonable amount of time' do timeout_if_not_debugging(0.1) do expected = [0, 1, 1, 3, 3, 3, 4, 4, 8, 8, 9 ] actual = [ 1, 2, 3, 3, 3, 3, 7, 8, 8, 9, 9] expect { expect(actual).to contain_exactly(*expected) }.to fail_including("the missing elements were: [0, 1, 4, 4]") end end it "fails if target includes extra items" do expect { expect([1, 2, 3, 4]).to contain_exactly(1, 2, 3) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 2, 3] actual collection contained: [1, 2, 3, 4] the extra elements were: [4] MESSAGE end it "fails if target is missing items" do expect { expect([1, 2]).to contain_exactly(1, 2, 3) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 2, 3] actual collection contained: [1, 2] the missing elements were: [3] MESSAGE end it "fails if target is missing items and has extra items" do expect { expect([1, 2, 4]).to contain_exactly(1, 2, 3) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 2, 3] actual collection contained: [1, 2, 4] the missing elements were: [3] the extra elements were: [4] MESSAGE end it "sorts items in the error message if they all respond to <=>" do expect { expect([6, 2, 1, 5]).to contain_exactly(4, 1, 2, 3) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 2, 3, 4] actual collection contained: [1, 2, 5, 6] the missing elements were: [3, 4] the extra elements were: [5, 6] MESSAGE end it "does not sort items in the error message if they don't all respond to <=>" do expect { expect([UnsortableObject.new(2), UnsortableObject.new(1)]).to contain_exactly(UnsortableObject.new(4), UnsortableObject.new(3)) }.to fail_with(<<-MESSAGE) expected collection contained: [4, 3] actual collection contained: [2, 1] the missing elements were: [4, 3] the extra elements were: [2, 1] MESSAGE end it "accurately reports extra elements when there are duplicates" do expect { expect([1, 1, 1, 5]).to contain_exactly(1, 5) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 5] actual collection contained: [1, 1, 1, 5] the extra elements were: [1, 1] MESSAGE end it "accurately reports missing elements when there are duplicates" do expect { expect([1, 5]).to contain_exactly(1, 1, 5) }.to fail_with(<<-MESSAGE) expected collection contained: [1, 1, 5] actual collection contained: [1, 5] the missing elements were: [1] MESSAGE end end RSpec.describe "expect(...).not_to contain_exactly(:with, :multiple, :args)" do it "fails when the arrays match" do expect { expect([1, 2, 3]).not_to contain_exactly(1, 2, 3) }.to fail_with "expected [1, 2, 3] not to contain exactly 1, 2, and 3" end it "fails when the arrays match in a different order" do expect { expect([1, 3, 2]).not_to contain_exactly(1, 2, 3) }.to fail_with "expected [1, 3, 2] not to contain exactly 1, 2, and 3" end it "passes when there are extra elements in the array" do expect([1, 3]).not_to contain_exactly(1, 2, 3) end it "passes when there are elements missing from the array" do expect([1, 2, 3, 4]).not_to contain_exactly(1, 2, 3) end end RSpec.describe "matching against things that aren't arrays" do it "fails with nil and the expected error message is given" do expect { expect(nil).to contain_exactly(1, 2, 3) }.to fail_with(/expected a collection/) end it "fails with a float and the expected error message is given" do expect { expect(3.7).to contain_exactly(1, 2, 3) }.to fail_with(/expected a collection/) end it "fails with a string and the expected error message is given" do expect { expect("I like turtles").to contain_exactly(1, 2, 3) }.to fail_with(/expected a collection/) end it 'works with other collection objects' do in_sub_process_if_possible do require 'set' expect(Set.new([3, 2, 1])).to contain_exactly(1, 2, 3) expect { expect(Set.new([3, 2, 1])).to contain_exactly(1, 2) }.to fail_including("expected collection contained: [1, 2]") end end it 'works with non-enumerables that implement `to_ary`' do relation = FakeActiveRecordRelation.new([1, 2, 3]) expect(relation).to contain_exactly(2, 1, 3) expect { expect(relation).to contain_exactly(1, 2) }.to fail_including("expected collection contained: [1, 2]") end end RSpec.describe "Composing `contain_exactly` with other matchers" do context "when it is compared to multiple possible matches" do it 'works properly when passed as an argument in its aliased form' do expect([[1, 3], ["food", "barn"]]).to include( a_collection_containing_exactly(/foo/, /bar/) ) end end describe "expect(...).to contain_exactly(matcher, matcher)" do it 'passes when the array matches the matchers in the same order' do expect(["food", "barn"]).to contain_exactly( a_string_matching(/foo/), a_string_matching(/bar/) ) end it 'passes when the array matches the matchers in a different order' do expect(["food", "barn"]).to contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/) ) end it 'fails with a useful message when there is an extra element' do expect { expect(["food", "barn", "goo"]).to contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/) ) }.to fail_with(dedent <<-EOS) |expected collection contained: [(a string matching /bar/), (a string matching /foo/)] |actual collection contained: ["barn", "food", "goo"] |the extra elements were: ["goo"] | EOS end it 'fails with a useful message when there is a missing element' do expect { expect(["food", "barn"]).to contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/), a_string_matching(/goo/) ) }.to fail_with(dedent <<-EOS) |expected collection contained: [(a string matching /bar/), (a string matching /foo/), (a string matching /goo/)] |actual collection contained: ["barn", "food"] |the missing elements were: [(a string matching /goo/)] | EOS end it 'pairs up the items in order to minimize the number of unpaired items' do expect { expect(["fool", "food", "good"]).to contain_exactly(/foo/, /fool/, /poo/) }.to fail_with(dedent <<-EOS) |expected collection contained: [/foo/, /fool/, /poo/] |actual collection contained: ["food", "fool", "good"] |the missing elements were: [/poo/] |the extra elements were: ["good"] | EOS end it 'provides a description' do description = contain_exactly(a_string_matching(/bar/), a_string_matching(/foo/)).description expect(description).to eq("contain exactly (a string matching /bar/) and (a string matching /foo/)") end context 'when an earlier matcher matches more strictly than a later matcher' do it 'works when the actual items match in the same order' do expect(["food", "fool"]).to contain_exactly(a_string_matching(/foo/), a_string_matching(/fool/)) end it 'works when the actual items match in reverse order' do expect(["fool", "food"]).to contain_exactly(a_string_matching(/foo/), a_string_matching(/fool/)) end it 'can handle multiple sets of overlapping matches' do expect(["fool", "barn", "bare", "food"]).to contain_exactly( a_string_matching(/bar/), a_string_matching(/barn/), a_string_matching(/foo/), a_string_matching(/fool/) ) end end it "can use `a_value_within` and `a_string_starting_with` against multiple types of values" do expect(["barn", 2.45]).to contain_exactly( a_value_within(0.1).of(2.5), a_string_starting_with("bar") ) end context 'when a later matcher matches more strictly than an earlier matcher' do it 'works when the actual items match in the same order' do expect(["fool", "food"]).to contain_exactly(a_string_matching(/fool/), a_string_matching(/foo/)) end it 'works when the actual items match in reverse order' do expect(["food", "fool"]).to contain_exactly(a_string_matching(/fool/), a_string_matching(/foo/)) end end end describe "expect(...).to_not contain_exactly(matcher, matcher)" do it 'fails when the array matches the matchers' do expect { expect(["food", "barn"]).to_not contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/) ) }.to fail_with 'expected ["food", "barn"] not to contain exactly '\ "(a string matching /bar/) and (a string matching /foo/)" end it 'passes when there is an extra element' do expect(["food", "barn", "goo"]).to_not contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/) ) end it 'passes when there is a missing element' do expect(["food", "barn"]).to_not contain_exactly( a_string_matching(/bar/), a_string_matching(/foo/), a_string_matching(/goo/) ) end end end RSpec.describe "Reusing a matcher that memoizes state" do require "rspec/matchers/fail_matchers" it "works properly in spite of the memoization" do matcher = contain_exactly(eq(1)) expect { expect([2]).to matcher }.to fail_including(<<-MESSAGE) expected collection contained: [(eq 1)] actual collection contained: [2] the missing elements were: [(eq 1)] the extra elements were: [2] MESSAGE expect { expect([3]).to matcher }.to fail_including(<<-MESSAGE) expected collection contained: [(eq 1)] actual collection contained: [3] the missing elements were: [(eq 1)] the extra elements were: [3] MESSAGE end end module RSpec module Matchers module BuiltIn class ContainExactly RSpec.describe PairingsMaximizer do it 'finds unmatched expected indexes' do maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1] }) expect(maximizer.solution.unmatched_expected_indexes).to eq([0]) end it 'finds unmatched actual indexes' do maximizer = PairingsMaximizer.new({ 0 => [0] }, { 0 => [0], 1 => [] }) expect(maximizer.solution.unmatched_actual_indexes).to eq([1]) end describe "finding indeterminate indexes" do it 'does not include unmatched indexes' do maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1], 1 => [] }) expect(maximizer.solution.indeterminate_expected_indexes).not_to include(0) expect(maximizer.solution.indeterminate_actual_indexes).not_to include(1) end it 'does not include indexes that are reciprocally to exactly one index' do maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1], 1 => [0] }) expect(maximizer.solution.indeterminate_expected_indexes).not_to include(1) expect(maximizer.solution.indeterminate_actual_indexes).not_to include(0) end it 'includes indexes that have multiple matches' do maximizer = PairingsMaximizer.new({ 0 => [0, 2], 1 => [0, 2], 2 => [] }, { 0 => [0, 1], 1 => [], 2 => [0, 1] }) expect(maximizer.solution.indeterminate_expected_indexes).to include(0, 1) expect(maximizer.solution.indeterminate_actual_indexes).to include(0, 2) end it 'includes indexes that have one match which has multiple matches' do maximizer = PairingsMaximizer.new({ 0 => [0], 1 => [0], 2 => [1, 2] }, { 0 => [0, 1], 1 => [2], 2 => [2] }) expect(maximizer.solution.indeterminate_expected_indexes).to include(0, 1) expect(maximizer.solution.indeterminate_actual_indexes).to include(1, 2) end end describe "#unmatched_item_count" do it 'returns the count of unmatched items' do maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] }, { 0 => [1], 1 => [0] }) expect(maximizer.solution.unmatched_item_count).to eq(0) maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] }, { 0 => [1], 1 => [0], 2 => [] }) expect(maximizer.solution.unmatched_item_count).to eq(1) end end describe "#find_best_solution" do matcher :produce_result do |unmatched_expected, unmatched_actual| match do |result| result.candidate? && result.unmatched_expected_indexes == unmatched_expected && result.unmatched_actual_indexes == unmatched_actual end failure_message do |result| if result.candidate_result? "expected a complete solution, but still had indeterminate indexes: " \ "expected: #{result.indeterminate_expected_indexes.inspect}; " \ "actual: #{result.indeterminate_actual_indexes.inspect}" elsif result.unmatched_expected_indexes != unmatched_expected "expected unmatched_expected_indexes: #{unmatched_expected.inspect} " \ "but got: #{result.unmatched_expected_indexes.inspect}" elsif result.unmatched_actual_indexes != unmatched_actual "expected unmatched_actual_indexes: #{unmatched_actual.inspect} " \ "but got: #{result.unmatched_actual_indexes.inspect}" end end end it 'returns no unmatched indexes when everything reciprocally matches one item' do maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] }, { 0 => [1], 1 => [0] }) expect(maximizer.find_best_solution).to produce_result([], []) end it 'returns unmatched indexes for everything that has no matches' do maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1], 1 => [] }) expect(maximizer.find_best_solution).to produce_result([0], [1]) end it 'searches the solution space for a perfectly matching solution' do maximizer = PairingsMaximizer.new({ 0 => [0, 1], 1 => [0] }, { 0 => [0, 1], 1 => [0] }) expect(maximizer.find_best_solution).to produce_result([], []) end end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/cover_spec.rb000066400000000000000000000037271455770000100255640ustar00rootroot00000000000000if (1..2).respond_to?(:cover?) RSpec.describe "expect(...).to cover(expected)" do it_behaves_like "an RSpec value matcher", :valid_value => (1..10), :invalid_value => (20..30) do let(:matcher) { cover(5) } end context "for a range target" do it "passes if target covers expected" do expect((1..10)).to cover(5) end it "fails if target does not cover expected" do expect { expect((1..10)).to cover(11) }.to fail_with("expected 1..10 to cover 11") end end end RSpec.describe "expect(...).to cover(with, multiple, args)" do context "for a range target" do it "passes if target covers all items" do expect((1..10)).to cover(4, 6) end it "fails if target does not cover any one of the items" do expect { expect((1..10)).to cover(4, 6, 11) }.to fail_with("expected 1..10 to cover 4, 6, and 11") end end end RSpec.describe "expect(...).not_to cover(expected)" do context "for a range target" do it "passes if target does not cover expected" do expect((1..10)).not_to cover(11) end it "fails if target covers expected" do expect { expect((1..10)).not_to cover(5) }.to fail_with("expected 1..10 not to cover 5") end end end RSpec.describe "expect(...).not_to cover(with, multiple, args)" do context "for a range target" do it "passes if the target does not cover any of the expected" do expect((1..10)).not_to cover(11, 12, 13) end it "fails if the target covers all of the expected" do expect { expect((1..10)).not_to cover(4, 6) }.to fail_with("expected 1..10 not to cover 4 and 6") end it "fails if the target covers some (but not all) of the expected" do expect { expect((1..10)).not_to cover(5, 11) }.to fail_with("expected 1..10 not to cover 5 and 11") end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/eq_spec.rb000066400000000000000000000136641455770000100250540ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe "eq" do it_behaves_like "an RSpec value matcher", :valid_value => 1, :invalid_value => 2 do let(:matcher) { eq(1) } end it "is diffable" do expect(eq(1)).to be_diffable end it "matches when actual == expected" do expect(1).to eq(1) end it "does not match when actual != expected" do expect(1).not_to eq(2) end it "compares by sending == to actual (not expected)" do called = false actual = Class.new do define_method :== do |_other| called = true end end.new expect(actual).to eq :anything # to trigger the matches? method expect(called).to be_truthy end it "describes itself" do matcher = eq(1) matcher.matches?(1) expect(matcher.description).to eq "eq 1" end it "provides message, expected and actual on #failure_message" do matcher = eq("1") matcher.matches?(1) expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using ==)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eq(1) matcher.matches?(1) expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using ==)\n" end # Older versions of Ruby such as less than 1.9 do not have String#encoding available, they are an array of bytes if String.method_defined?(:encoding) context "with String encoding as UTF-16LE" do it "provides message, expected and actual on #failure_message when string encoding is the same" do matcher = eq('abc'.encode('UTF-16LE')) matcher.matches?('def'.encode('UTF-16LE')) expect(matcher.failure_message).to eq "\nexpected: \"abc\"\n got: \"def\"\n\n(compared using ==)\n" end it "matches when actual is BINARY encoding and expected is UTF-8 encoding with the same chars" do expect('abc'.encode('BINARY')).to eq 'abc'.encode('UTF-8') end it "provides message, expected and actual with encoding details on #failure_message when string encoding is different" do matcher = eq('abc'.encode('UTF-16LE')) matcher.matches?('abc'.force_encoding('ASCII-8BIT')) expect(matcher.failure_message).to eq "\nexpected: # \"abc\"\n got: # \"abc\"\n\n(compared using ==)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eq('abc'.encode('UTF-16LE')) matcher.matches?('abc'.encode('UTF-16LE')) expect(matcher.failure_message_when_negated).to eq "\nexpected: value != \"abc\"\n got: \"abc\"\n\n(compared using ==)\n" end end end context "with Time objects" do RSpec::Matchers.define :a_string_with_differing_output do match do |string| time_strings = /expected: (.+)\n.*got: (.+)$/.match(string).captures time_strings.uniq.count == 2 end end let(:time1) { Time.utc(1969, 12, 31, 19, 10, 40, 101) } let(:time2) { Time.utc(1969, 12, 31, 19, 10, 40, 102) } it "provides additional precision on #failure_message" do expect { expect(time1).to eq(time2) }.to fail_with(a_string_with_differing_output) end it "provides additional precision on #negative_failure_message" do expect { expect(time1).to_not eq(time1) }.to fail_with(a_string_with_differing_output) end end it 'fails properly when the actual is an array of multiline strings' do expect { expect(["a\nb", "c\nd"]).to eq([]) }.to fail_including("expected: []") end describe '#description' do # Ruby 1.8.7 produces a less precise output expected_seconds = Time.method_defined?(:nsec) ? '000000000' : '000000' [ [nil, 'eq nil'], [true, 'eq true'], [false, 'eq false'], [:symbol, 'eq :symbol'], [1, 'eq 1'], [1.2, 'eq 1.2'], ['foo', 'eq "foo"'], [/regex/, 'eq /regex/'], [['foo'], 'eq ["foo"]'], [{ :foo => :bar }, 'eq {:foo=>:bar}'], [Class, 'eq Class'], [RSpec, 'eq RSpec'], [Time.utc(2014, 1, 1), "eq 2014-01-01 00:00:00.#{expected_seconds} +0000"], ].each do |expected, expected_description| context "with #{expected.inspect}" do around { |ex| with_env_vars('TZ' => 'UTC', &ex) } if expected.is_a?(Time) it "is \"#{expected_description}\"" do expect(eq(expected).description).to eq expected_description end end end context "with Date.new(2014, 1, 1)" do it "is eq to Date.new(2014, 1, 1).inspect" do in_sub_process_if_possible do require 'date' date = Date.new(2014, 1, 1) expect(eq(date).description).to eq "eq #{date.inspect}" end end end context "with Complex(1, 2)" do it "is eq to Complex(1, 2).inspect" do in_sub_process_if_possible do # complex is available w/o requiring on ruby 1.9+. # Loading it on 1.9+ issues a warning, so we only load it on 1.8.7. require 'complex' if RUBY_VERSION == '1.8.7' complex = Complex(1, 2) expect(eq(complex).description).to eq "eq #{complex.inspect}" end end end context 'with object' do it 'matches with "^eq #$"' do expect(eq(Object.new).description).to match(/^eq #$/) end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/eql_spec.rb000066400000000000000000000051751455770000100252260ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe "eql" do it_behaves_like "an RSpec value matcher", :valid_value => 1, :invalid_value => 2 do let(:matcher) { eql(1) } end it "is diffable" do expect(eql(1)).to be_diffable end it "matches when actual.eql?(expected)" do expect(1).to eql(1) end it "does not match when !actual.eql?(expected)" do expect(1).not_to eql(2) end it "describes itself" do matcher = eql(1) matcher.matches?(1) expect(matcher.description).to eq "eql 1" end it "provides message, expected and actual on #failure_message" do matcher = eql("1") matcher.matches?(1) expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using eql?)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eql(1) matcher.matches?(1) expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using eql?)\n" end # Older versions of Ruby such as less than 1.9 do not have String#encoding available, they are an array of bytes if String.method_defined?(:encoding) context "with String encoding as UTF-16LE" do it "provides message, expected and actual on #failure_message when string encoding is the same" do matcher = eql('abc'.encode('UTF-16LE')) matcher.matches?('def'.encode('UTF-16LE')) expect(matcher.failure_message).to eq "\nexpected: \"abc\"\n got: \"def\"\n\n(compared using eql?)\n" end it "matches when actual is BINARY encoding and expected is UTF-8 encoding with the same chars" do expect('abc'.encode('BINARY')).to eq 'abc'.encode('UTF-8') end it "provides message, expected and actual with encoding details on #failure_message when string encoding is different" do matcher = eql('abc'.encode('UTF-16LE')) matcher.matches?('abc'.force_encoding('ASCII-8BIT')) expect(matcher.failure_message).to eq "\nexpected: # \"abc\"\n got: # \"abc\"\n\n(compared using eql?)\n" end it "provides message, expected and actual on #negative_failure_message" do matcher = eql('abc'.encode('UTF-16LE')) matcher.matches?('abc'.encode('UTF-16LE')) expect(matcher.failure_message_when_negated).to eq "\nexpected: value != \"abc\"\n got: \"abc\"\n\n(compared using eql?)\n" end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/equal_spec.rb000066400000000000000000000074451455770000100255560ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe "equal" do it_behaves_like "an RSpec value matcher", :valid_value => :a, :invalid_value => :b do let(:matcher) { equal(:a) } end def inspect_object(o) "#<#{o.class}:#{o.object_id}> => #{o.inspect}" end it "matches when actual.equal?(expected)" do expect(1).to equal(1) end it "does not match when !actual.equal?(expected)" do expect("1").not_to equal("1".dup) end it "describes itself" do matcher = equal(1) matcher.matches?(1) expect(matcher.description).to eq "equal 1" end context "when the expected object is falsey in conditional semantics" do it "describes itself with the expected object" do matcher = equal(nil) matcher.matches?(nil) expect(matcher.description).to eq "equal nil" end end context "when the expected object's #equal? always returns true" do let(:strange_string) do string = "foo".dup def string.equal?(_other) true end string end it "describes itself with the expected object" do matcher = equal(strange_string) matcher.matches?(strange_string) expect(matcher.description).to eq 'equal "foo"' end end context "the output for expected" do it "doesn't include extra object detail for `true`" do expected, actual = true, "1" expect { expect(actual).to equal(expected) }.to fail_with "\nexpected true\n got #{inspect_object(actual)}\n" end it "doesn't include extra object detail for `false`" do expected, actual = false, "1" expect { expect(actual).to equal(expected) }.to fail_with "\nexpected false\n got #{inspect_object(actual)}\n" end it "doesn't include extra object detail for `nil`" do expected, actual = nil, "1" expect { expect(actual).to equal(expected) }.to fail_with "\nexpected nil\n got #{inspect_object(actual)}\n" end end context "the output for actual" do it "doesn't include extra object detail for `true`" do expected, actual = true, false expect { expect(actual).to equal(expected) }.to fail_with "\nexpected true\n got false\n" end it "doesn't include extra object detail for `false`" do expected, actual = false, nil expect { expect(actual).to equal(expected) }.to fail_with "\nexpected false\n got nil\n" end it "doesn't include extra object detail for `nil`" do expected, actual = nil, false expect { expect(actual).to equal(expected) }.to fail_with "\nexpected nil\n got false\n" end end it "suggests the `eq` matcher on failure" do expected, actual = "1", "1".dup expect { expect(actual).to equal(expected) }.to fail_with <<-MESSAGE expected #{inspect_object(expected)} got #{inspect_object(actual)} Compared using equal?, which compares object identity, but expected and actual are not the same object. Use `expect(actual).to eq(expected)` if you don't care about object identity in this example. MESSAGE end it "provides message on #negative_failure_message" do expected = actual = "1" matcher = equal(expected) matcher.matches?(actual) expect(matcher.failure_message_when_negated).to eq <<-MESSAGE expected not #{inspect_object(expected)} got #{inspect_object(actual)} Compared using equal?, which compares object identity. MESSAGE end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/exist_spec.rb000066400000000000000000000106231455770000100255730ustar00rootroot00000000000000RSpec.describe "exist matcher" do it_behaves_like "an RSpec value matcher", :valid_value => Class.new { def exist?; true; end }.new, :invalid_value => Class.new { def exist?; false; end }.new do let(:matcher) { exist } end context "when the object does not respond to #exist? or #exists?" do subject { double } [:to, :not_to].each do |expect_method| describe "expect(...).#{expect_method} exist" do it "fails" do expect { expect(subject).send(expect_method, exist) }.to fail_including("it does not respond to either `exist?` or `exists?`") end end end end it 'composes gracefully' do expect([ double, double(:exists? => false), double(:exists? => true), ]).to include existing end [:exist?, :exists?].each do |predicate| context "when the object responds to ##{predicate}" do describe "expect(...).to exist" do it "passes if #{predicate}" do expect(double(predicate => true)).to exist end it "fails if not #{predicate}" do expect { expect(double(predicate => false)).to exist }.to fail_with(/expected .* to exist/) end it 'works when the object overrides `send`' do klass = Struct.new(:message) do def send :message_sent end define_method predicate do true end end expect(klass.new("msg")).to exist end end describe "expect(...).not_to exist" do it "passes if not #{predicate}" do expect(double(predicate => false)).not_to exist end it "fails if #{predicate}" do expect { expect(double(predicate => true)).not_to exist }.to fail_with(/expected .* not to exist/) end end end end context "when the object responds to #exist? and #exists?" do context "when they both return falsey values" do subject { double(:exist? => false, :exists? => nil) } describe "expect(...).not_to exist" do it "passes" do expect(subject).not_to exist end end describe "expect(...).to exist" do it "fails" do expect { expect(subject).to exist }.to fail_with(/expected .* to exist/) end end end context "when they both return truthy values" do subject { double(:exist? => true, :exists? => "something true") } describe "expect(...).not_to exist" do it "fails" do expect { expect(subject).not_to exist }.to fail_with(/expected .* not to exist/) end end describe "expect(...).to exist" do it "passes" do expect(subject).to exist end end end context "when they return values with different truthiness" do subject { double(:exist? => true, :exists? => false) } [:to, :not_to].each do |expect_method| describe "expect(...).#{expect_method} exist" do it "fails" do expect { expect(subject).send(expect_method, exist) }.to fail_including("`exist?` and `exists?` returned different values") end end end end context "when one predicate is deprecated" do context 'File has deprecated exists?' do it 'will not call exists? triggering the warning' do expect(File).to exist __FILE__ end end context 'FileTest has deprecated exists?' do it 'will not call exists? triggering the warning' do expect(FileTest).to exist __FILE__ end end if RUBY_VERSION > "1.9" context 'Dir has deprecated exists?' do it 'will not call exists? triggering the warning' do expect(Dir).to exist Dir.pwd end end end end end it 'passes any provided arguments to the call to #exist?' do object = double expect(object).to receive(:exist?).with(:foo, :bar) { true }.at_least(:once) expect(object).to exist(:foo, :bar) end it 'memoizes the call to `exist?` because it can be expensive (such as doing a DB query)' do object = double allow(object).to receive(:exist?) { false } expect { expect(object).to exist }.to fail expect(object).to have_received(:exist?).once end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/has_spec.rb000066400000000000000000000144741455770000100252220ustar00rootroot00000000000000RSpec.describe "expect(...).to have_sym(*args)" do it_behaves_like "an RSpec value matcher", :valid_value => { :a => 1 }, :invalid_value => {} do let(:matcher) { have_key(:a) } end it "passes if #has_sym?(*args) returns true" do expect({ :a => "A" }).to have_key(:a) end if RSpec::Support::RubyFeatures.required_kw_args_supported? binding.eval(<<-CODE, __FILE__, __LINE__) it 'supports the use of required keyword arguments' do thing = Class.new { def has_keyword?(keyword:); keyword == 'a'; end } expect(thing.new).to have_keyword(keyword: 'a') end CODE end if RSpec::Support::RubyFeatures.kw_args_supported? binding.eval(<<-CODE, __FILE__, __LINE__) it 'supports the use of optional keyword arguments' do thing = Class.new { def has_keyword?(keyword: 'b'); keyword == 'a'; end } expect(thing.new).to have_keyword(keyword: 'a') end CODE end it "fails if #has_sym?(*args) returns false" do expect { expect({ :b => "B" }).to have_key(:a) }.to fail_with('expected `{:b=>"B"}.has_key?(:a)` to return true, got false') end obj_with_block_method = Object.new def obj_with_block_method.has_some_stuff?; yield; end it 'forwards the given `{ }` block on to the `has_xyz?` method' do expect(obj_with_block_method).to have_some_stuff { true } expect(obj_with_block_method).to_not have_some_stuff { false } end it 'forwards the given `do..end` block on to the `has_xyz?` method' do expect(obj_with_block_method).to have_some_stuff do true end expect(obj_with_block_method).to_not have_some_stuff do false end end it 'favors a curly brace block over a do...end one since it binds to the matcher method' do expect(obj_with_block_method).to have_some_stuff { true } do false end expect(obj_with_block_method).not_to have_some_stuff { false } do true end end it 'does not include any args in the failure message if no args were given to the matcher' do o = Object.new def o.has_some_stuff?; false; end expect { expect(o).to have_some_stuff }.to fail_with("expected `#{o.inspect}.has_some_stuff?` to return true, got false") end it 'includes multiple args in the failure message if multiple args were given to the matcher' do o = Object.new def o.has_some_stuff?(*_); false; end expect { expect(o).to have_some_stuff(:a, 7, "foo") }.to fail_with(%Q{expected `#{o.inspect}.has_some_stuff?(:a, 7, "foo")` to return true, got false}) end it "fails if #has_sym?(*args) returns nil" do klass = Class.new do def has_foo? end end expect { expect(klass.new).to have_foo }.to fail_with(/expected `.*\.has_foo\?` to return true, got nil/) end it 'fails if #has_sym?(*args) is private' do klass = Class.new do private def has_foo? true end end expect { expect(klass.new).to have_foo }.to fail_with(/private/) end it "fails if target does not respond to #has_sym?" do expect { expect(Object.new).to have_key(:a) }.to fail_including('to respond to `has_key?`') end it "reraises an exception thrown in #has_sym?(*args)" do o = Object.new def o.has_sym?(*_args) raise "Funky exception" end expect { expect(o).to have_sym(:foo) }.to raise_error("Funky exception") end it 'allows composable aliases to be defined' do RSpec::Matchers.alias_matcher :an_object_having_sym, :have_sym o = Object.new def o.has_sym?(sym); sym == :foo; end expect(o).to an_object_having_sym(:foo) expect(o).not_to an_object_having_sym(:bar) expect(an_object_having_sym(:foo).description).to eq("an object having sym :foo") end it 'composes gracefully' do RSpec::Matchers.alias_matcher :an_object_having_foo, :have_foo expect([ double, double(:has_foo? => false), double(:has_foo? => true), ]).to include an_object_having_foo end end RSpec.describe "expect(...).not_to have_sym(*args)" do it "passes if #has_sym?(*args) returns false" do expect({ :a => "A" }).not_to have_key(:b) end context "when strict_predicate_matchers is set to true" do it "fails when #has_sym? returns nil" do actual = double("actual", :has_foo? => nil) expect { expect(actual).not_to have_foo }.to fail_with("expected `#{actual.inspect}.has_foo?` to return false, got nil") end end context "when strict_predicate_matchers is set to false" do around do |example| RSpec::Expectations.configuration.strict_predicate_matchers = false example.run RSpec::Expectations.configuration.strict_predicate_matchers = true end it "passes if #has_sym?(*args) returns nil" do actual = double("actual", :has_foo? => nil) expect(actual).not_to have_foo end end it "fails if #has_sym?(*args) returns true" do expect { expect({ :a => "A" }).not_to have_key(:a) }.to fail_with('expected `{:a=>"A"}.has_key?(:a)` to return false, got true') end it "fails if target does not respond to #has_sym?" do expect { expect(Object.new).not_to have_key(:a) }.to fail_including('to respond to `has_key?`') end it "reraises an exception thrown in #has_sym?(*args)" do o = Object.new def o.has_sym?(*_args) raise "Funky exception" end expect { expect(o).not_to have_sym(:foo) }.to raise_error("Funky exception") end it 'does not include any args in the failure message if no args were given to the matcher' do o = Object.new def o.has_some_stuff?; true; end expect { expect(o).not_to have_some_stuff }.to fail_with("expected `#{o.inspect}.has_some_stuff?` to return false, got true") end it 'includes multiple args in the failure message if multiple args were given to the matcher' do o = Object.new def o.has_some_stuff?(*_); true; end expect { expect(o).not_to have_some_stuff(:a, 7, "foo") }.to fail_with(%Q{expected `#{o.inspect}.has_some_stuff?(:a, 7, "foo")` to return false, got true}) end end RSpec.describe "has" do it "works when the target implements #send" do o = { :a => "A" } def o.send(*_args); raise "DOH! Library developers shouldn't use #send!" end expect { expect(o).to have_key(:a) }.not_to raise_error end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/have_attributes_spec.rb000066400000000000000000000206121455770000100276270ustar00rootroot00000000000000RSpec.describe "#have_attributes matcher" do include RSpec::Support::Spec::DiffHelpers Person = Struct.new(:name, :age) class Person def parent(parent_name) @parent = parent_name end end # This simulates a behaviour of Rails, see #1162. class DynamicAttributes def initialize(attributes) @attributes = attributes end def method_missing(name, *args, &block) @attributes[name] || super end def respond_to?(method_name) @attributes.keys.include?(method_name) || super end end let(:wrong_name) { "Wrong Name" } let(:wrong_age) { 11 } let(:correct_name) { "Correct name" } let(:correct_age) { 33 } let(:person) { Person.new(correct_name, correct_age) } it "is diffable" do expect(have_attributes(:age => correct_age)).to be_diffable end describe "expect(...).to have_attributes(with_one_attribute)" do it_behaves_like "an RSpec value matcher", :valid_value => Person.new("Correct name", 33), :invalid_value => Person.new("Wrong Name", 11) do let(:matcher) { have_attributes(:name => "Correct name") } end it "passes if target has the provided attributes" do expect(person).to have_attributes(:name => correct_name) end it "passes if target responds to :sym but does not implement method" do expect(DynamicAttributes.new(:name => "value")).to have_attributes(:name => "value") end it "fails if target does not have any of the expected attributes" do expect { expect(person).to have_attributes(:name => wrong_name) }.to fail_with(%r|expected #{object_inspect person} to have attributes #{hash_inspect :name => wrong_name} but had attributes #{hash_inspect :name => correct_name }|) end it "fails with correct message if object manipulates its data" do counter = Class.new do def initialize; @count = 1; end def count @count += 1 end end.new expect { expect(counter).to have_attributes(:count => 1) }.to fail_with(%r|to have attributes #{hash_inspect :count => 1} but had attributes #{hash_inspect :count => 2 }|) end it 'diffs the attributes received with those expected' do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) expected_diff = dedent(<<-EOS) |@@ #{one_line_header} @@ |-:name => "Wrong Name", |+:name => "Correct name", EOS expect { expect(person).to have_attributes(:name => wrong_name) }.to fail_including(expected_diff) end it "fails if target does not responds to any of the attributes" do expect { expect(person).to have_attributes(:color => 'red') }.to fail_including("expected #{object_inspect person} to respond to :color") end it "doesn't produce a diff if the target fails the respond to check" do expect { expect(person).to have_attributes(:color => 'red') }.to fail_with(a_string_excluding "Diff") end it "fails if target responds to the attribute but requires arguments" do expect { expect(person).to have_attributes(:parent => 'Billy') }.to fail_including("expected #{object_inspect person} to respond to :parent with 0 arguments") end describe "expect(...).to have_attributes(key => matcher)" do it "passes when the matchers match" do expect(person).to have_attributes(:age => (a_value > 30)) end it 'provides a description' do description = have_attributes(:age => (a_value > 30)).description expect(description).to eq("have attributes {:age => (a value > 30)}") end it "fails with a clear message when the matcher does not match" do expect { expect(person).to have_attributes(:age => (a_value < 10)) }.to fail_including("expected #{object_inspect person} to have attributes {:age => (a value < 10)}") end end end describe "expect(...).to_not have_attributes(with_one_attribute)" do it "passes if target does not have any of the expected attributes" do expect(person).to_not have_attributes(:age => wrong_age) end it "fails if target has all of the expected attributes" do expect { expect(person).to_not have_attributes(:age => correct_age) }.to fail_with(%r|expected #{object_inspect person} not to have attributes #{hash_inspect :age => correct_age}|) end it "doesn't produce a diff" do expect { expect(person).to_not have_attributes(:age => correct_age) }.to fail_with(a_string_excluding "Diff") end it "fails if target does not responds to any of the attributes" do expect { expect(person).to_not have_attributes(:color => 'red') }.to fail_including("expected #{object_inspect person} to respond to :color") end it "fails if target responds to the attribute but requires arguments" do expect { expect(person).to_not have_attributes(:parent => 'Billy') }.to fail_including("expected #{object_inspect person} to respond to :parent with 0 arguments") end end describe "expect(...).to have_attributes(with_multiple_attributes)" do it_behaves_like "an RSpec value matcher", :valid_value => Person.new("Correct name", 33), :invalid_value => Person.new("Wrong Name", 11) do let(:matcher) { have_attributes(:name => "Correct name", :age => 33) } end it "passes if target has the provided attributes" do expect(person).to have_attributes(:name => correct_name, :age => correct_age) end it "fails if target does not have any of the expected attributes" do expect { expect(person).to have_attributes(:name => correct_name, :age => wrong_age) }.to fail_with(%r|expected #{object_inspect person} to have attributes #{hash_inspect :age => wrong_age, :name => correct_name }|) end it 'diffs the attributes received with those expected' do allow(RSpec::Matchers.configuration).to receive_messages(:color? => false) expected_diff = dedent(<<-EOS) |@@ #{one_line_header(3)} @@ |-:age => 11, |+:age => 33, EOS expected_diff << "\n :name => \"Correct name\",\n" if Diff::LCS::VERSION.to_f < 1.4 expect { expect(person).to have_attributes(:name => correct_name, :age => wrong_age) }.to fail_including(expected_diff) end it "fails if target does not responds to any of the attributes" do expect { expect(person).to have_attributes(:name => correct_name, :color => 'red') }.to fail_including("expected #{object_inspect person} to respond to :color") end it "fails if target responds to the attribute but requires arguments" do expect { expect(person).to have_attributes(:name => correct_name, :parent => 'Billy') }.to fail_including("expected #{object_inspect person} to respond to :parent with 0 arguments") end end describe "expect(...).to_not have_attributes(with_multiple_attributes)" do it "passes if target has none of the expected attributes" do expect(person).to_not have_attributes(:name => wrong_name, :age => wrong_age) end it "fails if target has any of the expected attributes" do expect { expect(person).to_not have_attributes(:name => wrong_name, :age => correct_age) }.to fail_with(%r|expected #{object_inspect person} not to have attributes #{hash_inspect :age => correct_age, :name => wrong_name }|) end it "fails if target has all of the expected attributes" do expect { expect(person).to_not have_attributes(:name => correct_name, :age => correct_age) }.to fail_with(%r|expected #{object_inspect person} not to have attributes #{hash_inspect :age => correct_age, :name => correct_name }|) end it "fails if target does not responds to any of the attributes" do expect { expect(person).to_not have_attributes(:name => correct_name, :color => 'red') }.to fail_including("expected #{object_inspect person} to respond to :color") end it "fails if target responds to the attribute but requires arguments" do expect { expect(person).to_not have_attributes(:name => correct_name, :parent => 'Billy') }.to fail_including("expected #{object_inspect person} to respond to :parent with 0 arguments") end end include RSpec::Matchers::Composable # a helper for failure message assertion def object_inspect(object) surface_descriptions_in object.inspect end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/include_spec.rb000066400000000000000000001130561455770000100260660ustar00rootroot00000000000000# This class fakes some behavior of # ActiveSupport::HashWithIndifferentAccess. # It doesn't convert recursively. class FakeHashWithIndifferentAccess < Hash class << self def from_hash(hsh) new_hsh = new hsh.each do |key, value| new_hsh[key] = value end new_hsh end end def [](key) super(key.to_s) end def []=(key, value) super(key.to_s, value) end def key?(key) super(key.to_s) end def to_hash new_hsh = ::Hash.new each do |key, value| new_hsh[key] = value end new_hsh end end # Some custom hashes don't support fuzzy matching class CaseInsensitiveHash < Hash class << self def from_hash(hsh) new_hsh = new hsh.each do |key, value| new_hsh[key] = value end new_hsh end end def include?(key) super(key.downcase) end alias :key? :include? end RSpec.describe "#include matcher" do include RSpec::Support::Spec::DiffHelpers it "is diffable" do expect(include("a")).to be_diffable end shared_examples_for "a Hash target" do def build_target(hsh) hsh end def use_string_keys_in_failure_message? false end def convert_key(key) use_string_keys_in_failure_message? ? "\"#{key}\"" : ":#{key}" end it 'passes if target has the expected as a key' do expect(build_target(:key => 'value')).to include(:key) end it 'passes if target has the expected as a key fuzzily matched' do expect(build_target('KEY' => 'value')).to include(match(/key/i)) end it "fails if target does not include expected" do failure_string = %(expected {#{convert_key(:key)} => "value"} to include :other) expect { expect(build_target(:key => 'value')).to include(:other) }.to fail_matching(failure_string) end it "fails if target doesn't have a key and we expect nil" do expect { expect(build_target({})).to include(:something => nil) }.to fail_matching("expected {} to include {:something => nil}") end it 'works even when an entry in the hash overrides #send' do hash = build_target(:key => 'value') def hash.send; :sent; end expect(hash).to include(hash) end it 'provides a valid diff' do allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false) failure_string = if use_string_keys_in_failure_message? dedent(<<-END) |Diff: |@@ -1,3 +1,3 @@ |-:bar => 3, |-:foo => 1, |+"bar" => 2, |+"foo" => 1, END else diff = dedent(<<-END) |Diff: |@@ #{one_line_header(3)} @@ |-:bar => 3, |+:bar => 2, END diff << "\n :foo => 1,\n" if Diff::LCS::VERSION.to_f < 1.4 diff end expect { expect(build_target(:foo => 1, :bar => 2)).to include(:foo => 1, :bar => 3) }.to fail_including(failure_string) end it 'provides a valid diff for fuzzy matchers' do allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false) failure_string = if use_string_keys_in_failure_message? dedent(<<-END) |Diff: |@@ -1,3 +1,3 @@ |-(match /FOO/i) => 1, |-:bar => 3, |+"bar" => 2, |+"foo" => 1, END else dedent(<<-END) |Diff: |@@ -1,3 +1,3 @@ |-(match /FOO/i) => 1, |-:bar => 3, |+:bar => 2, |+:foo => 1, END end expect { expect(build_target(:foo => 1, :bar => 2)).to include(match(/FOO/i) => 1, :bar => 3) }.to fail_including(failure_string) end it 'does not support count constraint' do expect { expect(build_target(:key => 'value')).to include(:other).once }.to raise_error(NotImplementedError) end end describe "expect(...).to include(with_one_arg)" do it_behaves_like "an RSpec value matcher", :valid_value => [1, 2], :invalid_value => [1] do let(:matcher) { include(2) } end context "for an object that does not respond to `include?`" do it 'fails gracefully' do expect { expect(5).to include(1) }.to fail_matching("expected 5 to include 1, but it does not respond to `include?`") expect { expect(5).to include(1).once }.to fail_matching("expected 5 to include 1 once, but it does not respond to `include?`") end end context "for an arbitrary object that responds to `include?`" do it 'delegates to `include?`' do container = double("Container") allow(container).to receive(:include?) { |arg| arg == :stuff } expect(container).to include(:stuff) expect { expect(container).to include(:space) }.to fail_matching("to include :space") end end context "for an arbitrary object that responds to `include?` and `to_hash`" do it "delegates to `include?`" do container = double("Container", :include? => true, :to_hash => { "foo" => "bar" }) expect(container).to receive(:include?).with("foo").and_return(true) expect(container).to include("foo") end end context "for a string target" do it "passes if target includes expected" do expect("abc").to include("a") end it "fails if target does not include expected" do expect { expect("abc").to include("d") }.to fail_matching("expected \"abc\" to include \"d\"") end it "includes a diff when actual is multiline" do expect { expect("abc\ndef").to include("g") }.to fail_matching("expected \"abc\\ndef\" to include \"g\"\nDiff") end it "includes a diff when actual is multiline and there are multiple expecteds" do expect { expect("abc\ndef").to include("g", "h") }.to fail_matching("expected \"abc\\ndef\" to include \"g\" and \"h\"\nDiff") end it "does not diff when lines match but are not an exact match" do expect { expect(" foo\nbar\nbazz").to include("foo", "bar", "gaz") }.to fail_with(a_string_not_matching(/Diff/i)) end context "with exact count" do it 'fails if the block yields wrong number of times' do expect { expect('foo bar foo').to include('foo').once }.to fail_with(/expected "foo bar foo" to include "foo" once but it is included twice/) end it 'passes if the block yields the specified number of times' do expect('fooo bar').to include('oo').once expect('fooo bar').to include('o').thrice expect('fooo ooo oo bar foo').to include('oo').exactly(4).times end end context "with at_least count" do it 'passes if the search term is included at least the number of times' do expect('foo bar foo').to include('foo').at_least(2).times expect('foo bar foo foo').to include('foo').at_least(:twice) end it 'fails if the search term is included too few times' do expect { expect('foo bar foo').to include('foo').at_least(:thrice) }.to fail_with(/expected "foo bar foo" to include "foo" at least 3 times but it is included twice/) end end context "with at_most count" do it 'passes if the search term is included at most the number of times' do expect('foo bar foo').to include('foo').at_most(2).times expect('foo bar').to include('foo').at_most(:twice) end it 'fails if the search term is included too many times' do expect { expect('foo bar foo foo').to include('foo').at_most(:twice) }.to fail_with(/expected "foo bar foo foo" to include "foo" at most twice but it is included 3 times/) end end end context "for an array target" do it "passes if target includes expected" do expect([1, 2, 3]).to include(3) end it "passes if target includes expected fuzzily matched" do expect(["A", "B", "C"]).to include(match(/a/i)) end it "fails if target does not include expected" do expect { expect([1, 2, 3]).to include(4) }.to fail_matching("expected [1, 2, 3] to include 4") end it 'fails when given differing null doubles' do dbl_1 = double.as_null_object dbl_2 = double.as_null_object expect { expect([dbl_1]).to include(dbl_2) }.to fail_matching("expected [#{dbl_1.inspect}] to include") end it 'passes when given the same null double' do dbl = double.as_null_object expect([dbl]).to include(dbl) end context "with exact count" do it 'fails if the block yields wrong number of times' do expect { expect([1, 2, 1]).to include(1).once }.to fail_with('expected [1, 2, 1] to include 1 once but it is included twice') expect { expect([10, 20, 30]).to include(a_value_within(2).of(17)).twice }.to fail_with('expected [10, 20, 30] to include (a value within 2 of 17) twice but it is included 0 times') end it 'passes if the block yields the specified number of times' do expect([1, 2, 1]).to include(1).twice expect([10, 20, 30]).to include(a_value_within(5).of(17)).once expect([{ 'a' => 1 }]).to include('a' => 1).once end end context "with at_least count" do it 'passes if the search term is included at least the number of times' do expect([1, 2, 1]).to include(1).at_least(2).times expect([1, 2, 1, 1]).to include(1).at_least(:twice) end it 'fails if the search term is included too few times' do expect { expect([1, 2, 1]).to include(1).at_least(:thrice) }.to fail_with('expected [1, 2, 1] to include 1 at least 3 times but it is included twice') end end context "with at_most count" do it 'passes if the search term is included at most the number of times' do expect([1, 2, 1]).to include(1).at_most(2).times expect([1, 2]).to include(1).at_most(:twice) end it 'fails if the search term is included too many times' do expect { expect([1, 2, 1, 1]).to include(1).at_most(:twice) }.to fail_with('expected [1, 2, 1, 1] to include 1 at most twice but it is included 3 times') end end end context "for a hash target" do it_behaves_like "a Hash target" end context "for a target that subclasses Hash to treat string/symbol keys interchangeably, but returns a raw hash from #to_hash" do it_behaves_like "a Hash target" do undef :build_target # to prevent "method redefined" warning def build_target(hsh) FakeHashWithIndifferentAccess.from_hash(hsh) end undef :use_string_keys_in_failure_message? # to prevent "method redefined" warning def use_string_keys_in_failure_message? true end end end context "for a target that subclasses Hash to perform custom key checks like downcasing" do it_behaves_like "a Hash target" do undef :build_target # to prevent "method redefined" warning def build_target(hsh) CaseInsensitiveHash.from_hash(hsh) end end end context "for a target that can pass for a hash" do def build_target(hsh) PseudoHash.new(hsh) end around do |example| in_sub_process_if_possible do require 'delegate' class PseudoHash < SimpleDelegator end example.run end end it_behaves_like "a Hash target" end end describe "expect(...).to include(with, multiple, args)" do it "has a description" do matcher = include("a") expect(matcher.description).to eq("include \"a\"") end context "for a string target" do it "passes if target includes all items" do expect("a string").to include("str", "a") end it "fails if target does not include one of the items" do expect { expect("a string").to include("str", "a", "foo") }.to fail_matching('expected "a string" to include "foo"') end it "fails if target does not include two of the items" do expect { expect("a string").to include("nope", "a", "nada", "str") }.to fail_matching('expected "a string" to include "nope" and "nada"') end it "fails if target does not include many of the items" do expect { expect("a string").to include("nope", "a", "nada", "nein", "ing", "str") }.to fail_matching('expected "a string" to include "nope", "nada", and "nein"') end end context "for an array target" do it "passes if target includes all items" do expect([1, 2, 3]).to include(1, 2, 3) end it "passes if target includes all items fuzzily matched" do expect(["A", "B", "C"]).to include(match(/b/i), "A") end it "fails if target does not include one of the items" do expect { expect([1, 2, 3]).to include(1, 2, 4) }.to fail_matching("expected [1, 2, 3] to include 4") end it "fails if target does not include two of the items" do expect { expect([1, 2, 3]).to include(5, 1, 2, 4) }.to fail_matching("expected [1, 2, 3] to include 5 and 4") end it "fails if target does not include many of the items" do expect { expect([1, 2, 3]).to include(5, 1, 6, 2, 4) }.to fail_matching("expected [1, 2, 3] to include 5, 6, and 4") end it 'correctly diffs lists of hashes' do allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false) expect { expect([ { :number => 1 }, { :number => 2 }, { :number => 3 } ]).to include( { :number => 1 }, { :number => 0 }, { :number => 3 } ) }.to fail_including(dedent(<<-END)) |Diff: |@@ #{one_line_header} @@ |-[{:number=>1}, {:number=>0}, {:number=>3}] |+[{:number=>1}, {:number=>2}, {:number=>3}] END end end context "for a hash target" do it 'passes if target includes all items as keys' do expect({ :key => 'value', :other => 'value' }).to include(:key, :other) end it "passes if target includes all items as keys fuzzily matched" do expect({ "A" => "B", "C" => "D" }).to include(match(/c/i), "A") end it 'fails if target does not include one of the items as a key' do expect { expect({ :key => 'value', :this => 'that' }).to include(:key, :nope, :this) }.to fail_with(%r|expected #{hash_inspect :key => "value", :this => "that"} to include :nope|) end it "fails if target does not include two of the items as keys" do expect { expect({ :key => 'value', :this => 'that' }).to include(:nada, :key, :nope, :this) }.to fail_with(%r|expected #{hash_inspect :key => "value", :this => "that"} to include :nada and :nope|) end it "fails if target does not include many of the items as keys" do expect { expect({ :key => 'value', :this => 'that' }).to include(:nada, :key, :nope, :negative, :this) }.to fail_with(%r|expected #{hash_inspect :key => "value", :this => "that"} to include :nada, :nope, and :negative|) end end it 'does not implement count constraints' do expect { expect('').to include('foo', 'bar').once }.to raise_error(NotImplementedError) expect { expect('').to include('foo', 'bar').at_least(:twice) }.to raise_error(NotImplementedError) expect { expect('').to include('foo', 'bar').at_most(:twice) }.to raise_error(NotImplementedError) end end describe "expect(...).not_to include(expected)" do context "for an object that does not respond to `include?`" do it 'fails gracefully' do expect { expect(5).not_to include(1) }.to fail_matching("expected 5 not to include 1, but it does not respond to `include?`") end end context "for an arbitrary object that responds to `include?`" do it 'delegates to `include?`' do container = double("Container") allow(container).to receive(:include?) { |arg| arg == :stuff } expect(container).not_to include(:space) expect { expect(container).not_to include(:stuff) }.to fail_matching("not to include :stuff") end end context "for a string target" do it "passes if target does not include expected" do expect("abc").not_to include("d") end it "fails if target includes expected" do expect { expect("abc").not_to include("c") }.to fail_with("expected \"abc\" not to include \"c\"") end context "with exact count" do it 'passes if the block yields wrong number of times' do expect('foo bar foo').not_to include('foo').once end it 'fails if the block yields the specified number of times' do expect { expect('fooo bar').not_to include('oo').once }.to fail_with(/expected "fooo bar" not to include "oo" once but it is included once/) end end context "with at_least count" do it 'fails if the search term is included at least the number of times' do expect { expect('foo bar foo foo').not_to include('foo').at_least(:twice) }.to fail_with(/expected "foo bar foo foo" not to include "foo" at least twice but it is included 3 times/) end it 'passes if the search term is included too few times' do expect('foo bar foo').not_to include('foo').at_least(:thrice) end end context "with at_most count" do it 'fails if the search term is included at most the number of times' do expect { expect('foo bar').not_to include('foo').at_most(:twice) }.to fail_with(/expected "foo bar" not to include "foo" at most twice but it is included once/) end it 'passes if the search term is included too many times' do expect('foo bar foo foo').not_to include('foo').at_most(:twice) end end end context "for an array target" do it "passes if target does not include expected" do expect([1, 2, 3]).not_to include(4) end it "fails if target includes expected" do expect { expect([1, 2, 3]).not_to include(3) }.to fail_with("expected [1, 2, 3] not to include 3") end it 'passes when given differing null doubles' do expect([double.as_null_object]).not_to include(double.as_null_object) end it 'fails when given the same null double' do dbl = double.as_null_object expect { expect([dbl]).not_to include(dbl) }.to fail_matching("expected [#{dbl.inspect}] not to include") end end context "for a hash target" do it 'passes if target does not have the expected as a key' do expect({ :other => 'value' }).not_to include(:key) end it "fails if target includes expected key" do expect { expect({ :key => 'value' }).not_to include(:key) }.to fail_matching('expected {:key => "value"} not to include :key') end end end describe "expect(...).not_to include(with, multiple, args)" do context "for a string target" do it "passes if the target does not include any of the expected" do expect("abc").not_to include("d", "e", "f") end it "fails if the target includes all of the expected" do expect { expect("abc").not_to include("c", "a") }.to fail_with('expected "abc" not to include "c" and "a"') end it "fails if the target includes one (but not all) of the expected" do expect { expect("abc").not_to include("d", "a") }.to fail_with('expected "abc" not to include "a"') end it "fails if the target includes two (but not all) of the expected" do expect { expect("abc").not_to include("d", "a", "b") }.to fail_with('expected "abc" not to include "a" and "b"') end it "fails if the target includes many (but not all) of the expected" do expect { expect("abcd").not_to include("b", "d", "a", "f") }.to fail_with('expected "abcd" not to include "b", "d", and "a"') end end context "for a hash target" do it "passes if it does not include any of the expected keys" do expect({ :a => 1, :b => 2 }).not_to include(:c, :d) end it "fails if the target includes all of the expected keys" do expect { expect({ :a => 1, :b => 2 }).not_to include(:a, :b) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} not to include :a and :b|) end it "fails if the target includes one (but not all) of the expected keys" do expect { expect({ :a => 1, :b => 2 }).not_to include(:d, :b) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} not to include :b|) end it "fails if the target includes two (but not all) of the expected keys" do expect { expect({ :a => 1, :b => 2 }).not_to include(:a, :b, :c) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} not to include :a and :b|) end it "fails if the target includes many (but not all) of the expected keys" do expect { expect({ :a => 1, :b => 2, :c => 3 }).not_to include(:b, :a, :c, :f) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2, :c => 3} not to include :b, :a, and :c|) end end context "for an array target" do it "passes if the target does not include any of the expected" do expect([1, 2, 3]).not_to include(4, 5, 6) end it "fails if the target includes all of the expected" do expect { expect([1, 2, 3]).not_to include(3, 1) }.to fail_with('expected [1, 2, 3] not to include 3 and 1') end it "fails if the target includes one (but not all) of the expected" do expect { expect([1, 2, 3]).not_to include(4, 1) }.to fail_with('expected [1, 2, 3] not to include 1') end it "fails if the target includes two (but not all) of the expected" do expect { expect([1, 2, 3]).not_to include(4, 1, 2) }.to fail_with('expected [1, 2, 3] not to include 1 and 2') end it "fails if the target includes many (but not all) of the expected" do expect { expect([1, 2, 3]).not_to include(5, 4, 2, 1, 3) }.to fail_with('expected [1, 2, 3] not to include 2, 1, and 3') end end end describe "expect(...).to include(:key => value)" do context 'for a hash target' do it "passes if target includes the key/value pair" do expect({ :key => 'value' }).to include(:key => 'value') end it "passes if target includes the key/value pair among others" do expect({ :key => 'value', :other => 'different' }).to include(:key => 'value') end it "passes if target includes the key/value pair fuzzily matched among others", :if => (RUBY_VERSION.to_f > 1.8) do hsh = { :key => 'value', :other => 'different' } expect(hsh).to include(match(/KEY/i) => 'value') expect(FakeHashWithIndifferentAccess.from_hash(hsh)).to include(match(/KEY/i) => 'value') expect(CaseInsensitiveHash.from_hash(hsh)).to include(match(/KEY/i) => 'value') end it "fails if target has a different value for key" do expect { expect({ :key => 'different' }).to include(:key => 'value') }.to fail_matching('expected {:key => "different"} to include {:key => "value"}') end it "fails if target has a different key" do expect { expect({ :other => 'value' }).to include(:key => 'value') }.to fail_matching('expected {:other => "value"} to include {:key => "value"}') end end context 'for a non-hash target' do it "fails if the target does not contain the given hash" do expect { expect(['a', 'b']).to include(:key => 'value') }.to fail_matching('expected ["a", "b"] to include {:key => "value"}') end it "passes if the target contains the given hash" do expect(['a', { :key => 'value' }]).to include(:key => 'value') end end end describe "expect(...).not_to include(:key => value)" do context 'for a hash target' do it "fails if target includes the key/value pair" do expect { expect({ :key => 'value' }).not_to include(:key => 'value') }.to fail_matching('expected {:key => "value"} not to include {:key => "value"}') end it "fails if target includes the key/value pair among others" do expect { expect({ :key => 'value', :other => 'different' }).not_to include(:key => 'value') }.to fail_with(%r|expected #{hash_inspect :key => "value", :other => "different"} not to include \{:key => "value"\}|) end it "passes if target has a different value for key" do expect({ :key => 'different' }).not_to include(:key => 'value') end it "passes if target has a different key" do expect({ :other => 'value' }).not_to include(:key => 'value') end end context "for a non-hash target" do it "passes if the target does not contain the given hash" do expect(['a', 'b']).not_to include(:key => 'value') end it "fails if the target contains the given hash" do expect { expect(['a', { :key => 'value' }]).not_to include(:key => 'value') }.to fail_matching('expected ["a", {:key => "value"}] not to include {:key => "value"}') end end end describe "expect(...).to include(:key1 => value1, :key2 => value2)" do context 'for a hash target' do it "passes if target includes the key/value pairs" do expect({ :a => 1, :b => 2 }).to include(:b => 2, :a => 1) end it "passes if target includes the key/value pairs among others" do expect({ :a => 1, :c => 3, :b => 2 }).to include(:b => 2, :a => 1) end it "fails if target has a different value for one of the keys" do expect { expect({ :a => 1, :b => 2 }).to include(:a => 2, :b => 2) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} to include #{hash_inspect :a => 2}|) end it "fails if target has a different value for both of the keys" do expect { expect({ :a => 1, :b => 1 }).to include(:a => 2, :b => 2) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :a => 2, :b => 2}|) end it "fails if target lacks one of the keys" do expect { expect({ :a => 1, :b => 1 }).to include(:a => 1, :c => 1) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :c => 1}|) end it "fails if target lacks both of the keys" do expect { expect({ :a => 1, :b => 1 }).to include(:c => 1, :d => 1) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :c => 1, :d => 1}|) end it "fails if target lacks one of the keys and has a different value for another" do expect { expect({ :a => 1, :b => 2 }).to include(:c => 1, :b => 3) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} to include #{hash_inspect :c => 1, :b => 3}|) end end context 'for a non-hash target' do it "fails if the target does not contain the given hash" do expect { expect(['a', 'b']).to include(:a => 1, :b => 1) }.to fail_with(%r|expected \["a", "b"\] to include #{hash_inspect :a => 1, :b => 1}|) end it "passes if the target contains the given hash" do expect(['a', { :a => 1, :b => 2 }]).to include(:a => 1, :b => 2) end end end describe "expect(...).not_to include(:key1 => value1, :key2 => value2)" do context 'for a hash target' do it "fails if target includes the key/value pairs" do expect { expect({ :a => 1, :b => 2 }).not_to include(:a => 1, :b => 2) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} not to include #{hash_inspect :a => 1, :b => 2}|) end it "fails if target includes the key/value pairs among others" do hash = { :a => 1, :b => 2, :c => 3 } expect { expect(hash).not_to include(:a => 1, :b => 2) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2, :c => 3} not to include #{hash_inspect :a => 1, :b => 2}|) end it "fails if target has a different value for one of the keys" do expect { expect({ :a => 1, :b => 2 }).not_to include(:a => 2, :b => 2) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 2} not to include #{hash_inspect :b => 2}|) end it "passes if target has a different value for both of the keys" do expect({ :a => 1, :b => 1 }).not_to include(:a => 2, :b => 2) end it "fails if target lacks one of the keys" do expect { expect({ :a => 1, :b => 1 }).not_to include(:a => 1, :c => 1) }.to fail_with(%r|expected #{hash_inspect :a => 1, :b => 1} not to include #{hash_inspect :a => 1}|) end it "passes if target lacks both of the keys" do expect({ :a => 1, :b => 1 }).not_to include(:c => 1, :d => 1) end end context 'for a non-hash target' do it "passes if the target does not contain the given hash" do expect(['a', 'b']).not_to include(:a => 1, :b => 1) end it "fails if the target contains the given hash" do expect { expect(['a', { :a => 1, :b => 2 }]).not_to include(:a => 1, :b => 2) }.to fail_with(%r|expected \["a", #{hash_inspect :a => 1, :b => 2}\] not to include #{hash_inspect :a => 1, :b => 2}|) end end end describe "Composing matchers with `include`" do RSpec::Matchers.define :a_string_containing do |expected| match do |actual| actual.include?(expected) end description do "a string containing '#{expected}'" end end describe "expect(array).to include(matcher)" do it "passes when the matcher matches one of the values" do expect([10, 20, 30]).to include( a_value_within(5).of(24) ) end it 'provides a description' do description = include( a_value_within(5).of(24) ).description expect(description).to eq("include (a value within 5 of 24)") end it 'fails with a clear message when the matcher matches none of the values' do expect { expect([10, 30]).to include( a_value_within(5).of(24) ) }.to fail_with("expected [10, 30] to include (a value within 5 of 24)") end it 'works with comparison matchers' do expect { expect([100, 200]).to include(a_value < 90) }.to fail_with("expected [100, 200] to include (a value < 90)") expect([100, 200]).to include(a_value > 150) end it 'does not treat an object that only implements #matches? as a matcher' do not_a_matcher = Struct.new(:value) do def matches?(_) fail "`matches?` should never be called" end end expect([not_a_matcher.new("rspec.info")]).to include(not_a_matcher.new("rspec.info")) expect { expect([not_a_matcher.new("rspec.info")]).to include(not_a_matcher.new("foo.com")) }.to fail_matching("expected [#{not_a_matcher.new("rspec.info").inspect}] to include") end end describe "expect(array).to include(multiple, matcher, arguments)" do it "passes if target includes items satisfying all matchers" do expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing('oo')) end it "fails if target does not include an item satisfying any one of the items" do expect { expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing("abc")) }.to fail_matching("expected #{['foo', 'bar', 'baz'].inspect} to include (a string containing 'abc')") end end describe "expect(hash).to include(key => matcher)" do it "passes when the matcher matches" do expect(:a => 12).to include(:a => a_value_within(3).of(10)) end it 'provides a description' do description = include(:a => a_value_within(3).of(10)).description expect(description).to eq("include {:a => (a value within 3 of 10)}") end it "fails with a clear message when the matcher does not match" do expect { expect(:a => 15).to include(:a => a_value_within(3).of(10)) }.to fail_matching("expected {:a => 15} to include {:a => (a value within 3 of 10)}") end end describe "expect(hash).to include(key_matcher)" do it "passes when the matcher matches a key", :if => (RUBY_VERSION.to_f > 1.8) do expect(:drink => "water", :food => "bread").to include(match(/foo/)) end it 'provides a description' do description = include(match(/foo/)).description expect(description).to eq("include (match /foo/)") end it 'fails with a clear message when the matcher does not match', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect(:drink => "water", :food => "bread").to include(match(/bar/)) }.to fail_matching('expected {:drink => "water", :food => "bread"} to include (match /bar/)') end end describe "expect(hash).to include(key_matcher => value)" do it "passes when the matcher matches a pair", :if => (RUBY_VERSION.to_f > 1.8) do expect(:drink => "water", :food => "bread").to include(match(/foo/) => "bread") end it "passes when the matcher matches all pairs", :if => (RUBY_VERSION.to_f > 1.8) do expect(:drink => "water", :food => "bread").to include(match(/foo/) => "bread", match(/ink/) => "water") end it "passes with a natural matcher", :if => (RUBY_VERSION.to_f > 1.8) do expect(:drink => "water", :food => "bread").to include(/foo/ => "bread") end it "passes with a natural matcher", :if => (RUBY_VERSION.to_f > 1.8) do expect(:drink => "water", :food => "bread").to include(/foo/ => /read/) end it 'provides a description' do description = include(match(/foo/) => "bread").description expect(description).to eq('include {(match /foo/) => "bread"}') end it 'fails with a clear message when the value does not match', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect(:drink => "water", :food => "bread").to include(match(/foo/) => "meat") }.to fail_matching('expected {:drink => "water", :food => "bread"} to include {(match /foo/) => "meat"}') end it 'fails with a clear message when the matcher does not match', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect(:drink => "water", :food => "bread").to include(match(/bar/) => "bread") }.to fail_matching('expected {:drink => "water", :food => "bread"} to include {(match /bar/) => "bread"}') end it 'fails with a clear message when several matchers do not match', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect(:drink => "water", :food => "bread").to include(match(/bar/) => "bread", match(/baz/) => "water") }.to fail_matching('expected {:drink => "water", :food => "bread"} to include {(match /bar/) => "bread", (match /baz/) => "water"}') end end describe "expect(array).not_to include(multiple, matcher, arguments)" do it "passes if none of the target values satisfies any of the matchers" do expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("gh"), a_string_containing('de')) end it 'fails if all of the matchers are satisfied by one of the target values' do expect { expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('az')) }.to fail_matching("expected #{['foo', 'bar', 'baz'].inspect} not to include (a string containing 'ar') and (a string containing 'az')") end it 'fails if the some (but not all) of the matchers are satisfied' do expect { expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('bz')) }.to fail_matching("expected #{['foo', 'bar', 'baz'].inspect} not to include (a string containing 'ar')") end end end # `fail_including` uses the `include` matcher internally, and using a matcher # to test itself is potentially problematic, so just for this spec file we # use `fail_matching` instead, which converts to a regex instead. def fail_matching(message) raise_error(RSpec::Expectations::ExpectationNotMetError, /#{Regexp.escape(message)}/) end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/match_spec.rb000066400000000000000000000110451455770000100255320ustar00rootroot00000000000000RSpec.describe "expect(...).to match(expected)" do include RSpec::Support::Spec::DiffHelpers it_behaves_like "an RSpec value matcher", :valid_value => 'ab', :invalid_value => 'bc' do let(:matcher) { match(/a/) } end it "passes when target (String) matches expected (Regexp)" do expect("string").to match(/tri/) end it "passes when target (Regexp) matches expected (String)" do expect(/tri/).to match("string") end it "passes when target (Regexp) matches expected (Regexp)" do expect(/tri/).to match(/tri/) end it "passes when target (String) matches expected (a matcher)" do expect("string").to match(a_string_including("str")) end it "passes when target (Regexp) matches expected (a matcher)" do expect(/foo/).to match(be_a Regexp) end it "passes when target (String) matches expected (String)" do expect("string").to match("tri") end it "fails when target (String) does not match expected (Regexp)" do expect { expect("string").to match(/rings/) }.to fail_with a_string_starting_with 'expected "string" to match /rings/' end it "fails when target (Regexp) does not match expected (String)" do expect { expect(/rings/).to match("string") }.to fail_with a_string_starting_with 'expected /rings/ to match "string"' end it "fails when target (String) does not match expected (a matcher)" do expect { expect("string").to match(a_string_including("foo")) }.to fail_with(a_string_starting_with 'expected "string" to match (a string including "foo")') end it "fails when target (Regexp) does not match expected (a matcher)" do expect { expect(/foo/).to match(be_a_kind_of String) }.to fail_with(a_string_starting_with 'expected /foo/ to match (be a kind of String)') end it "fails when target (String) does not match expected (String)" do expect { expect("string").to match("rings") }.to fail end it "provides message, expected and actual on failure" do matcher = match(/rings/) matcher.matches?("string") expect(matcher.failure_message).to eq "expected \"string\" to match /rings/" end it "provides a diff on failure" do allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false) failure_message_that_includes_diff = %r| \s*Diff: \s*@@ #{Regexp.escape one_line_header} @@ \s*-/bar/ \s*\+"foo"| expect { expect("foo").to match(/bar/) }.to fail_with(failure_message_that_includes_diff) end context "when passed a data structure with matchers" do it 'passes when the matchers match' do expect(["food", 1.1]).to match([a_string_matching(/foo/), a_value_within(0.2).of(1)]) end it 'fails when the matchers do not match' do expect { expect(["fod", 1.1]).to match([a_string_matching(/foo/), a_value_within(0.2).of(1)]) }.to fail_with('expected ["fod", 1.1] to match [(a string matching /foo/), (a value within 0.2 of 1)]') end it 'provides a description' do description = match([a_string_matching(/foo/), a_value_within(0.2).of(1)]).description expect(description).to eq("match [(a string matching /foo/), (a value within 0.2 of 1)]") end end end RSpec.describe "expect(...).not_to match(expected)" do it "passes when target (String) matches does not match (Regexp)" do expect("string").not_to match(/rings/) end it "passes when target (String) matches does not match (String)" do expect("string").not_to match("rings") end it "fails when target (String) matches expected (Regexp)" do expect { expect("string").not_to match(/tri/) }.to fail_with a_string_starting_with 'expected "string" not to match /tri/' end it "fails when target (String) matches expected (String)" do expect { expect("string").not_to match("tri") }.to fail_with a_string_starting_with 'expected "string" not to match "tri"' end it "provides message, expected and actual on failure" do matcher = match(/tri/) matcher.matches?("string") expect(matcher.failure_message_when_negated).to eq "expected \"string\" not to match /tri/" end context "when passed a data structure with matchers" do it 'passes when the matchers match' do expect(["food", 1.1]).not_to match([a_string_matching(/fod/), a_value_within(0.2).of(1)]) end it 'fails when the matchers do not match' do expect { expect(["fod", 1.1]).not_to match([a_string_matching(/fod/), a_value_within(0.2).of(1)]) }.to fail_with('expected ["fod", 1.1] not to match [(a string matching /fod/), (a value within 0.2 of 1)]') end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/operators_spec.rb000066400000000000000000000171241455770000100264600ustar00rootroot00000000000000class MethodOverrideObject def method :foo end end class MethodMissingObject < Struct.new(:original) undef == def method_missing(name, *args, &block) original.__send__ name, *args, &block end end RSpec.describe "operator matchers", :uses_should do describe "should ==" do it "delegates message to target" do subject = "apple".dup expect(subject).to receive(:==).with("apple").and_return(true) subject.should == "apple" end it "returns true on success" do subject = "apple" (subject.should == "apple").should be_truthy end it "fails when target.==(actual) returns false" do subject = "apple" expect(RSpec::Expectations).to receive(:fail_with).with(%{expected: "orange"\n got: "apple" (using ==)}, "orange", "apple") subject.should == "orange" end it "works when #method is overridden" do myobj = MethodOverrideObject.new expect { myobj.should == myobj }.to_not raise_error end it "works when implemented via method_missing" do obj = Object.new myobj = MethodMissingObject.new(obj) (myobj.should == obj).nil? # just to avoid `useless use of == in void context` warning myobj.should_not == Object.new end end describe "unsupported operators", :if => RUBY_VERSION.to_f == 1.9 do it "raises an appropriate error for should != expected" do expect { "apple".should != "pear" }.to raise_error(/does not support `should != expected`. Use `should_not == expected`/) end it "raises an appropriate error for should_not != expected" do expect { "apple".should_not != "pear" }.to raise_error(/does not support `should_not != expected`. Use `should == expected`/) end it "raises an appropriate error for should !~ expected" do expect { "apple".should !~ /regex/ }.to raise_error(/does not support `should !~ expected`. Use `should_not =~ expected`/) end it "raises an appropriate error for should_not !~ expected" do expect { "apple".should_not !~ /regex/ }.to raise_error(/does not support `should_not !~ expected`. Use `should =~ expected`/) end end describe "should_not ==" do it "delegates message to target" do subject = "orange".dup expect(subject).to receive(:==).with("apple").and_return(false) subject.should_not == "apple" end it "returns true on success" do subject = "apple" (subject.should_not == "orange").should be_falsey end it "fails when target.==(actual) returns false" do subject = "apple" expect(RSpec::Expectations).to receive(:fail_with).with(%(expected not: == "apple"\n got: "apple"), "apple", "apple") subject.should_not == "apple" end end describe "should ===" do it "delegates message to target" do subject = "apple".dup expect(subject).to receive(:===).with("apple").and_return(true) subject.should === "apple" end it "fails when target.===(actual) returns false" do subject = "apple".dup expect(subject).to receive(:===).with("orange").and_return(false) expect(RSpec::Expectations).to receive(:fail_with).with(%{expected: "orange"\n got: "apple" (using ===)}, "orange", "apple") subject.should === "orange" end end describe "should_not ===" do it "delegates message to target" do subject = "orange".dup expect(subject).to receive(:===).with("apple").and_return(false) subject.should_not === "apple" end it "fails when target.===(actual) returns false" do subject = "apple".dup expect(subject).to receive(:===).with("apple").and_return(true) expect(RSpec::Expectations).to receive(:fail_with).with(%(expected not: === "apple"\n got: "apple"), "apple", "apple") subject.should_not === "apple" end end describe "should =~" do it "delegates message to target" do subject = "foo".dup expect(subject).to receive(:=~).with(/oo/).and_return(true) subject.should =~ /oo/ end it "fails when target.=~(actual) returns false" do subject = "fu".dup expect(subject).to receive(:=~).with(/oo/).and_return(false) expect(RSpec::Expectations).to receive(:fail_with).with(%{expected: /oo/\n got: "fu" (using =~)}, /oo/, "fu") subject.should =~ /oo/ end end describe "should_not =~" do it "delegates message to target" do subject = "fu".dup expect(subject).to receive(:=~).with(/oo/).and_return(false) subject.should_not =~ /oo/ end it "fails when target.=~(actual) returns false" do subject = "foo".dup expect(subject).to receive(:=~).with(/oo/).and_return(true) expect(RSpec::Expectations).to receive(:fail_with).with(%(expected not: =~ /oo/\n got: "foo"), /oo/, "foo") subject.should_not =~ /oo/ end end describe "should >" do it "passes if > passes" do 4.should > 3 end it "fails if > fails" do expect(RSpec::Expectations).to receive(:fail_with).with("expected: > 5\n got: 4", 5, 4) 4.should > 5 end end describe "should >=" do it "passes if actual == expected" do 4.should >= 4 end it "passes if actual > expected" do 4.should >= 3 end it "fails if > fails" do expect(RSpec::Expectations).to receive(:fail_with).with("expected: >= 5\n got: 4", 5, 4) 4.should >= 5 end end describe "should <" do it "passes if < passes" do 4.should < 5 end it "fails if > fails" do expect(RSpec::Expectations).to receive(:fail_with).with("expected: < 3\n got: 4", 3, 4) 4.should < 3 end end describe "should <=" do it "passes if actual == expected" do 4.should <= 4 end it "passes if actual < expected" do 4.should <= 5 end it "fails if > fails" do expect(RSpec::Expectations).to receive(:fail_with).with("expected: <= 3\n got: 4", 3, 4) 4.should <= 3 end end describe "OperatorMatcher registry" do let(:custom_klass) { Class.new } let(:custom_subklass) { Class.new(custom_klass) } after { RSpec::Matchers::BuiltIn::OperatorMatcher.unregister(custom_klass, "=~") } it "allows operator matchers to be registered for classes" do RSpec::Matchers::BuiltIn::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match) expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_klass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match) end it "considers ancestors when finding an operator matcher" do RSpec::Matchers::BuiltIn::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match) expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_subklass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match) end it "returns nil if there is no matcher registered for a class" do expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_klass, "=~")).to be_nil end end describe RSpec::Matchers::BuiltIn::PositiveOperatorMatcher do it "works when the target has implemented #send" do o = Object.new def o.send(*_args); raise "DOH! Library developers shouldn't use #send!" end expect { o.should == o }.not_to raise_error end end describe RSpec::Matchers::BuiltIn::NegativeOperatorMatcher do it "works when the target has implemented #send" do o = Object.new def o.send(*_args); raise "DOH! Library developers shouldn't use #send!" end expect { o.should_not == :foo }.not_to raise_error end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/output_spec.rb000066400000000000000000000167401455770000100260050ustar00rootroot00000000000000RSpec.shared_examples "output_to_stream" do |stream_name, matcher_method, helper_module| include helper_module extend helper_module it_behaves_like "an RSpec block-only matcher" do let(:matcher) { output(/fo/).send(matcher_method) } def valid_block print_to_stream('foo') end def invalid_block end end define_method :matcher do |*args| output(args.first).send(matcher_method) end it 'is diffable' do expect(matcher).to be_diffable end it 'does not produce warnings when the failure message is accessed first' do expect($VERBOSE).to be_truthy expect { matcher.failure_message }.not_to output.to_stderr end context "expect { ... }.to output.#{matcher_method}" do it "passes if the block outputs to #{stream_name}" do expect { print_to_stream 'foo' }.to matcher end it "fails if the block does not output to #{stream_name}" do expect { expect {}.to matcher }.to fail_with("expected block to output to #{stream_name}, but did not") end end context "expect { ... }.not_to output.#{matcher_method}" do it "passes if the block does not output to #{stream_name}" do expect {}.not_to matcher end it "fails if the block outputs to #{stream_name}" do expect { expect { print_to_stream 'foo' }.not_to matcher }.to fail_with("expected block to not output to #{stream_name}, but output \"foo\"") end end context "expect { ... }.to output('string').#{matcher_method}" do it "passes if the block outputs that string to #{stream_name}" do expect { print_to_stream 'foo' }.to matcher("foo") end it "fails if the block does not output to #{stream_name}" do expect { expect {}.to matcher('foo') }.to fail_with("expected block to output \"foo\" to #{stream_name}, but output nothing") end it "fails if the block outputs a different string to #{stream_name}" do expect { expect { print_to_stream 'food' }.to matcher('foo') }.to fail_with("expected block to output \"foo\" to #{stream_name}, but output \"food\"") end end context "expect { ... }.to_not output('string').#{matcher_method}" do it "passes if the block outputs a different string to #{stream_name}" do expect { print_to_stream 'food' }.to_not matcher('foo') end it "passes if the block does not output to #{stream_name}" do expect {}.to_not matcher('foo') end it "fails if the block outputs the same string to #{stream_name}" do expect { expect { print_to_stream 'foo' }.to_not matcher('foo') }.to fail_with("expected block to not output \"foo\" to #{stream_name}, but output \"foo\"") end end context "expect { ... }.to output(/regex/).#{matcher_method}" do it "passes if the block outputs a string to #{stream_name} that matches the regex" do expect { print_to_stream 'foo' }.to matcher(/foo/) end it "fails if the block does not output to #{stream_name}" do expect { expect {}.to matcher(/foo/) }.to fail_including("expected block to output /foo/ to #{stream_name}, but output nothing\nDiff") end it "fails if the block outputs a string to #{stream_name} that does not match" do expect { expect { print_to_stream 'foo' }.to matcher(/food/) }.to fail_including("expected block to output /food/ to #{stream_name}, but output \"foo\"\nDiff") end end context "expect { ... }.to_not output(/regex/).#{matcher_method}" do it "passes if the block outputs a string to #{stream_name} that does not match the regex" do expect { print_to_stream 'food' }.to_not matcher(/bar/) end it "passes if the block does not output to #{stream_name}" do expect {}.to_not matcher(/foo/) end it "fails if the block outputs a string to #{stream_name} that matches the regex" do expect { expect { print_to_stream 'foo' }.to_not matcher(/foo/) }.to fail_including("expected block to not output /foo/ to #{stream_name}, but output \"foo\"\nDiff") end end context "expect { ... }.to output(matcher).#{matcher_method}" do it "passes if the block outputs a string to #{stream_name} that passes the given matcher" do expect { print_to_stream 'foo' }.to matcher(a_string_starting_with("f")) end it "fails if the block outputs a string to #{stream_name} that does not pass the given matcher" do expect { expect { print_to_stream 'foo' }.to matcher(a_string_starting_with("b")) }.to fail_including("expected block to output a string starting with \"b\" to #{stream_name}, but output \"foo\"\nDiff") end end context "expect { ... }.to_not output(matcher).#{matcher_method}" do it "passes if the block does not output a string to #{stream_name} that passes the given matcher" do expect { print_to_stream 'foo' }.to_not matcher(a_string_starting_with("b")) end it "fails if the block outputs a string to #{stream_name} that passes the given matcher" do expect { expect { print_to_stream 'foo' }.to_not matcher(a_string_starting_with("f")) }.to fail_including("expected block to not output a string starting with \"f\" to #{stream_name}, but output \"foo\"\nDiff") end end end module RSpec module Matchers RSpec.describe "output.to_stderr matcher" do include_examples "output_to_stream", :stderr, :to_stderr, Module.new { def print_to_stream(msg) $stderr.print(msg) end } end RSpec.describe "output.to_stdout matcher" do include_examples "output_to_stream", :stdout, :to_stdout, Module.new { def print_to_stream(msg) print(msg) end } end RSpec.describe "output.to_stderr_from_any_process matcher" do include_examples "output_to_stream", :stderr, :to_stderr_from_any_process, Module.new { def print_to_stream(msg) if RSpec::Support::OS.windows? system("&2") else system("printf #{msg} 1>&2") end end } end RSpec.describe "output.to_stdout_from_any_process matcher" do include_examples "output_to_stream", :stdout, :to_stdout_from_any_process, Module.new { def print_to_stream(msg) if RSpec::Support::OS.windows? system("/ expect { raise StandardError.new, 'boom' }.to raise_error end it "issues a warning when `nil` is passed for an error class" do expect_warning_with_call_site __FILE__, __LINE__+1, /with a `nil`/ expect { raise }.to raise_error(nil) end it "issues a warning when `nil` is passed for an error class when negated" do expect_warning_with_call_site __FILE__, __LINE__+1, /raise_error\(nil\)/ expect { '' }.not_to raise_error(nil) end it "issues a warning that does not include current error when it's not present" do expect(::Kernel).to receive(:warn) do |message| ex = /Actual error raised was/ expect(message).not_to match ex end expect { expect { '' }.to(raise_error) }.to fail_with("expected Exception but nothing was raised") end it "raises an exception when configured to do so" do begin RSpec::Expectations.configuration.on_potential_false_positives = :raise expect_no_warnings expect { expect { '' }.to raise_error }.to raise_error ArgumentError ensure RSpec::Expectations.configuration.on_potential_false_positives = :warn end end it "can supresses the warning when configured to do so", :warn_about_potential_false_positives do RSpec::Expectations.configuration.warn_about_potential_false_positives = false expect_no_warnings expect { raise }.to raise_error end it "can supresses the warning when configured to do so", :warn_about_potential_false_positives do RSpec::Expectations.configuration.on_potential_false_positives = :nothing expect_no_warnings expect { raise }.to raise_error end it 'does not issue a warning when an exception class is specified (even if it is just `Exception`)' do expect_no_warnings expect { raise "error" }.to raise_error Exception end it 'does not issue a warning when a message is specified' do expect_no_warnings expect { raise "error" }.to raise_error "error" end it 'does not issue a warning when a block is passed' do expect_no_warnings expect { raise "error" }.to raise_error { |_| } end it "passes if an error instance is expected" do s = StandardError.new expect { raise s }.to raise_error(s) end it 'passes if an error instance with a non string message is raised' do special_error = Class.new(StandardError) do def initialize(message) @message = message end def message self end def to_s @message end end s = special_error.new 'Stringlike' expect { raise s }.to raise_error('Stringlike') end it "fails if a different error instance is thrown from the one that is expected" do s = StandardError.new("Error 1") to_raise = StandardError.new("Error 2") expect do expect { raise to_raise }.to raise_error(s) end.to fail_with(Regexp.new("expected #{s.inspect}, got #{to_raise.inspect} with backtrace")) end it "passes if an error class is expected and an instance of that class is thrown" do s = StandardError.new :bees expect { raise s }.to raise_error(StandardError) end it "fails if nothing is raised" do expect { expect {}.to raise_error Exception }.to fail_with("expected Exception but nothing was raised") end end RSpec.describe "raise_exception aliased to raise_error" do it "passes if anything is raised" do expect { raise "exception" }.to raise_exception "exception" end end RSpec.describe "expect { ... }.to raise_error {|err| ... }" do it "passes if there is an error" do ran = false expect { non_existent_method }.to raise_error { |_e| ran = true } expect(ran).to be_truthy end it "passes the error to the block" do error = nil expect { non_existent_method }.to raise_error { |e| error = e } expect(error).to be_kind_of(NameError) end end RSpec.describe "expect { ... }.to raise_error do |err| ... end" do it "passes the error to the block" do error = nil expect { non_existent_method }.to raise_error do |e| error = e end expect(error).to be_kind_of(NameError) end end RSpec.describe "expect { ... }.to(raise_error { |err| ... }) do |err| ... end" do it "passes the error only to the block taken directly by #raise_error" do error_passed_to_curly = nil error_passed_to_do_end = nil expect { non_existent_method }.to(raise_error { |e| error_passed_to_curly = e }) do |e| error_passed_to_do_end = e end expect(error_passed_to_curly).to be_kind_of(NameError) expect(error_passed_to_do_end).to be_nil end end # rubocop:disable Style/RedundantException RSpec.describe "expect { ... }.not_to raise_error" do context "with a specific error class" do it "issues a warning" do expect_warning_with_call_site __FILE__, __LINE__+1, /risks false positives/ expect { "bees" }.not_to raise_error(RuntimeError) end it "can supresses the warning when configured to do so", :warn_about_potential_false_positives do RSpec::Expectations.configuration.warn_about_potential_false_positives = false expect_no_warnings expect { "bees" }.not_to raise_error(RuntimeError) end end context "with no specific error class" do it "passes if nothing is raised" do expect {}.not_to raise_error end it "fails if anything is raised" do expect { expect { raise RuntimeError, "example message" }.not_to raise_error }.to fail_with(/expected no Exception, got #/) end it 'includes the backtrace of the error that was raised in the error message' do expect { expect { raise "boom" }.not_to raise_error }.to raise_error { |e| backtrace_line = "#{File.basename(__FILE__)}:#{__LINE__ - 2}" expect(e.message).to include("with backtrace", backtrace_line) } end it 'formats the backtrace using the configured backtrace formatter' do allow(RSpec::Matchers.configuration.backtrace_formatter). to receive(:format_backtrace). and_return("formatted-backtrace") expect { expect { raise "boom" }.not_to raise_error }.to raise_error { |e| expect(e.message).to include("with backtrace", "formatted-backtrace") } end end end RSpec.describe "expect { ... }.to raise_error(message)" do it "passes if RuntimeError is raised with the right message" do expect { raise 'blah' }.to raise_error('blah') end it "passes if RuntimeError is raised with a matching message" do expect { raise 'blah' }.to raise_error(/blah/) end it "passes if any other error is raised with the right message" do expect { raise NameError.new('blah') }.to raise_error('blah') end it "fails if RuntimeError error is raised with the wrong message" do expect do expect { raise 'blarg' }.to raise_error('blah') end.to fail_with(/expected Exception with \"blah\", got #/) end it "fails if any other error is raised with the wrong message" do expect do expect { raise NameError.new('blarg') }.to raise_error('blah') end.to fail_with(/expected Exception with \"blah\", got #/) end it "fails if any other error is raised with the wrong message" do expect do expect { raise NameError.new('blarg') }.to raise_error.with_message('blah') end.to fail_with(/expected Exception with \"blah\", got #/) end it "fails if another error is raised (NameError)" do expect { expect { load "non/existent/file" }.to raise_error(NameError) }.to fail_with(/expected NameError, got #/) end it "fails if correct error is raised with incorrect message" do expect { expect { raise RuntimeError.new("not the example message") }.to raise_error(RuntimeError, "example message") }.to fail_with(/expected RuntimeError with \"example message\", got #/) end it "fails if correct error is raised with incorrect message" do expect { expect { raise RuntimeError.new("not the example message") }.to raise_error(RuntimeError, /less than ample mess/) }.to fail_with(/expected RuntimeError with message matching \/less than ample mess\/, got #/) end end # rubocop:enable Style/RedundantException RSpec.describe "expect { ... }.not_to raise_error(NamedError, error_message) with Regexp" do it "issues a warning" do expect_warning_with_call_site __FILE__, __LINE__+1, /risks false positives/ expect {}.not_to raise_error(RuntimeError, /ample mess/) end it "can supresses the warning when configured to do so", :warn_about_potential_false_positives do RSpec::Expectations.configuration.warn_about_potential_false_positives = false expect_no_warnings expect {}.not_to raise_error(RuntimeError, /ample mess/) end end RSpec.describe "expect { ... }.to raise_error(NamedError, error_message) { |err| ... }" do it "yields exception if named error is raised with same message" do ran = false expect { raise "example message" }.to raise_error(RuntimeError, "example message") { |err| ran = true expect(err.class).to eq RuntimeError expect(err.message).to eq "example message" } expect(ran).to be(true) end it "yielded block fails on it's own right" do ran, passed = false, false expect { expect { raise "example message" }.to raise_error(RuntimeError, "example message") { |_err| ran = true expect(5).to eq 4 passed = true } }.to fail_with(/expected: 4/m) expect(ran).to be_truthy expect(passed).to be_falsey end it "does NOT yield exception if no error was thrown" do ran = false expect { expect {}.to raise_error(RuntimeError, "example message") { |_err| ran = true } }.to fail_with(/expected RuntimeError with \"example message\" but nothing was raised/) expect(ran).to eq false end it "does not yield exception if error class is not matched" do ran = false expect { expect { raise "example message" }.to raise_error(SyntaxError, "example message") { |_err| ran = true } }.to fail_with(/expected SyntaxError with \"example message\", got #/) expect(ran).to eq false end it "does NOT yield exception if error message is not matched" do ran = false expect { expect { raise "example message" }.to raise_error(RuntimeError, "different message") { |_err| ran = true } }.to fail_with(/expected RuntimeError with \"different message\", got #/) expect(ran).to eq false end end RSpec.describe "expect { ... }.not_to raise_error(NamedError, error_message) { |err| ... }" do it "issues a warning" do expect_warning_with_call_site __FILE__, __LINE__+1, /risks false positives/ expect {}.not_to raise_error(RuntimeError, "example message") { |err| } end it "can supresses the warning when configured to do so", :warn_about_potential_false_positives do RSpec::Expectations.configuration.warn_about_potential_false_positives = false expect_no_warnings expect {}.not_to raise_error(RuntimeError, "example message") { |err| } end end RSpec.describe "Composing matchers with `raise_error`" do matcher :an_attribute do |attr| chain :equal_to do |value| @expected_value = value end match do |error| return false unless error.respond_to?(attr) error.__send__(attr) == @expected_value end end class FooError < StandardError def foo; :bar; end end describe "expect { }.to raise_error(matcher)" do it 'passes when the matcher matches the raised error' do expect { raise FooError }.to raise_error(an_attribute(:foo).equal_to(:bar)) end it 'passes when the matcher matches the exception message' do expect { raise FooError, "food" }.to raise_error(a_string_including("foo")) end it 'fails with a clear message when the matcher does not match the raised error' do expect { expect { raise FooError }.to raise_error(an_attribute(:foo).equal_to(3)) }.to fail_including("expected Exception with an attribute :foo equal to 3, got #") end it 'fails with a clear message when the matcher does not match the exception message' do expect { expect { raise FooError, "food" }.to raise_error(a_string_including("bar")) }.to fail_including('expected Exception with a string including "bar", got # "s", :invalid_value => 5 do let(:matcher) { respond_to(:upcase) } end it "passes if target responds to :sym" do expect(Object.new).to respond_to(:methods) end it "passes if target responds to :sym but does not implement method" do # This simulates a behaviour of Rails, see #1162. klass = Class.new { def respond_to?(_); true; end } expect(klass.new).to respond_to(:my_method) end it "fails if target does not respond to :sym" do expect { expect("this string").to respond_to(:some_method) }.to fail_with('expected "this string" to respond to :some_method') end end RSpec.describe "expect(...).to respond_to(:sym).with(1).argument" do it "passes if target responds to :sym with 1 arg" do obj = Object.new def obj.foo(arg); end expect(obj).to respond_to(:foo).with(1).argument end it "passes if target responds to any number of arguments" do obj = Object.new def obj.foo(*args); end expect(obj).to respond_to(:foo).with(1).argument end it "passes if target responds to one or more arguments" do obj = Object.new def obj.foo(a, *args); end expect(obj).to respond_to(:foo).with(1).argument end it "verifes the method signature of new as if it was initialize" do klass = Class.new { def initialize(a, b); end; } expect(klass).to respond_to(:new).with(2).arguments end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with(1).argument }.to fail_with(/expected .* to respond to :some_method/) end it "fails if :sym expects 0 args" do obj = Object.new def obj.foo; end expect { expect(obj).to respond_to(:foo).with(1).argument }.to fail_with(/expected # to respond to :foo with 1 argument/) end it "fails if :sym expects 2 args" do obj = Object.new def obj.foo(arg, arg2); end expect { expect(obj).to respond_to(:foo).with(1).argument }.to fail_with(/expected # to respond to :foo with 1 argument/) end it "fails if :sym expects 2 or more args" do obj = Object.new def obj.foo(arg, arg2, *args); end expect { expect(obj).to respond_to(:foo).with(1).argument }.to fail_with(/expected # to respond to :foo with 1 argument/) end it "fails if the method signature of initialize does not match" do klass = Class.new { def initialize(a, b); end; } expect { expect(klass).to respond_to(:new).with(1).arguments }.to fail_with(/expected # to respond to :new with 1 argument/) end it "still works if target has overridden the method method" do obj = Object.new def obj.method; end def obj.other_method(arg); end expect(obj).to respond_to(:other_method).with(1).argument end it "warns that the subject does not have the implementation required when method does not exist" do # This simulates a behaviour of Rails, see #1162. klass = Class.new { def respond_to?(_); true; end } expect { expect(klass.new).to respond_to(:my_method).with(0).arguments }.to raise_error(ArgumentError) end end RSpec.describe "expect(...).to respond_to(:new)" do context "with no tampering" do it "will validate new as if it was initialize" do klass = Class.new { def initialize(a, b, c); end } expect(klass).not_to respond_to(:new).with(2).arguments expect(klass).to respond_to(:new).with(3).arguments end end context "on a class that has redefined `new`" do it "uses the method signature of the redefined `new` for arg verification" do klass = Class.new { def self.new(a); end } expect(klass).to respond_to(:new).with(1).argument expect { expect(klass).to respond_to(:new).with(2).arguments }.to fail_with(/expected # to respond to :new with 2 arguments/) expect { expect(klass).to_not respond_to(:new).with(1).argument }.to fail_with(/expected # not to respond to :new with 1 argument/) end end context "on a class that has undefined `new`" do it "will not respond to new" do klass = Class.new do class << self undef new end end expect { expect(klass).to respond_to(:new) }.to fail_with(/expected .* to respond to :new/) end end context "on a class with a private `new`" do it "will not respond to new" do klass = Class.new { private_class_method :new; def initialize(a, b, c); end } expect(klass).not_to respond_to(:new) end end end RSpec.describe "expect(...).to respond_to(message1, message2)" do it "passes if target responds to both messages" do expect(Object.new).to respond_to('methods', 'inspect') end it "fails if target does not respond to first message" do expect { expect(Object.new).to respond_to('method_one', 'inspect') }.to fail_with(/expected # to respond to "method_one"/) end it "fails if target does not respond to second message" do expect { expect(Object.new).to respond_to('inspect', 'method_one') }.to fail_with(/expected # to respond to "method_one"/) end it "fails if target does not respond to either message" do expect { expect(Object.new).to respond_to('method_one', 'method_two') }.to fail_with(/expected # to respond to "method_one", "method_two"/) end end RSpec.describe "expect(...).to respond_to(:sym).with(2).arguments" do it "passes if target responds to :sym with 2 args" do obj = Object.new def obj.foo(a1, a2); end expect(obj).to respond_to(:foo).with(2).arguments end it "passes if target responds to any number of arguments" do obj = Object.new def obj.foo(*args); end expect(obj).to respond_to(:foo).with(2).arguments end it "passes if target responds to one or more arguments" do obj = Object.new def obj.foo(a, *args); end expect(obj).to respond_to(:foo).with(2).arguments end it "passes if target responds to two or more arguments" do obj = Object.new def obj.foo(a, b, *args); end expect(obj).to respond_to(:foo).with(2).arguments end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with(2).arguments }.to fail_with(/expected .* to respond to :some_method/) end it "fails if :sym expects 0 args" do obj = Object.new def obj.foo; end expect { expect(obj).to respond_to(:foo).with(2).arguments }.to fail_with(/expected # to respond to :foo with 2 arguments/) end it "fails if :sym expects 1 args" do obj = Object.new def obj.foo(arg); end expect { expect(obj).to respond_to(:foo).with(2).arguments }.to fail_with(/expected # to respond to :foo with 2 arguments/) end it "fails if :sym expects 3 or more args" do obj = Object.new def obj.foo(arg, arg2, arg3, *args); end expect { expect(obj).to respond_to(:foo).with(2).arguments }.to fail_with(/expected # to respond to :foo with 2 arguments/) end end RSpec.describe "expect(...).to respond_to(:sym).with(1..2).arguments" do it "passes if target responds to any number of arguments" do obj = Object.new def obj.foo(*args); end expect(obj).to respond_to(:foo).with(1..2).arguments end it "passes if target responds to one or more arguments" do obj = Object.new def obj.foo(a, *args); end expect(obj).to respond_to(:foo).with(1..2).arguments end it "passes if target responds to one or two arguments" do obj = Object.new def obj.foo(a, b=nil); end expect(obj).to respond_to(:foo).with(1..2).arguments end it "passes if target responds to one to three arguments" do obj = Object.new def obj.foo(a, b=nil, c=nil); end expect(obj).to respond_to(:foo).with(1..2).arguments end it "passes if target is new and initialize reponds to arguments" do klass = Class.new { def initialize(arg, arg2=nil, arg3=nil); end } expect(klass).to respond_to(:new).with(1..2).arguments end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with(1..2).arguments }.to fail_with(/expected .* to respond to :some_method/) end it "fails if :sym expects 0 args" do obj = Object.new def obj.foo; end expect { expect(obj).to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected # to respond to :foo with 1..2 arguments/) end it "fails if :sym expects 1 args" do obj = Object.new def obj.foo(arg); end expect { expect(obj).to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected # to respond to :foo with 1..2 arguments/) end it "fails if :sym expects 2 args" do obj = Object.new def obj.foo(a, b); end expect { expect(obj).to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected # to respond to :foo with 1..2 arguments/) end it "fails if :sym expects 3 or more args" do obj = Object.new def obj.foo(arg, arg2, arg3, *args); end expect { expect(obj).to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected # to respond to :foo with 1..2 arguments/) end it "fails when new unless initialize matches the signature" do klass = Class.new { def initialize(arg, arg2, arg3, *args); end } expect { expect(klass).to respond_to(:new).with(1..2).arguments }.to fail_with(/expected # to respond to :new with 1..2 arguments/) end end RSpec.describe "expect(...).to respond_to(:sym).with_unlimited_arguments" do it "passes if target responds to any number of arguments" do obj = Object.new def obj.foo(*args); end expect(obj).to respond_to(:foo).with_unlimited_arguments end it "passes if target responds to a minimum number of arguments" do obj = Object.new def obj.foo(arg, arg2, arg3, *args); end expect(obj).to respond_to(:foo).with(3).arguments.and_unlimited_arguments end it "passes when target is new and initialize responds to any number of arguments" do # note we can't use the metaobject definition for initialize klass_2 = Class.new { def initialize(*args); end } expect(klass_2).to respond_to(:new).with_unlimited_arguments end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with_unlimited_arguments }.to fail_with(/expected .* to respond to :some_method/) end it "fails if :sym expects a minimum number of arguments" do obj = Object.new def obj.some_method(arg, arg2, arg3, *args); end expect { expect(obj).to respond_to(:some_method).with_unlimited_arguments }.to fail_with(/expected .* to respond to :some_method with unlimited arguments/) end it "fails if :sym expects a limited number of arguments" do obj = Object.new def obj.some_method(arg); end expect { expect(obj).to respond_to(:some_method).with_unlimited_arguments }.to fail_with(/expected .* to respond to :some_method with unlimited arguments/) end it "fails when target is new and initialize responds to a set number of arguments" do klass = Class.new { def initialize(a); end } expect { expect(klass).to respond_to(:new).with_unlimited_arguments }.to fail_with(/expected .* to respond to :new with unlimited arguments/) end end RSpec.describe "expect(...).not_to respond_to(:sym)" do it "passes if target does not respond to :sym" do expect(Object.new).not_to respond_to(:some_method) end it "fails if target responds to :sym" do expect { expect(Object.new).not_to respond_to(:methods) }.to fail_with(/expected # not to respond to :methods/) end end RSpec.describe "expect(...).not_to respond_to(:sym).with(1).argument" do it "fails if target responds to :sym with 1 arg" do obj = Object.new def obj.foo(arg); end expect { expect(obj).not_to respond_to(:foo).with(1).argument }.to fail_with(/expected # not to respond to :foo with 1 argument/) end it "fails if target responds to :sym with any number of args" do obj = Object.new def obj.foo(*args); end expect { expect(obj).not_to respond_to(:foo).with(1).argument }.to fail_with(/expected # not to respond to :foo with 1 argument/) end it "fails if target responds to :sym with one or more args" do obj = Object.new def obj.foo(a, *args); end expect { expect(obj).not_to respond_to(:foo).with(1).argument }.to fail_with(/expected # not to respond to :foo with 1 argument/) end it "will fail when target is new and initialize matches the argument signature" do klass = Class.new { def initialize(a); end } expect { expect(klass).to_not respond_to(:new).with(1).argument }.to fail_with(/not to respond to :new with 1 argument/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with(1).argument end it "passes if :sym expects 0 args" do obj = Object.new def obj.foo; end expect(obj).not_to respond_to(:foo).with(1).argument end it "passes if :sym expects 2 args" do obj = Object.new def obj.foo(arg, arg2); end expect(obj).not_to respond_to(:foo).with(1).argument end it "passes if :sym expects 2 or more args" do obj = Object.new def obj.foo(arg, arg2, *args); end expect(obj).not_to respond_to(:foo).with(1).argument end it "will pass when target is new and initialize does not matches the argument signature" do klass = Class.new { def initialize(a, b); end } expect(klass).to_not respond_to(:new).with(1).argument end end RSpec.describe "expect(...).not_to respond_to(message1, message2)" do it "passes if target does not respond to either message1 or message2" do expect(Object.new).not_to respond_to(:some_method, :some_other_method) end it "fails if target responds to message1 but not message2" do expect { expect(Object.new).not_to respond_to(:object_id, :some_method) }.to fail_with(/expected # not to respond to :object_id/) end it "fails if target responds to message2 but not message1" do expect { expect(Object.new).not_to respond_to(:some_method, :object_id) }.to fail_with(/expected # not to respond to :object_id/) end it "fails if target responds to both message1 and message2" do expect { expect(Object.new).not_to respond_to(:class, :object_id) }.to fail_with(/expected # not to respond to :class, :object_id/) end end RSpec.describe "expect(...).not_to respond_to(:sym).with(2).arguments" do it "fails if target responds to :sym with 2 args" do obj = Object.new def obj.foo(a1, a2); end expect { expect(obj).not_to respond_to(:foo).with(2).arguments }.to fail_with(/expected .* not to respond to :foo with 2 arguments/) end it "fails if target responds to :sym with any number args" do obj = Object.new def obj.foo(*args); end expect { expect(obj).not_to respond_to(:foo).with(2).arguments }.to fail_with(/expected .* not to respond to :foo with 2 arguments/) end it "fails if target responds to :sym with one or more args" do obj = Object.new def obj.foo(a, *args); end expect { expect(obj).not_to respond_to(:foo).with(2).arguments }.to fail_with(/expected .* not to respond to :foo with 2 arguments/) end it "fails if target responds to :sym with two or more args" do obj = Object.new def obj.foo(a, b, *args); end expect { expect(obj).not_to respond_to(:foo).with(2).arguments }.to fail_with(/expected .* not to respond to :foo with 2 arguments/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with(2).arguments end it "passes if :sym expects 0 args" do obj = Object.new def obj.foo; end expect(obj).not_to respond_to(:foo).with(2).arguments end it "passes if :sym expects 2 args" do obj = Object.new def obj.foo(arg); end expect(obj).not_to respond_to(:foo).with(2).arguments end it "passes if :sym expects 3 or more args" do obj = Object.new def obj.foo(a, b, c, *arg); end expect(obj).not_to respond_to(:foo).with(2).arguments end end RSpec.describe "expect(...).not_to respond_to(:sym).with(1..2).arguments" do it "fails if target responds to :sym with one or two args" do obj = Object.new def obj.foo(a1, a2=nil); end expect { expect(obj).not_to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected .* not to respond to :foo with 1..2 arguments/) end it "fails if target responds to :sym with any number args" do obj = Object.new def obj.foo(*args); end expect { expect(obj).not_to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected .* not to respond to :foo with 1..2 arguments/) end it "fails if target responds to :sym with one or more args" do obj = Object.new def obj.foo(a, *args); end expect { expect(obj).not_to respond_to(:foo).with(1..2).arguments }.to fail_with(/expected .* not to respond to :foo with 1..2 arguments/) end it "will fail when target is new and initialize matches the argument signature" do klass = Class.new { def initialize(a, *args); end } expect { expect(klass).to_not respond_to(:new).with(1..2).argument }.to fail_with(/not to respond to :new with 1..2 argument/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with(1..2).arguments end it "passes if :sym expects 0 args" do obj = Object.new def obj.foo; end expect(obj).not_to respond_to(:foo).with(1..2).arguments end it "passes if :sym expects 1 arg" do obj = Object.new def obj.foo(arg); end expect(obj).not_to respond_to(:foo).with(1..2).arguments end it "passes if :sym expects 2 args" do obj = Object.new def obj.foo(a, b); end expect(obj).not_to respond_to(:foo).with(1..2).arguments end it "passes if :sym expects 3 or more args" do obj = Object.new def obj.foo(a, b, c, *arg); end expect(obj).not_to respond_to(:foo).with(1..2).arguments end it "passes when target is new and initialize does not match the argument signature" do klass = Class.new { def initialize(a); end } expect(klass).to_not respond_to(:new).with(1..2).argument end end RSpec.describe "expect(...).not_to respond_to(:sym).with_unlimited_arguments" do it "fails if target responds to :sym with any number args" do obj = Object.new def obj.foo(*args); end expect { expect(obj).not_to respond_to(:foo).with_unlimited_arguments }.to fail_with(/expected .* not to respond to :foo with unlimited arguments/) end it "will fail when target is new and initialize has unlimited arguments" do klass = Class.new { def initialize(*args); end } expect { expect(klass).to_not respond_to(:new).with_unlimited_arguments }.to fail_with(/not to respond to :new with unlimited argument/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with_unlimited_arguments end it "passes if :sym expects a limited number of arguments" do obj = Object.new def obj.some_method(arg); end expect(obj).not_to respond_to(:some_method).with_unlimited_arguments end it "passes if :sym expects a minimum number of arguments" do obj = Object.new def obj.some_method(arg, arg2, arg3, *args); end expect(obj).not_to respond_to(:some_method).with_unlimited_arguments end it "passes when target is new and initialize has arguments" do klass = Class.new { def initialize(a, *args); end } expect(klass).to_not respond_to(:new).with_unlimited_arguments end end if RSpec::Support::RubyFeatures.kw_args_supported? RSpec.describe "expect(...).to respond_to(:sym).with_keywords(:foo, :bar)" do it 'passes if target responds to :sym with specified optional keywords' do obj = Object.new eval %{def obj.foo(a: nil, b: nil); end} expect(obj).to respond_to(:foo).with_keywords(:a, :b) end it 'passes if target responds to :sym with any keywords' do obj = Object.new eval %{def obj.foo(**kw_args); end} expect(obj).to respond_to(:foo).with_keywords(:a, :b) end it 'passes if target is :new with keywords' do # note we can't use the metaobject definition for initialize klass = eval %{Class.new { def initialize(a: nil, b: nil); end}} expect(klass).to respond_to(:new).with_keywords(:a, :b) # note we can't use the metaobject definition for initialize klass_2 = eval %{Class.new { def initialize(**kw_args); end}} expect(klass_2).to respond_to(:new).with_keywords(:a, :b) end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with_keywords(:a, :b) }.to fail_with(/expected .* to respond to :some_method with keywords :a and :b/) end it "fails if :sym does not expect specified keywords" do obj = Object.new def obj.foo; end expect { expect(obj).to respond_to(:foo).with_keywords(:a, :b) }.to fail_with(/expected .* to respond to :foo with keywords :a and :b/) end it "fails if :sym does not expect many specified keywords" do obj = Object.new def obj.foo; end expect { expect(obj).to respond_to(:foo).with_keywords(:a, :b, :c, :d, :e, :f) }.to fail_with(/expected .* to respond to :foo with keywords :a, :b, :c, :d, :e, and :f/) end it 'fails if target is :new but initialize does not expect the right keywords' do # note we can't use the metaobject definition for initialize klass = eval %{Class.new { def initialize(a: nil); end}} expect { expect(klass).to respond_to(:new).with_keywords(:a, :b) }.to fail_with(/expected .* to respond to :new with keywords :a and :b/) end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "passes if target responds to :sym with specified required keywords" do obj = Object.new eval %{def obj.foo(a:, b:, c: nil, d: nil); end} expect(obj).to respond_to(:foo).with_keywords(:a, :b) end it "passes if target responds to :sym with keyword arg splat" do obj = Object.new eval %{def obj.foo(**rest); end} expect(obj).to respond_to(:foo).with_keywords(:a, :b) end it 'passes if target is :new and initialize has specified required keywords' do # note we can't use the metaobject definition for initialize klass = eval %{Class.new { def initialize(a:, b:); end}} expect(klass).to respond_to(:new).with_keywords(:a, :b) end it "fails if :sym expects specified optional keywords but expects missing required keywords" do obj = Object.new eval %{def obj.foo(a:, b:, c: nil, d: nil); end} expect { expect(obj).to respond_to(:some_method).with_keywords(:c, :d) }.to fail_with(/expected .* to respond to :some_method with keywords :c and :d/) end it "fails if target responds to :sym with keyword arg splat but missing required keywords" do obj = Object.new eval %{def obj.foo(a:, b:, **rest); end} expect { expect(obj).to respond_to(:some_method).with_keywords(:c, :d) }.to fail_with(/expected .* to respond to :some_method with keywords :c and :d/) end it 'fails if target is :new and initialize has is missing required keywords' do # note we can't use the metaobject definition for initialize klass = eval %{Class.new { def initialize(a:, b:); end}} expect { expect(klass).to respond_to(:new).with_keywords(:c, :d) }.to fail_with(/expected .* to respond to :new with keywords :c and :d/) end end end RSpec.describe "expect(...).to respond_to(:sym).with(2).arguments.and_keywords(:foo, :bar)" do it "passes if target responds to :sym with 2 args and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, b, u: nil, v: nil); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "passes if target responds to :sym with any number of arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(*args, u: nil, v: nil); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "passes if target responds to :sym with one or more arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, *args, u: nil, v: nil); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "passes if target responds to :sym with two or more arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, b, *args, u: nil, v: nil); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected .* to respond to :some_method with 2 arguments and keywords :u and :v/) end it "fails if :sym expects 1 argument" do obj = Object.new eval %{def obj.foo(a, u: nil, v: nil); end} expect { expect(obj).to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected .* to respond to :some_method with 2 arguments and keywords :u and :v/) end it "fails if :sym does not expect specified keywords" do obj = Object.new def obj.foo(a, b); end expect { expect(obj).to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected .* to respond to :some_method with 2 arguments and keywords :u and :v/) end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "passes if target responds to :sym with 2 args and specified required keywords" do obj = Object.new eval %{def obj.foo(a, b, u:, v:); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "passes if target responds to :sym with 2 args and keyword arg splat" do obj = Object.new eval %{def obj.foo(a, b, **rest); end} expect(obj).to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) end it "passes for new when target responds to initialize with a mixture of arguments" do klass = eval %{Class.new { def initialize(a, b, c:, d: nil); end }} expect(klass).to respond_to(:new).with(2).arguments.and_keywords(:c, :d) end it "fails if :sym expects 2 arguments and specified optional keywords but expects missing required keywords" do obj = Object.new eval %{def obj.foo(a, b, u: nil, v: nil, x:, y:); end} expect { expect(obj).to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected .* to respond to :some_method with 2 arguments and keywords :u and :v/) end it "fails for new when target responds to initialize with the wrong mixture of arguments" do klass = eval %{Class.new { def initialize(a, b, c:); end }} expect { expect(klass).to respond_to(:new).with(2).arguments.and_keywords(:c, :d) }.to fail_with(/expected .* to respond to :new with 2 arguments and keywords :c and :d/) end end end RSpec.describe "expect(...).to respond_to(:sym).with_any_keywords" do it "passes if target responds to any keywords" do obj = Object.new eval %{def obj.foo(**kw_args); end} expect(obj).to respond_to(:foo).with_any_keywords end it "passes when initialize responds to any keywords and we check new" do klass = eval %{Class.new { def initialize(**kw_args); end }} expect(klass).to respond_to(:new).with_any_keywords end it "fails if target does not respond to :sym" do obj = Object.new expect { expect(obj).to respond_to(:some_method).with_any_keywords }.to fail_with(/expected .* to respond to :some_method/) end it "fails if :sym expects a limited set of keywords" do obj = Object.new eval %{def obj.some_method(a: nil, b: nil); end} expect { expect(obj).to respond_to(:some_method).with_any_keywords }.to fail_with(/expected .* to respond to :some_method with any keywords/) end it "fails when initialize expects a limited set of keywords and we check new" do klass = eval %{Class.new { def initialize(a: nil); end }} expect { expect(klass).to respond_to(:new).with_any_keywords }.to fail_with(/expected .* to respond to :new with any keywords/) end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "fails if :sym expects missing required keywords" do obj = Object.new eval %{def obj.some_method(a:, b:, **kw_args); end} expect { expect(obj).to respond_to(:some_method).with_any_keywords }.to fail_with(/expected .* to respond to :some_method with any keywords/) end it "fails if :initialize expects missing required keywords when we test new" do klass = eval %{Class.new { def initialize(a:, **kw_args); end }} eval %{def initialize(a:, b:, **kw_args); end} expect { expect(klass).to respond_to(:new).with_any_keywords }.to fail_with(/expected .* to respond to :new with any keywords/) end end end RSpec.describe "expect(...).not_to respond_to(:sym).with_keywords(:foo, :bar)" do it "fails if target responds to :sym with specified optional keywords" do obj = Object.new eval %{def obj.foo(a: nil, b: nil); end} expect { expect(obj).not_to respond_to(:foo).with_keywords(:a, :b) }.to fail_with(/expected # not to respond to :foo with keywords :a and :b/) end it "fails if target responds to :sym with any keywords" do obj = Object.new eval %{def obj.foo(**kw_args); end} expect { expect(obj).not_to respond_to(:foo).with_keywords(:a, :b) }.to fail_with(/expected # not to respond to :foo with keywords :a and :b/) end it "fails if target initialize responds to expected keywords when checking new" do klass = eval %{Class.new { def initialize(**kw_args); end }} expect { expect(klass).not_to respond_to(:new).with_keywords(:a, :b) }.to fail_with(/expected .* not to respond to :new with keywords :a and :b/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with_keywords(:a, :b) end it "passes if :sym does not expect specified keywords" do obj = Object.new eval %{def obj.foo(a: nil, b: nil); end} expect(obj).not_to respond_to(:some_method).with_keywords(:c, :d) end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "fails if target responds to :sym with specified required keywords" do obj = Object.new eval %{def obj.foo(a:, b:); end} expect { expect(obj).not_to respond_to(:foo).with_keywords(:a, :b) }.to fail_with(/expected # not to respond to :foo with keywords :a and :b/) end it "fails if target responds to :sym with keyword arg splat" do obj = Object.new eval %{def obj.foo(**rest); end} expect { expect(obj).not_to respond_to(:foo).with_keywords(:a, :b) }.to fail_with(/expected # not to respond to :foo with keywords :a and :b/) end it "passes if :sym expects missing required keywords" do obj = Object.new eval %{def obj.foo(a:, b:, c: nil, d: nil); end} expect(obj).not_to respond_to(:some_method).with_keywords(:c, :d) end it "passes if :initialize expects missing required keywords for :new" do klass = eval %{Class.new { def initialize(a:, b:, c: nil, d: nil); end }} expect(klass).not_to respond_to(:new).with_keywords(:c, :d) end end end RSpec.describe "expect(...).not_to respond_to(:sym).with(2).arguments.and_keywords(:foo, :bar)" do it "fails if target responds to :sym with 2 args and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, b, u: nil, v: nil); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "fails if target responds to :sym with any number of arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(*args, u: nil, v: nil); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "fails if target responds to :sym with one or more arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, *args, u: nil, v: nil); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "fails if target responds to :sym with two or more arguments and specified optional keywords" do obj = Object.new eval %{def obj.foo(a, b, *args, u: nil, v: nil); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) end it "passes if :sym expects 1 argument" do obj = Object.new eval %{def obj.foo(a, u: nil, v: nil); end} expect(obj).not_to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) end it "passes if :sym does not expect specified keywords" do obj = Object.new def obj.foo(a, b); end expect(obj).not_to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "fails if target responds to :sym with 2 args and specified required keywords" do obj = Object.new eval %{def obj.foo(a, b, u:, v:); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "fails if target responds to :sym with 2 args and keyword arg splat" do obj = Object.new eval %{def obj.foo(a, b, **rest); end} expect { expect(obj).not_to respond_to(:foo).with(2).arguments.and_keywords(:u, :v) }.to fail_with(/expected # not to respond to :foo with 2 arguments and keywords :u and :v/) end it "passes if :sym expects 2 arguments and specified optional keywords but expects missing required keywords" do obj = Object.new eval %{def obj.foo(a, b, u: nil, v: nil, x:, y:); end} expect(obj).not_to respond_to(:some_method).with(2).arguments.and_keywords(:u, :v) end end end RSpec.describe "expect(...).not_to respond_to(:sym).with_any_keywords" do it "fails if target responds to any keywords" do obj = Object.new eval %{def obj.foo(**kw_args); end} expect { expect(obj).not_to respond_to(:foo).with_any_keywords }.to fail_with(/expected # not to respond to :foo with any keywords/) end it "passes if target does not respond to :sym" do obj = Object.new expect(obj).not_to respond_to(:some_method).with_any_keywords end it "passes if :sym expects a limited set of keywords" do obj = Object.new eval %{def obj.some_method(a: nil, b: nil); end} expect(obj).not_to respond_to(:some_method).with_any_keywords end if RSpec::Support::RubyFeatures.required_kw_args_supported? it "passes if :sym expects missing required keywords" do obj = Object.new eval %{def obj.some_method(a:, b:, **kw_args); end} expect(obj).not_to respond_to(:some_method).with_any_keywords end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/satisfy_spec.rb000066400000000000000000000073411455770000100261240ustar00rootroot00000000000000RSpec.describe "expect(...).to satisfy { block }" do it_behaves_like "an RSpec value matcher", :valid_value => true, :invalid_value => false do let(:matcher) { satisfy { |v| v } } end it "describes itself" do expect(satisfy.description).to eq("satisfy block") end it "passes if block returns true" do expect(true).to satisfy { |val| val } expect(true).to satisfy do |val| val end end context "when no custom description is provided" do context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "fails with block snippet if block returns false" do expect { expect(false).to satisfy { |val| val } }.to fail_with("expected false to satisfy expression `val`") expect do expect(false).to satisfy do |val| val end end.to fail_with("expected false to satisfy expression `val`") end context 'when used with an alias name' do alias_matcher :fulfill, :satisfy it 'can extract the block snippet' do expect { expect(false).to fulfill { |val| val } }.to fail_with("expected false to fulfill expression `val`") end end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "fails without block snippet if block returns false" do expect { expect(false).to satisfy { |val| val } }.to fail_with("expected false to satisfy block") expect do expect(false).to satisfy do |val| val end end.to fail_with("expected false to satisfy block") end end end context "when a custom description is provided" do it "describes itself" do expect(satisfy("be awesome").description).to eq("be awesome") end it "passes if block returns true" do expect(true).to satisfy("be true") { |val| val } expect(true).to satisfy("be true") do |val| val end end it "fails with the custom description if block returns false" do expect { expect(false).to satisfy("be true") { |val| val } }.to fail_with("expected false to be true") expect do expect(false).to satisfy("be true") do |val| val end end.to fail_with("expected false to be true") end end end RSpec.describe "expect(...).not_to satisfy { block }" do it "passes if block returns false" do expect(false).not_to satisfy { |val| val } expect(false).not_to satisfy do |val| val end end context "when no custom description is provided" do context 'in Ripper supported environment', :if => RSpec::Support::RubyFeatures.ripper_supported? do it "fails with block snippet if block returns true" do expect { expect(true).not_to satisfy { |val| val } }.to fail_with("expected true not to satisfy expression `val`") end end context 'in Ripper unsupported environment', :unless => RSpec::Support::RubyFeatures.ripper_supported? do it "fails without block snippet if block returns true" do expect { expect(true).not_to satisfy { |val| val } }.to fail_with("expected true not to satisfy block") end end end context "when a custom description is provided" do it "passes if block returns false" do expect(false).not_to satisfy("be true") { |val| val } expect(false).not_to satisfy("be true") do |val| val end end it "fails with the custom description if block returns true" do expect { expect(true).not_to satisfy("be true") { |val| val } }.to fail_with("expected true not to be true") end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/start_and_end_with_spec.rb000066400000000000000000000323341455770000100303020ustar00rootroot00000000000000RSpec.describe "expect(...).to start_with" do it_behaves_like "an RSpec value matcher", :valid_value => "ab", :invalid_value => "bc" do let(:matcher) { start_with("a") } end context "with a string" do it "passes if it matches the start of the actual string" do expect("this string").to start_with "this str" end it "fails if it does not match the start of the actual string" do expect { expect("this string").to start_with "that str" }.to fail_with("expected \"this string\" to start with \"that str\"") end end context "with an array" do it "passes if it is the first element of the array" do expect([0, 1, 2]).to start_with 0 end it "passes if the first elements of the array match" do expect([0, 1, 2]).to start_with 0, 1 end it "fails if it does not match the first element of the array" do expect { expect([0, 1, 2]).to start_with 2 }.to fail_with("expected [0, 1, 2] to start with 2") end it "fails if it the first elements of the array do not match" do expect { expect([0, 1, 2]).to start_with 1, 2 }.to fail_with("expected [0, 1, 2] to start with 1 and 2") end end context "with an array of strings" do it "passes if given the first element of the array" do expect(%w[ a b c ]).to start_with 'a' end it "passes if given the first n of the array" do expect(%w[ a b c ]).to start_with('a', 'b') end it 'fails if given the wrong first element of the array' do expect { expect(%w[ a b c ]).to start_with 'z' }.to fail_with('expected ["a", "b", "c"] to start with "z"') end end context "with an array of uncustomized structs" do struct = Struct.new(:foo) it 'passes if the array ends with a struct equal to the provided struct' do s1 = struct.new(5) s2 = struct.new(5) expect(s1).to eq(s2) expect([s1, 10]).to start_with(s2) end it 'fails if the array ends with a struct not equal to the provided struct' do s1 = struct.new(5) s2 = struct.new(6) expect(s1).not_to eq(s2) expect { expect([s1, 10]).to start_with(s2) }.to fail_including("expected [#{s1.inspect}, 10] to start with #{s2.inspect}") end end context "with an array of structs that have a custom `==` definition" do my_struct = Struct.new(:id, :fluff) do def ==(other) other.is_a?(self.class) && other.id == id end end it 'passes if the array ends with a struct equal to the provided struct' do s1 = my_struct.new(1, "foo") s2 = my_struct.new(1, "bar") expect(s1).to eq(s2) expect([s1, 10]).to start_with(s2) end it 'fails if the array ends with a struct not equal to the provided struct' do s1 = my_struct.new(1, "foo") s2 = my_struct.new(2, "bar") expect(s1).not_to eq(s2) expect { expect([s1, 10]).to start_with(s2) }.to fail_including("expected [#{s1.inspect}, 10] to start with #{s2.inspect}") end end context "with an object that does not respond to :[]" do it "fails with a useful message" do actual = Object.new expect { expect(actual).to start_with 0 }.to fail_with("expected #{actual.inspect} to start with 0, but it cannot be indexed using #[]") end end context "with a hash" do it "fails with a useful error if trying to match more than one element" do actual = { :a => 'b', :b => 'b', :c => 'c' } expected = { :a => 'b', :b => 'b' } expect { expect(actual).to start_with(expected) }.to fail_with(/\Aexpected #{hash_inspect(actual).gsub(" => ", "=>")} to start with #{hash_inspect(expected).gsub(" => ", "=>")}, but it does not have ordered elements\z/) end end describe "composing with other matchers" do it 'passes if the start of an array matches two given matchers' do expect([1.01, "food", 3]).to start_with(a_value_within(0.2).of(1), a_string_matching(/foo/)) end it 'passes if the start of an array matches one given matcher' do expect([1.01, "food", 3]).to start_with(a_value_within(0.2).of(1)) end it 'provides a description' do description = start_with(a_value_within(0.1).of(1), a_string_matching(/abc/)).description expect(description).to eq("start with a value within 0.1 of 1 and a string matching /abc/") end it 'fails with a clear error message when the matchers do not match' do expect { expect([2.01, "food", 3]).to start_with(a_value_within(0.2).of(1), a_string_matching(/foo/)) }.to fail_with('expected [2.01, "food", 3] to start with a value within 0.2 of 1 and a string matching /foo/') end end end RSpec.describe "expect(...).not_to start_with" do context "with a string" do it "passes if it does not match the start of the actual string" do expect("this string").not_to start_with "that str" end it "fails if it does match the start of the actual string" do expect { expect("this string").not_to start_with "this str" }.to fail_with("expected \"this string\" not to start with \"this str\"") end end context "with an array" do it "passes if it is not the first element of the array" do expect([0, 1, 2]).not_to start_with 2 end it "passes if the first elements of the array do not match" do expect([0, 1, 2]).not_to start_with 1, 2 end it "fails if it matches the first element of the array" do expect { expect([0, 1, 2]).not_to start_with 0 }.to fail_with("expected [0, 1, 2] not to start with 0") end it "fails if it the first elements of the array match" do expect { expect([0, 1, 2]).not_to start_with 0, 1 }.to fail_with("expected [0, 1, 2] not to start with 0 and 1") end end context "with an array of strings" do it "fails if given the first element of the array" do expect { expect(%w[ a b c ]).not_to start_with 'a' }.to fail_with('expected ["a", "b", "c"] not to start with "a"') end it "fails if given the first n of the array" do expect { expect(%w[ a b c ]).not_to start_with('a', 'b') }.to fail_with('expected ["a", "b", "c"] not to start with "a" and "b"') end it 'passes if given the wrong first element of the array' do expect(%w[ a b c ]).not_to start_with 'z' end end it 'can pass when composed with another matcher' do expect(["a"]).not_to start_with(a_string_matching(/bar/)) end it 'can fail when composed with another matcher' do expect { expect(["a"]).not_to start_with(a_string_matching(/a/)) }.to fail_with('expected ["a"] not to start with a string matching /a/') end end RSpec.describe "expect(...).to end_with" do it_behaves_like "an RSpec value matcher", :valid_value => "ab", :invalid_value => "bc" do let(:matcher) { end_with("b") } end context "with a string" do it "passes if it matches the end of the actual string" do expect("this string").to end_with "is string" end it "fails if it does not match the end of the actual string" do expect { expect("this string").to end_with "is stringy" }.to fail_with("expected \"this string\" to end with \"is stringy\"") end end context "with an array" do it "passes if it is the last element of the array" do expect([0, 1, 2]).to end_with 2 end it "passes if the last elements of the array match" do expect([0, 1, 2]).to end_with [1, 2] end it "fails if it does not match the last element of the array" do expect { expect([0, 1, 2]).to end_with 1 }.to fail_with("expected [0, 1, 2] to end with 1") end it "fails if it the last elements of the array do not match" do expect { expect([0, 1, 2]).to end_with [0, 1] }.to fail_with("expected [0, 1, 2] to end with 0 and 1") end end context "with an array of strings" do it "passes if given the last element of the array" do expect(%w[ a b c ]).to end_with 'c' end it "passes if given the last n of the array" do expect(%w[ a b c ]).to end_with('b', 'c') end it 'fails if given the wrong last element of the array' do expect { expect(%w[ a b c ]).to end_with 'z' }.to fail_with('expected ["a", "b", "c"] to end with "z"') end end context "with an array of uncustomized structs" do struct = Struct.new(:foo) it 'passes if the array ends with a struct equal to the provided struct' do s1 = struct.new(5) s2 = struct.new(5) expect(s1).to eq(s2) expect([10, s1]).to end_with(s2) end it 'fails if the array ends with a struct not equal to the provided struct' do s1 = struct.new(5) s2 = struct.new(6) expect(s1).not_to eq(s2) expect { expect([10, s1]).to end_with(s2) }.to fail_including("expected [10, #{s1.inspect}] to end with #{s2.inspect}") end end context "with an array of structs that have a custom `==` definition" do my_struct = Struct.new(:id, :fluff) do def ==(other) other.is_a?(self.class) && other.id == id end end it 'passes if the array ends with a struct equal to the provided struct' do s1 = my_struct.new(1, "foo") s2 = my_struct.new(1, "bar") expect(s1).to eq(s2) expect([10, s1]).to end_with(s2) end it 'fails if the array ends with a struct not equal to the provided struct' do s1 = my_struct.new(1, "foo") s2 = my_struct.new(2, "bar") expect(s1).not_to eq(s2) expect { expect([10, s1]).to end_with(s2) }.to fail_including("expected [10, #{s1.inspect}] to end with #{s2.inspect}") end end context "with an object that does not respond to :[]" do it "fails with a useful message" do actual = Object.new expect { expect(actual).to end_with 0 }.to fail_with("expected #{actual.inspect} to end with 0, but it cannot be indexed using #[]") end end context "with a hash" do it "raises an ArgumentError if trying to match more than one element" do actual = { :a => 'b', :b => 'b', :c => 'c' } expected = { :a => 'b', :b => 'b' } expect { expect(actual).to end_with(expected) }.to fail_with(/\Aexpected #{hash_inspect(actual).gsub(" => ", "=>")} to end with #{hash_inspect(expected).gsub(" => ", "=>")}, but it does not have ordered elements\z/) end end describe "composing with other matchers" do it 'passes if the end of an array matches two given matchers' do expect([3, "food", 1.1]).to end_with(a_string_matching(/foo/), a_value_within(0.2).of(1)) end it 'passes if the end of an array matches one given matcher' do expect([3, "food", 1.1]).to end_with(a_value_within(0.2).of(1)) end it 'provides a description' do description = end_with(a_value_within(0.1).of(1), a_string_matching(/abc/)).description expect(description).to eq("end with a value within 0.1 of 1 and a string matching /abc/") end it 'fails with a clear error message when the matchers do not match' do expect { expect([2.01, 3, "food"]).to end_with(a_value_within(0.2).of(1), a_string_matching(/foo/)) }.to fail_with('expected [2.01, 3, "food"] to end with a value within 0.2 of 1 and a string matching /foo/') end end end RSpec.describe "expect(...).not_to end_with" do context "with a sting" do it "passes if it does not match the end of the actual string" do expect("this string").not_to end_with "stringy" end it "fails if it matches the end of the actual string" do expect { expect("this string").not_to end_with "string" }.to fail_with("expected \"this string\" not to end with \"string\"") end end context "an array" do it "passes if it is not the last element of the array" do expect([0, 1, 2]).not_to end_with 1 end it "passes if the last elements of the array do not match" do expect([0, 1, 2]).not_to end_with [0, 1] end it "fails if it matches the last element of the array" do expect { expect([0, 1, 2]).not_to end_with 2 }.to fail_with("expected [0, 1, 2] not to end with 2") end it "fails if it the last elements of the array match" do expect { expect([0, 1, 2]).not_to end_with [1, 2] }.to fail_with("expected [0, 1, 2] not to end with 1 and 2") end end context "with an array of strings" do it "fails if given the last element of the array" do expect { expect(%w[ a b c ]).not_to end_with 'c' }.to fail_with('expected ["a", "b", "c"] not to end with "c"') end it "fails if given the last n of the array" do expect { expect(%w[ a b c ]).not_to end_with('b', 'c') }.to fail_with('expected ["a", "b", "c"] not to end with "b" and "c"') end it 'passes if given the wrong last element of the array' do expect(%w[ a b c ]).not_to end_with 'z' end end it 'can pass when composed with another matcher' do expect(["a"]).not_to end_with(a_string_matching(/bar/)) end it 'can fail when composed with another matcher' do expect { expect(["a"]).not_to end_with(a_string_matching(/a/)) }.to fail_with('expected ["a"] not to end with a string matching /a/') end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/throw_symbol_spec.rb000066400000000000000000000127701455770000100271740ustar00rootroot00000000000000module RSpec::Matchers::BuiltIn RSpec.describe ThrowSymbol do it_behaves_like "an RSpec block-only matcher" do def valid_block throw :foo end def invalid_block end let(:matcher) { throw_symbol(:foo) } end describe "with no args" do before(:example) { @matcher = throw_symbol } it "matches if any Symbol is thrown" do expect(@matcher.matches?(lambda { throw :sym })).to be_truthy end it "matches if any Symbol is thrown with an arg" do expect(@matcher.matches?(lambda { throw :sym, "argument" })).to be_truthy end it "does not match if no Symbol is thrown" do expect(@matcher.matches?(lambda {})).to be_falsey end it "provides a failure message" do @matcher.matches?(lambda {}) expect(@matcher.failure_message).to eq "expected a Symbol to be thrown, got nothing" end it "provides a negative failure message" do @matcher.matches?(lambda { throw :sym }) expect(@matcher.failure_message_when_negated).to eq "expected no Symbol to be thrown, got :sym" end end describe "with a symbol" do before(:example) { @matcher = throw_symbol(:sym) } it "matches if correct Symbol is thrown" do expect(@matcher.matches?(lambda { throw :sym })).to be_truthy end it "matches if correct Symbol is thrown with an arg" do expect(@matcher.matches?(lambda { throw :sym, "argument" })).to be_truthy end it "does not match if no Symbol is thrown" do expect(@matcher.matches?(lambda {})).to be_falsey end it "does not match if correct Symbol is thrown" do expect(@matcher.matches?(lambda { throw :other_sym })).to be_falsey end it "provides a failure message when no Symbol is thrown" do @matcher.matches?(lambda {}) expect(@matcher.failure_message).to eq "expected :sym to be thrown, got nothing" end it "provides a failure message when wrong Symbol is thrown" do @matcher.matches?(lambda { throw :other_sym }) expect(@matcher.failure_message).to eq "expected :sym to be thrown, got :other_sym" end it "provides a negative failure message" do @matcher.matches?(lambda { throw :sym }) expect(@matcher.failure_message_when_negated).to eq "expected :sym not to be thrown, got :sym" end it "only matches NameErrors raised by uncaught throws" do expect { expect(@matcher.matches?(lambda { sym })).to be_falsey }.to raise_error(NameError) end end describe "with a symbol and an arg" do before(:example) { @matcher = throw_symbol(:sym, "a") } it "matches if correct Symbol and args are thrown" do expect(@matcher.matches?(lambda { throw :sym, "a" })).to be_truthy end it "does not match if nothing is thrown" do expect(@matcher.matches?(lambda {})).to be_falsey end it "does not match if other Symbol is thrown" do expect(@matcher.matches?(lambda { throw :other_sym, "a" })).to be_falsey end it "does not match if no arg is thrown" do expect(@matcher.matches?(lambda { throw :sym })).to be_falsey end it "does not match if wrong arg is thrown" do expect(@matcher.matches?(lambda { throw :sym, "b" })).to be_falsey end it "provides a failure message when no Symbol is thrown" do @matcher.matches?(lambda {}) expect(@matcher.failure_message).to eq 'expected :sym with "a" to be thrown, got nothing' end it "provides a failure message when wrong Symbol is thrown" do @matcher.matches?(lambda { throw :other_sym }) expect(@matcher.failure_message).to eq 'expected :sym with "a" to be thrown, got :other_sym' end it "provides a failure message when wrong arg is thrown" do @matcher.matches?(lambda { throw :sym, "b" }) expect(@matcher.failure_message).to eq 'expected :sym with "a" to be thrown, got :sym with "b"' end it "provides a failure message when no arg is thrown" do @matcher.matches?(lambda { throw :sym }) expect(@matcher.failure_message).to eq 'expected :sym with "a" to be thrown, got :sym with no argument' end it "provides a negative failure message" do @matcher.matches?(lambda { throw :sym }) expect(@matcher.failure_message_when_negated).to eq 'expected :sym with "a" not to be thrown, got :sym with no argument' end it "only matches NameErrors raised by uncaught throws" do expect { expect(@matcher.matches?(lambda { sym })).to be_falsey }.to raise_error(NameError) end it "raises other errors" do expect { @matcher.matches?(lambda { raise "Boom" }) }.to raise_error(/Boom/) end end describe "composing with other matchers" do it 'passes when the matcher matches the thrown arg' do expect { throw :foo, "bar" }.to throw_symbol(:foo, a_string_matching(/bar/)) end it 'fails when the matcher does not match the thrown arg' do expect { expect { throw :foo, "bar" }.to throw_symbol(:foo, a_string_matching(/foo/)) }.to fail_with('expected :foo with a string matching /foo/ to be thrown, got :foo with "bar"') end it 'provides a description' do description = throw_symbol(:foo, a_string_matching(/bar/)).description expect(description).to eq("throw :foo with a string matching /bar/") end end end end rspec-expectations-3.13.0/spec/rspec/matchers/built_in/yield_spec.rb000066400000000000000000000750641455770000100255570ustar00rootroot00000000000000module YieldHelpers # these helpers are prefixed with an underscore to prevent # collisions with the matchers (some of which have the same names) def _dont_yield end def _yield_with_no_args yield end def _yield_with_args(*args) yield(*args) end end class InstanceEvaler def yield_with_no_args(&block) instance_exec(&block) end def yield_with_args(*args, &block) instance_exec(*args, &block) end def each_arg(*args, &block) args.each do |arg| instance_exec(arg, &block) end end end # NOTE: `yield` passes a probe to expect an that probe should be passed # to expectation target. This is different from the other block matchers. # Due to strict requirement in Ruby 1.8 to call a block with arguments if # the block is declared to accept them. To work around this limitation, # this example group overrides the default definition of expectations # and lambdas that take the expectation target in a way that they accept # a probe. RSpec.shared_examples "an RSpec probe-yielding block-only matcher" do |*options| include_examples "an RSpec block-only matcher", { :expects_lambda => true }.merge(options.first || {}) do let(:valid_expectation) { expect { |block| valid_block(&block) } } let(:invalid_expectation) { expect { |block| invalid_block(&block) } } let(:valid_block_lambda) { lambda { |block| valid_block(&block) } } let(:invalid_block_lambda) { lambda { |block| invalid_block(&block) } } end end RSpec.describe "yield_control matcher" do include YieldHelpers extend YieldHelpers it_behaves_like "an RSpec probe-yielding block-only matcher", :failure_message_uses_no_inspect => true do let(:matcher) { yield_control } def valid_block(&block) _yield_with_no_args(&block) end def invalid_block(&block) _dont_yield(&block) end end it 'has a description' do expect(yield_control.description).to eq("yield control") end describe "expect {...}.to yield_control" do it 'passes if the block yields, regardless of the number of yielded arguments or the number of yields' do expect { |b| _yield_with_no_args(&b) }.to yield_control expect { |b| _yield_with_args(1, 2, &b) }.to yield_control expect { |b| 1.upto(10, &b) }.to yield_control end it 'passes if the block yields using instance_exec' do expect { |b| InstanceEvaler.new.yield_with_no_args(&b) }.to yield_control end it 'fails if the block does not yield' do expect { expect { |b| _dont_yield(&b) }.to yield_control }.to fail_with(/expected given block to yield control but/) end it 'fails if the block does not yield the correct number of times' do expect { expect { |b| 0.times.each(&b) }.to yield_control.at_least(:once) }.to fail_with(/expected given block to yield control at least once but did not yield/) expect { expect { |b| 2.times.each(&b) }.to yield_control.at_most(:once) }.to fail_with(/expected given block to yield control at most once but yielded twice/) expect { expect { |b| 1.times.each(&b) }.to yield_control.at_least(:twice) }.to fail_with(/expected given block to yield control at least twice but yielded once/) expect { expect { |b| 3.times.each(&b) }.to yield_control.at_least(:once).at_most(2) }.to fail_with(/expected given block to yield control between 1 and 2 times but yielded 3 times/) expect { expect { |b| 0.times.each(&b) }.to yield_control }.to fail_with(/expected given block to yield control but did not yield/) end it 'does not return a meaningful value from the block' do val = nil expect { |b| val = _yield_with_args(&b) }.to yield_control expect(val).to be_nil end it 'raises an error if given an invalid count argument' do expect { yield_control.exactly('2') }.to raise_error(ArgumentError) expect { yield_control.at_least(:trice_with_typo) }.to raise_error(ArgumentError) expect { yield_control.at_most(nil) }.to raise_error(ArgumentError) expect { yield_control.at_least(2).at_least(1) }.to raise_error(ArgumentError) expect { yield_control.at_most(2).at_most(1) }.to raise_error(ArgumentError) expect { yield_control.at_most(2).at_least(1).at_most(1) }.to raise_error(ArgumentError) expect { yield_control.at_most(1).at_least(2) }.to raise_error(ArgumentError) expect { yield_control.at_least(2).at_most(1) }.to raise_error(ArgumentError) end it 'is supports multiple calls to compatible count constraints' do expect { |b| 1.upto(4, &b) }.to yield_control.at_least(3).at_most(4).times expect { |b| 1.upto(2, &b) }.not_to yield_control.at_least(3).at_most(4).times end it 'raises an error on multiple incompatible calls to count constraints' do expect { yield_control.once.twice }.to raise_error(/multiple/i) end context "with exact count" do it 'fails if the block yields wrong number of times' do expect { expect { |b| [1, 2].each(&b) }.to yield_control.once }.to fail_with(/expected given block to yield control once but yielded twice/) expect { expect { |b| [1, 2, 3].each(&b) }.to yield_control.twice }.to fail_with(/expected given block to yield control twice but yielded 3 times/) expect { expect { |b| [1, 2].each(&b) }.to yield_control.thrice }.to fail_with(/expected given block to yield control 3 times/) end it 'passes if the block yields the specified number of times' do expect { |b| [1].each(&b) }.to yield_control.once expect { |b| [1, 2].each(&b) }.to yield_control.twice expect { |b| [1, 2, 3].each(&b) }.to yield_control.thrice expect { |b| [1, 2, 3, 4].each(&b) }.to yield_control.exactly(4).times end end context "with at_least count" do it 'passes if the block yields the given number of times' do expect { |b| [1, 2].each(&b) }.to yield_control.at_least(2).times expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(3).times end it 'passes if the block yields more times' do expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(2).times expect { |b| [1, 2, 3, 4].each(&b) }.to yield_control.at_least(3).times end it 'allows :once, :twice, and :thrice to be passed as counts' do expect { |b| [1].each(&b) }.to yield_control.at_least(:once) expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:once) expect { expect { |b| [].each(&b) }.to yield_control.at_least(:once) }.to fail_with(/at least once/) expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:twice) expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(:twice) expect { expect { |b| [1].each(&b) }.to yield_control.at_least(:twice) }.to fail_with(/at least twice/) expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_least(:thrice) expect { |b| [1, 2, 3, 4].each(&b) }.to yield_control.at_least(:thrice) expect { expect { |b| [1, 2].each(&b) }.to yield_control.at_least(:thrice) }.to fail_with(/at least 3 times/) end it 'fails if the block yields too few times' do expect { expect { |b| _yield_with_no_args(&b) }.to yield_control.at_least(2).times }.to fail_with(/expected given block to yield control at least twice/) end end context "with at_most count" do it 'passes if the block yields the given number of times' do expect { |b| [1, 2].each(&b) }.to yield_control.at_most(2).times expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(3).times end it 'passes if the block yields fewer times' do expect { |b| [1, 2].each(&b) }.to yield_control.at_most(3).times end it 'allows :once, :twice, and :thrice to be passed as counts' do expect { |b| [1].each(&b) }.to yield_control.at_most(:once) expect { expect { |b| [1, 2].each(&b) }.to yield_control.at_most(:once) }.to fail_with(/expected given block to yield control at most once/) expect { |b| [1, 2].each(&b) }.to yield_control.at_most(:twice) expect { expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(:twice) }.to fail_with(/expected given block to yield control at most twice/) expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(:thrice) expect { expect { |b| [1, 2, 3, 4].each(&b) }.to yield_control.at_most(:thrice) }.to fail_with(/expected given block to yield control at most 3 times/) end it 'fails if the block yields too many times' do expect { expect { |b| [1, 2, 3].each(&b) }.to yield_control.at_most(2).times }.to fail_with(/expected given block to yield control at most twice/) end end end describe "expect {...}.not_to yield_control" do it 'passes if the block does not yield' do expect { |b| _dont_yield(&b) }.not_to yield_control end it 'fails if the block does yield' do expect { expect { |b| _yield_with_no_args(&b) }.not_to yield_control }.to fail_with(/expected given block not to yield control/) end it 'fails if the expect block does not accept an argument', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect {}.not_to yield_control }.to raise_error(/expect block must accept an argument/) end it 'still works when the block uses an arg splat' do expect { |*args| _dont_yield(&args.first) }.not_to yield_control end it 'raises an error if the expect block arg is not passed to a method as a block' do expect { expect { |b| }.not_to yield_control }.to raise_error(/must pass the argument.*as a block/) end end end RSpec.describe "yield_with_no_args matcher" do include YieldHelpers extend YieldHelpers it_behaves_like "an RSpec probe-yielding block-only matcher" do let(:matcher) { yield_with_no_args } def valid_block(&block) _yield_with_no_args(&block) end def invalid_block(&block) _yield_with_args(1, &block) end end it 'has a description' do expect(yield_with_no_args.description).to eq("yield with no args") end it 'does not return a meaningful value from the block' do val = nil expect { |b| val = _yield_with_no_args(&b) }.to yield_with_no_args expect(val).to be_nil end describe "expect {...}.to yield_with_no_args" do it 'passes if the block yields with no args' do expect { |b| _yield_with_no_args(&b) }.to yield_with_no_args end it 'passes if the block yields with no args using instance_exec' do expect { |b| InstanceEvaler.new.yield_with_no_args(&b) }.to yield_with_no_args end it 'fails if the block does not yield' do expect { expect { |b| _dont_yield(&b) }.to yield_with_no_args }.to fail_with(/expected given block to yield with no arguments, but did not yield/) end it 'fails if the block yields with args' do expect { expect { |b| _yield_with_args(1, &b) }.to yield_with_no_args }.to fail_with(/expected given block to yield with no arguments, but yielded with arguments/) end it 'fails if the block yields with arg false' do expect { expect { |b| _yield_with_args(false, &b) }.to yield_with_no_args }.to fail_with(/expected given block to yield with no arguments, but yielded with arguments/) end it 'raises an error if it yields multiple times' do expect { expect { |b| [1, 2].each(&b) }.to yield_with_no_args }.to raise_error(/not designed.*yields multiple times/) end end describe "expect {...}.not_to yield_with_no_args" do it "passes if the block does not yield" do expect { |b| _dont_yield(&b) }.not_to yield_with_no_args end it "passes if the block yields with args" do expect { |b| _yield_with_args(1, &b) }.not_to yield_with_no_args end it "fails if the block yields with no args" do expect { expect { |b| _yield_with_no_args(&b) }.not_to yield_with_no_args }.to fail_with(/expected given block not to yield with no arguments, but did/) end it 'fails if the expect block does not accept an argument', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect {}.not_to yield_with_no_args }.to raise_error(/expect block must accept an argument/) end it 'raises an error if the expect block arg is not passed to a method as a block' do expect { expect { |b| }.not_to yield_with_no_args }.to raise_error(/must pass the argument.*as a block/) end end end RSpec.describe "yield_with_args matcher" do include YieldHelpers extend YieldHelpers it_behaves_like "an RSpec probe-yielding block-only matcher" do let(:matcher) { yield_with_args(1) } def valid_block(&block) _yield_with_args(1, &block) end def invalid_block(&block) _yield_with_args(2, &block) end end it 'has a description' do expect(yield_with_args.description).to eq("yield with args") expect(yield_with_args(1, 3).description).to eq("yield with args(1, 3)") expect(yield_with_args(false).description).to eq("yield with args(false)") end it 'does not return a meaningful value from the block' do val = nil expect { |b| val = _yield_with_args(1, &b) }.to yield_with_args(1) expect(val).to be_nil end describe "expect {...}.to yield_with_args" do it 'passes if the block yields with arguments' do expect { |b| _yield_with_args(1, &b) }.to yield_with_args end it 'passes if the matchers match at yield time only' do expect { |b| val = [] _yield_with_args(val, &b) val << 1 }.to yield_with_args(be_empty) end it 'fails if the block does not yield' do expect { expect { |b| _dont_yield(&b) }.to yield_with_args }.to fail_with(/expected given block to yield with arguments, but did not yield/) end it 'fails if the block yields with no arguments' do expect { expect { |b| _yield_with_no_args(&b) }.to yield_with_args }.to fail_with(/expected given block to yield with arguments, but yielded with no arguments/) end it 'fails if the matchers match at return time only' do expect { expect { |b| val = [1] _yield_with_args(val, &b) val.clear }.to yield_with_args(be_empty) }.to fail_with(dedent <<-EOS) |expected given block to yield with arguments, but yielded with unexpected arguments |expected: [(be empty)] | got: [[1]] EOS end it 'raises an error if it yields multiple times' do expect { expect { |b| [1, 2].each(&b) }.to yield_with_args }.to raise_error(/not designed.*yields multiple times/) end end describe "expect {...}.not_to yield_with_args" do it 'fails if the block yields with arguments' do expect { expect { |b| _yield_with_args(1, &b) }.not_to yield_with_args }.to fail_with(/expected given block not to yield with arguments, but did/) end it 'fails if the matchers match at yield time only' do expect { expect { |b| val = [] _yield_with_args(val, &b) val << 1 }.not_to yield_with_args(be_empty) }.to fail_with(dedent <<-EOS) |expected given block not to yield with arguments, but yielded with expected arguments |expected not: [(be empty)] | got: [[]] EOS end it 'passes if the block does not yield' do expect { |b| _dont_yield(&b) }.not_to yield_with_args end it 'passes if the block yields with no arguments' do expect { |b| _yield_with_no_args(&b) }.not_to yield_with_args end it 'passes if the matchers match at return time only' do expect { |b| val = [1] _yield_with_args(val, &b) val.clear }.not_to yield_with_args(be_empty) end it 'fails if the expect block does not accept an argument', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect {}.not_to yield_with_args }.to raise_error(/expect block must accept an argument/) end it 'raises an error if the expect block arg is not passed to a method as a block' do expect { expect { |b| }.not_to yield_with_args }.to raise_error(/must pass the argument.*as a block/) end end describe "expect {...}.to yield_with_args(3, 17)" do it 'passes if the block yields with the given arguments' do expect { |b| _yield_with_args(3, 17, &b) }.to yield_with_args(3, 17) end it 'passes if the block yields with the given arguments using instance_exec' do expect { |b| InstanceEvaler.new.yield_with_args(3, 17, &b) }.to yield_with_args(3, 17) end it 'fails if the block does not yield' do expect { expect { |b| _dont_yield(&b) }.to yield_with_args(3, 17) }.to fail_with(/expected given block to yield with arguments, but did not yield/) end it 'fails if the block yields with no arguments' do expect { expect { |b| _yield_with_no_args(&b) }.to yield_with_args(3, 17) }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end it 'fails if the block yields with different arguments' do expect { expect { |b| _yield_with_args("a", "b", &b) }.to yield_with_args("a", "c") }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end end describe "expect {...}.to yield_with_args(matcher, matcher)" do it 'passes when the matchers match the args' do expect { |b| _yield_with_args(1.1, "food", &b) }.to yield_with_args(a_value_within(0.2).of(1), a_string_matching(/foo/)) end it 'provides a description' do description = yield_with_args(a_value_within(0.2).of(1), a_string_matching(/foo/)).description expect(description).to eq("yield with args(a value within 0.2 of 1, a string matching /foo/)") end it 'fails with a useful error message when the matchers do not match the args' do expect { expect { |b| _yield_with_args(2.1, "food", &b) }.to yield_with_args(a_value_within(0.2).of(1), a_string_matching(/foo/)) }.to fail_with(dedent <<-EOS) |expected given block to yield with arguments, but yielded with unexpected arguments |expected: [(a value within 0.2 of 1), (a string matching /foo/)] | got: [2.1, "food"] EOS end end describe "expect {...}.not_to yield_with_args(3, 17)" do it 'passes if the block yields with different arguments' do expect { |b| _yield_with_args("a", "b", &b) }.not_to yield_with_args("a", "c") end it 'fails if the block yields with the given arguments' do expect { expect { |b| _yield_with_args("a", "b", &b) }.not_to yield_with_args("a", "b") }.to fail_with(/expected given block not to yield with arguments, but yielded with expected arguments/) end end describe "expect {...}.not_to yield_with_args(matcher, matcher)" do it 'passes when the matchers do not match the args' do expect { |b| _yield_with_args(2.1, "food", &b) }.not_to yield_with_args(a_value_within(0.2).of(1), a_string_matching(/foo/)) end it 'fails with a useful error message when the matchers do not match the args' do expect { expect { |b| _yield_with_args(1.1, "food", &b) }.not_to yield_with_args(a_value_within(0.2).of(1), a_string_matching(/foo/)) }.to fail_with(dedent <<-EOS) |expected given block not to yield with arguments, but yielded with expected arguments |expected not: [(a value within 0.2 of 1), (a string matching /foo/)] | got: [1.1, "food"] EOS end end describe "expect {...}.to yield_with_args( false )" do it 'passes if the block yields with the given arguments' do expect { |b| _yield_with_args(false, &b) }.to yield_with_args(false) end it 'passes if the block yields with the given arguments using instance_exec' do expect { |b| InstanceEvaler.new.yield_with_args(false, &b) }.to yield_with_args(false) end it 'fails if the block does not yield' do expect { expect { |b| _dont_yield(&b) }.to yield_with_args(false) }.to fail_with(/expected given block to yield with arguments, but did not yield/) end it 'fails if the block yields with no arguments' do expect { expect { |b| _yield_with_no_args(&b) }.to yield_with_args(false) }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end it 'fails if the block yields with different arguments' do expect { expect { |b| _yield_with_args(false, &b) }.to yield_with_args(true) }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end end describe "expect {...}.to yield_with_args(/reg/, /ex/)" do it "passes if the block yields strings matching the regexes" do expect { |b| _yield_with_args("regular", "expression", &b) }.to yield_with_args(/reg/, /ex/) end it "fails if the block yields strings that do not match the regexes" do expect { expect { |b| _yield_with_args("no", "match", &b) }.to yield_with_args(/reg/, /ex/) }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end end describe "expect {...}.to yield_with_args(String, Integer)" do it "passes if the block yields objects of the given classes" do expect { |b| _yield_with_args("string", 15, &b) }.to yield_with_args(String, Integer) end it "passes if the block yields the given classes" do expect { |b| _yield_with_args(String, Integer, &b) }.to yield_with_args(String, Integer) end it "fails if the block yields objects of different classes" do expect { expect { |b| _yield_with_args(15, "string", &b) }.to yield_with_args(String, Integer) }.to fail_with(/expected given block to yield with arguments, but yielded with unexpected arguments/) end end end RSpec.describe "yield_successive_args matcher" do include YieldHelpers extend YieldHelpers it_behaves_like "an RSpec probe-yielding block-only matcher" do let(:matcher) { yield_successive_args(1, 2) } def valid_block(&block) [1, 2].each(&block) end def invalid_block(&block) [3, 4].each(&block) end end it 'has a description' do expect(yield_successive_args(1, 3).description).to eq("yield successive args(1, 3)") expect(yield_successive_args([:a, 1], [:b, 2]).description).to eq("yield successive args([:a, 1], [:b, 2])") end it 'does not return a meaningful value from the block' do val = nil expect { |b| val = _yield_with_args(1, &b) }.to yield_successive_args(1) expect(val).to be_nil end it "works correctly when the method yields multiple args each time (passing case)" do expect { |block| ['football', 'barstool'].each_with_index(&block) }.to yield_successive_args( [/foo/, 0], [a_string_starting_with('bar'), 1] ) end it "works correctly when the method yields multiple args each time (failing case)" do expect { expect { |block| ['football', 'barstool'].each_with_index(&block) }.to yield_successive_args( [/foo/, 0], [a_string_starting_with('abr'), 1] ) }.to fail_with(dedent <<-EOS) |expected given block to yield successively with arguments, but yielded with unexpected arguments |expected: [[/foo/, 0], [(a string starting with "abr"), 1]] | got: [["football", 0], ["barstool", 1]] EOS end describe "expect {...}.to yield_successive_args([:a, 1], [:b, 2])" do it 'passes when the block successively yields the given args' do expect { |b| [[:a, 1], [:b, 2]].each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) end it 'passes if matched at yield time only' do expect { |b| [[:a, 1], [:b, 2]].each do |val| _yield_with_args(val, &b) val.clear end }.to yield_successive_args([:a, 1], [:b, 2]) end it 'fails when the block does not yield that many times' do expect { expect { |b| [[:a, 1]].each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) }.to fail_with(/but yielded with unexpected arguments/) end it 'fails when the block yields the right number of times but with different arguments' do expect { expect { |b| [[:a, 1], [:b, 3]].each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) }.to fail_with(/but yielded with unexpected arguments/) end it 'fails if matched at return time only' do expect { expect { |b| [[:a, 1], [:b, 2]].each do |eventual| initial = [] _yield_with_args(initial, &b) initial.concat(eventual) end }.to yield_successive_args([:a, 1], [:b, 2]) }.to fail_with(dedent <<-EOS) |expected given block to yield successively with arguments, but yielded with unexpected arguments |expected: [[:a, 1], [:b, 2]] | got: [[], []] EOS end end describe "expect {...}.to yield_successive_args(1, 2, 3)" do it 'passes when the block successively yields the given args' do expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3) end it 'passes when the block successively yields the given args using instance_exec' do expect { |b| InstanceEvaler.new.each_arg(1, 2, 3, &b) }.to yield_successive_args(1, 2, 3) end it 'fails when the block does not yield the expected args' do expect { expect { |b| [1, 2, 4].each(&b) }.to yield_successive_args([:a, 1], [:b, 2]) }.to fail_with(/but yielded with unexpected arguments/) end end describe "expect {...}.to yield_successive_args(matcher, matcher)" do it 'passes when the successively yielded args match the matchers' do expect { |b| %w[ food barn ].each(&b) }.to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) end it 'fails when the successively yielded args do not match the matchers' do expect { expect { |b| %w[ barn food ].each(&b) }.to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) }.to fail_with(dedent <<-EOS) |expected given block to yield successively with arguments, but yielded with unexpected arguments |expected: [(a string matching /foo/), (a string matching /bar/)] | got: ["barn", "food"] EOS end it 'provides a description' do description = yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)).description expect(description).to eq("yield successive args(a string matching /foo/, a string matching /bar/)") end end describe "expect {...}.not_to yield_successive_args(1, 2, 3)" do it 'passes when the block does not yield' do expect { |b| _dont_yield(&b) }.not_to yield_successive_args(1, 2, 3) end it 'passes when the block yields the wrong number of times' do expect { |b| [1, 2].each(&b) }.not_to yield_successive_args(1, 2, 3) end it 'passes when the block yields the wrong arguments' do expect { |b| [1, 2, 4].each(&b) }.not_to yield_successive_args(1, 2, 3) end it 'fails when the block yields the given arguments' do expect { expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2, 3) }.to fail_with(/expected given block not to yield successively/) end it 'fails if the expect block does not accept an argument', :if => (RUBY_VERSION.to_f > 1.8) do expect { expect {}.not_to yield_successive_args(1, 2, 3) }.to raise_error(/expect block must accept an argument/) end it 'raises an error if the expect block arg is not passed to a method as a block' do expect { expect { |b| }.not_to yield_successive_args(1, 2, 3) }.to raise_error(/must pass the argument.*as a block/) end end describe "expect {...}.not_to yield_successive_args(matcher, matcher)" do it 'passes when the successively yielded args do not match the matchers' do expect { |b| %w[ barn food ].each(&b) }.not_to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) end it 'passes when the successively yielded args do not match the matchers (at yield time only)' do expect { |b| %w[ food barn ].each do |eventual| initial = '' _yield_with_args(initial, &b) initial << eventual end }.not_to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) end it 'fails when the successively yielded args match the matchers' do expect { expect { |b| %w[ food barn ].each(&b) }.not_to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) }.to fail_with(dedent <<-EOS) |expected given block not to yield successively with arguments, but yielded with expected arguments |expected not: [(a string matching /foo/), (a string matching /bar/)] | got: ["food", "barn"] EOS end it 'fails when the successively yielded args match the matchers (at yield time only)' do values = %w[ food barn ].collect { |value| value.dup } expect { expect { |b| values.each do |val| _yield_with_args(val, &b) val.sub!(/.+/, '') end }.not_to yield_successive_args(a_string_matching(/foo/), a_string_matching(/bar/)) }.to fail_with(dedent <<-EOS) |expected given block not to yield successively with arguments, but yielded with expected arguments |expected not: [(a string matching /foo/), (a string matching /bar/)] | got: ["food", "barn"] EOS end end describe "expect {...}.to yield_successive_args(String, Integer)" do it "passes if the block successively yields objects of the given classes" do expect { |b| ["string", 15].each(&b) }.to yield_successive_args(String, Integer) end it "passes if the block yields the given classes" do expect { |b| [String, Integer].each(&b) }.to yield_successive_args(String, Integer) end it "fails if the block yields objects of different classes" do expect { expect { |b| [15, "string"].each(&b) }.to yield_successive_args(String, Integer) }.to fail_with(/expected given block to yield successively with arguments/) end end end rspec-expectations-3.13.0/spec/rspec/matchers/composable_spec.rb000066400000000000000000000100201455770000100247450ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe Composable do RSpec::Matchers.define :matcher_using_surface_descriptions_in do |expected| match { false } failure_message { surface_descriptions_in(expected).to_s } end it "does not blow up when surfacing descriptions from an unreadable IO object" do expect { expect(3).to matcher_using_surface_descriptions_in(STDOUT) }.to fail_with(STDOUT.inspect) end it "does not blow up when surfacing descriptions from an unreadable Range object" do infinity = (1.0/0.0) infinite_range = -infinity..infinity expect { expect(1).to matcher_using_surface_descriptions_in(infinite_range) }.to fail_with(infinite_range.inspect) end it "does not blow up when surfacing descriptions from an Enumerable object whose #each includes the object itself" do array = ['something'] array << array expect { expect(1).to matcher_using_surface_descriptions_in(array) }.to fail_with(array.to_s) end it "does not enumerate normal ranges" do range = 1..3 expect { expect(1).to matcher_using_surface_descriptions_in(range) }.to fail_with(range.inspect) end it "doesn't mangle struct descriptions" do model = Struct.new(:a).new(1) expect { expect(1).to matcher_using_surface_descriptions_in(model) }.to fail_with(model.inspect) end RSpec::Matchers.define :all_but_one do |matcher| match do |actual| match_count = actual.count { |v| values_match?(matcher, v) } actual.size == match_count + 1 end end context "when using a matcher instance that memoizes state multiple times in a composed expression" do it "works properly in spite of the memoization" do expect(["foo", "bar", "a"]).to all_but_one(have_string_length(3)) end context "when passing a compound expression" do it "works properly in spite of the memoization" do expect(["A", "AB", "ABC"]).to all_but_one( have_string_length(1).or have_string_length(2) ) end end end describe "cloning data structures containing matchers" do include Composable it "clones only the contained matchers" do matcher_1 = eq(1) matcher_2 = eq(2) object = Object.new uncloneable = nil data_structure = { "foo" => matcher_1, "bar" => [matcher_2, uncloneable], "bazz" => object } cloned = with_matchers_cloned(data_structure) expect(cloned).not_to equal(data_structure) expect(cloned["foo"]).to be_a_clone_of(matcher_1) expect(cloned["bar"].first).to be_a_clone_of(matcher_2) expect(cloned["bazz"]).to equal(object) end it "copies custom matchers properly so they can work even though they have singleton behavior" do expect("foo").to with_matchers_cloned(have_string_length 3) end it 'does not blow up when passed an array containing an IO object' do stdout = STDOUT expect(with_matchers_cloned([stdout]).first).to equal(stdout) end end describe "when an unexpected call stack jump occurs" do RSpec::Matchers.define :cause_call_stack_jump do supports_block_expectations match do |block| begin block.call false rescue Exception # rubocop:disable Lint/RescueException true end end end it "issue a warning suggesting `expects_call_stack_jump?` has been improperly declared" do expect { x = 0 expect { x += 1; exit }.to change { x }.and cause_call_stack_jump }.to raise_error(/no match results, [\.\w\s]+ declare `expects_call_stack_jump\?`/) end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/define_negated_matcher_spec.rb000066400000000000000000000174221455770000100272620ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe 'RSpec::Matchers.define_negated_matcher' do RSpec::Matchers.define :my_base_non_negated_matcher do match { |actual| actual == foo } def foo 13 end def description "my base matcher description" end end shared_examples "making a copy" do |copy_method| context "when making a copy via `#{copy_method}`" do it "uses a copy of the base matcher" do base_matcher = include(3) aliased = AliasedNegatedMatcher.new(base_matcher, Proc.new {}) copy = aliased.__send__(copy_method) expect(copy).not_to equal(aliased) expect(copy.base_matcher).not_to equal(base_matcher) expect(copy.base_matcher).to be_a(RSpec::Matchers::BuiltIn::Include) expect(copy.base_matcher.expected).to eq([3]) end it "copies custom matchers properly so they can work even though they have singleton behavior" do base_matcher = my_base_non_negated_matcher aliased = AliasedNegatedMatcher.new(base_matcher, Proc.new { |a| a }) copy = aliased.__send__(copy_method) expect(copy).not_to equal(aliased) expect(copy.base_matcher).not_to equal(base_matcher) expect(15).to copy expect { expect(13).to copy }.to fail_with(/expected 13/) end end end include_examples "making a copy", :dup include_examples "making a copy", :clone RSpec::Matchers.define_negated_matcher :an_array_excluding, :include it_behaves_like "an RSpec value matcher", :valid_value => [1, 3], :invalid_value => [1, 2] do let(:matcher) { an_array_excluding(2) } end it 'works properly when composed' do list = 1.upto(10).to_a expect { list.delete(5) }.to change { list }.to(an_array_excluding 5) end describe "the failure message" do context "for a matcher with default failure messages" do RSpec::Matchers.define(:be_awesome) { match(&:awesome?) } RSpec::Matchers.define_negated_matcher :be_lame, :be_awesome context "when failing positively" do it "uses the phrasing from the provided defined matcher alias" do expect { expect(double(:awesome? => true, :inspect => "")).to be_lame }.to fail_with("expected to be lame") end end context "when failing negatively" do it "uses the phrasing from the provided defined matcher alias" do expect { expect(double(:awesome? => false, :inspect => "")).not_to be_lame }.to fail_with("expected not to be lame") end end context "when accessed via an alias that is not included in failure messages" do alias_method :be_fantastic, :be_awesome RSpec::Matchers.define_negated_matcher :be_terrible, :be_fantastic context "when failing positively" do it "uses the wrapped matcher's `failure_message_when_negated`" do expect { expect(double(:awesome? => true, :inspect => "")).to be_terrible }.to fail_with("expected not to be awesome") end end context "when failing negatively" do it "uses the wrapped matcher's `failure_message`" do expect { expect(double(:awesome? => false, :inspect => "")).not_to be_terrible }.to fail_with("expected to be awesome") end end end end context "for a matcher with a customized `failure_message_when_negated`" do RSpec::Matchers.define(:be_tall) do match(&:tall?) failure_message_when_negated do |actual| "expected #{actual.inspect} not to be tall, but was tall" end end RSpec::Matchers.define_negated_matcher :be_short, :be_tall context "when failing positively" do it "uses the wrapped matcher's `failure_message_when_negated` since it may include more detail" do expect { expect(double(:tall? => true, :inspect => "")).to be_short }.to fail_with("expected not to be tall, but was tall") end end context "when failing negatively" do it "uses the wrapped matcher's `failure_message` since it may include more detail" do expect { expect(double(:tall? => false, :inspect => "")).not_to be_short }.to fail_with("expected to be tall") end end end end context 'when no block is passed' do RSpec::Matchers.define :be_an_odd_number do match { |actual| actual.odd? } end RSpec::Matchers.define_negated_matcher :be_an_even_number, :be_an_odd_number it 'uses the default negated description' do expect(be_an_even_number.description).to eq("be an even number") end context "when matched positively" do it 'matches values that fail the original matcher' do expect { expect(22).to be_an_odd_number }.to fail_with("expected 22 to be an odd number") expect(22).to be_an_even_number end it "fails matches against values that pass the original matcher" do expect(21).to be_an_odd_number expect { expect(21).to be_an_even_number }.to fail_with("expected 21 to be an even number") end end context "when matched negatively" do it 'matches values that fail the original matcher' do expect { expect(21).not_to be_an_odd_number }.to fail_with("expected 21 not to be an odd number") expect(21).not_to be_an_even_number end it "fails matches against values that pass the original matcher" do expect(22).not_to be_an_odd_number expect { expect(22).not_to be_an_even_number }.to fail_with("expected 22 not to be an even number") end end end context 'when the negated description is overridden' do RSpec::Matchers.define :be_bigger_than_ten do match { |actual| actual > 10 } end RSpec::Matchers.define_negated_matcher :be_smaller_than_ten, :be_bigger_than_ten do |desc| "#{desc.sub('bigger', 'smaller')} (overridden)" end it 'overrides the description with the provided block' do expect(be_smaller_than_ten.description).to eq("be smaller than ten (overridden)") end it 'overrides the failure message with the provided block' do expect { expect(12).to be_smaller_than_ten }.to fail_with("expected 12 to be smaller than ten (overridden)") end end context "for a matcher that has custom `match_when_negated` logic" do RSpec::Matchers.define :matcher_with_custom_negation do |match_value| match { match_value } match_when_negated { |actual| actual == :does_not_match_true } end RSpec::Matchers.define_negated_matcher :negated_matcher_with_custom_negation, :matcher_with_custom_negation it "uses the `match_when_negated` logic for matching" do expect(:does_not_match_true).to negated_matcher_with_custom_negation(true) expect { expect(:does_not_match_false).to negated_matcher_with_custom_negation(true) }.to fail end it "uses the `match` logic for `expect(..).not_to`" do expect(:foo).not_to negated_matcher_with_custom_negation(true) end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/description_generation_spec.rb000066400000000000000000000162621455770000100273750ustar00rootroot00000000000000RSpec.describe 'a matcher is expected to be able to have its description generated' do after(:example) do RSpec::Matchers.clear_generated_description end example "expect(...).to eq expected" do expect("this").to eq "this" expect(RSpec::Matchers.generated_description).to eq "is expected to eq \"this\"" end example "expect(...).to not eq expected" do expect("this").not_to eq "that" expect(RSpec::Matchers.generated_description).to eq "is expected not to eq \"that\"" end example "expect(...).to be empty (arbitrary predicate)" do expect([]).to be_empty expect(RSpec::Matchers.generated_description).to eq "is expected to be empty" end example "expect(...).to not be empty (arbitrary predicate)" do expect([1]).not_to be_empty expect(RSpec::Matchers.generated_description).to eq "is expected not to be empty" end example "expect(...).to be truthy" do expect(true).to be_truthy expect(RSpec::Matchers.generated_description).to eq "is expected to be truthy" end example "expect(...).to be falsey" do expect(false).to be_falsey expect(RSpec::Matchers.generated_description).to eq "is expected to be falsey" end example "expect(...).to be nil" do expect(nil).to be_nil expect(RSpec::Matchers.generated_description).to eq "is expected to be nil" end example "expect(...).to be > n" do expect(5).to be > 3 expect(RSpec::Matchers.generated_description).to eq "is expected to be > 3" end example "expect(...).to be between min and max" do expect(10).to be_between(0, 10) expect(RSpec::Matchers.generated_description).to eq "is expected to be between 0 and 10 (inclusive)" end example "expect(...).to be exclusively between min and max" do expect(9).to be_between(0, 10).exclusive expect(RSpec::Matchers.generated_description).to eq "is expected to be between 0 and 10 (exclusive)" end example "expect(...).to be predicate arg1, arg2 and arg3" do class Parent; end class Child < Parent def child_of?(*parents) parents.all? { |parent| is_a?(parent) } end end expect(Child.new).to be_a_child_of(Parent, Object) expect(RSpec::Matchers.generated_description).to eq "is expected to be a child of Parent and Object" end example "expect(...).to equal" do expected = "expected" expect(expected).to equal(expected) expect(RSpec::Matchers.generated_description).to eq "is expected to equal \"expected\"" end example "expect(...).not_to equal" do expect(5).not_to equal(37) expect(RSpec::Matchers.generated_description).to eq "is expected not to equal 37" end example "expect(...).to eql" do expect("string").to eql("string") expect(RSpec::Matchers.generated_description).to eq "is expected to eql \"string\"" end example "expect(...).not_to eql" do expect("a").not_to eql(:a) expect(RSpec::Matchers.generated_description).to eq "is expected not to eql :a" end example "expect(...).to have_key" do expect({ :a => "a" }).to have_key(:a) expect(RSpec::Matchers.generated_description).to eq "is expected to have key :a" end example "expect(...).to have_some_method" do object = Object.new def object.has_eyes_closed?; true; end expect(object).to have_eyes_closed expect(RSpec::Matchers.generated_description).to eq 'is expected to have eyes closed' end example "expect(...).to have_some_method(args*)" do object = Object.new def object.has_taste_for?(*_args); true; end expect(object).to have_taste_for("wine", "cheese") expect(RSpec::Matchers.generated_description).to eq 'is expected to have taste for "wine" and "cheese"' end example "expect(...).to include(x)" do expect([1, 2, 3]).to include(3) expect(RSpec::Matchers.generated_description).to eq "is expected to include 3" end example "expect(...).to include(x) when x responds to description but is not a matcher" do obj = double(:description => "description", :inspect => "inspect") expect([obj]).to include(obj) expect(RSpec::Matchers.generated_description).to eq "is expected to include inspect" end example "expect(...).to include(x) when x responds to description and is a matcher" do matcher = double(:description => "description", :matches? => true, :failure_message => "") expect([matcher]).to include(matcher) expect(RSpec::Matchers.generated_description).to eq "is expected to include (description)" end example "expect(array).to contain_exactly(1, 2, 3)" do expect([1, 2, 3]).to contain_exactly(1, 2, 3) expect(RSpec::Matchers.generated_description).to eq "is expected to contain exactly 1, 2, and 3" end example "expect(...).to match" do expect("this string").to match(/this string/) expect(RSpec::Matchers.generated_description).to eq "is expected to match /this string/" end example "expect(...).to raise_error" do expect { raise 'foo' }.to raise_error Exception expect(RSpec::Matchers.generated_description).to eq "is expected to raise Exception" end example "expect(...).to raise_error with class" do expect { raise }.to raise_error(RuntimeError) expect(RSpec::Matchers.generated_description).to eq "is expected to raise RuntimeError" end example "expect(...).to raise_error with class and message" do expect { raise "there was an error" }.to raise_error(RuntimeError, "there was an error") expect(RSpec::Matchers.generated_description).to eq "is expected to raise RuntimeError with \"there was an error\"" end example "expect(...).to respond_to" do expect([]).to respond_to(:insert) expect(RSpec::Matchers.generated_description).to eq "is expected to respond to #insert" end example "expect(...).to throw symbol" do expect { throw :what_a_mess }.to throw_symbol expect(RSpec::Matchers.generated_description).to eq "is expected to throw a Symbol" end example "expect(...).to throw symbol (with named symbol)" do expect { throw :what_a_mess }.to throw_symbol(:what_a_mess) expect(RSpec::Matchers.generated_description).to eq "is expected to throw :what_a_mess" end example "expect(...).to matcher_that_delegates_to_an_internal_expectation" do expect(1).to matcher_that_delegates_to_an_internal_expectation expect(RSpec::Matchers.generated_description).to eq "is expected to matcher that delegates to an internal expectation" end example "expect(...).not_to matcher_that_delegates_to_an_internal_expectation" do expect(1).not_to matcher_that_delegates_to_an_internal_expectation expect(RSpec::Matchers.generated_description).to eq "is expected not to matcher that delegates to an internal expectation" end RSpec::Matchers.define :matcher_that_delegates_to_an_internal_expectation do match { expect(1).to eq(1) } match_when_negated { expect(1).to eq(1) } end end RSpec.describe "a Matcher with no description" do it "provides a helpful message when used in a string-less example block" do matcher = Class.new do def matches?(_ignore); true; end def failure_message; ""; end end.new expect(5).to matcher expect(RSpec::Matchers.generated_description).to match(/When you call.*description method/m) end end rspec-expectations-3.13.0/spec/rspec/matchers/dsl_spec.rb000066400000000000000000001243531455770000100234220ustar00rootroot00000000000000RSpec.describe "a matcher defined using the matcher DSL" do def question? :answer end def ok "ok" end it "supports calling custom matchers from within other custom matchers" do RSpec::Matchers.define :be_ok do match { |actual| actual == ok } end RSpec::Matchers.define :be_well do match { |actual| expect(actual).to be_ok } end expect(ok).to be_well end it "has access to methods available in the scope of the example" do RSpec::Matchers.define(:matcher_a) {} expect(matcher_a.question?).to eq(:answer) end it "raises when method is missing from local scope as well as matcher" do RSpec::Matchers.define(:matcher_b) {} expect { matcher_b.i_dont_exist }.to raise_error(NameError) end if RSpec::Support::RubyFeatures.required_kw_args_supported? binding.eval(<<-CODE, __FILE__, __LINE__) it 'supports the use of required keyword arguments in definition block' do RSpec::Matchers.define(:match_required_kw) do |bar:| match { expect(actual).to eq bar } end expect(1).to match_required_kw(bar: 1) end def kw(a:) a end it "supports the use of required keyword arguments on methods" do RSpec::Matchers.define(:matcher_required_kw_on_method) {} expect(matcher_required_kw_on_method.kw(a: 1)).to eq(1) end CODE end if RSpec::Support::RubyFeatures.kw_args_supported? binding.eval(<<-CODE, __FILE__, __LINE__) it 'supports the use of optional keyword arguments in definition block' do RSpec::Matchers.define(:match_optional_kw) do |bar: nil| match { expect(actual).to eq bar } end expect(1).to match_optional_kw(bar: 1) end def optional_kw(a: nil) a end it "supports the use of optional keyword arguments on methods" do RSpec::Matchers.define(:matcher_optional_kw_on_method) {} expect(matcher_optional_kw_on_method.optional_kw(a: 1)).to eq(1) end CODE end it "clears user instance variables between invocations" do RSpec::Matchers.define(:be_just_like) do |expected| match do |actual| @foo ||= expected @foo == actual end end expect(3).to be_just_like(3) expect(4).to be_just_like(4) end describe '#block_arg' do before(:context) do RSpec::Matchers.define :be_lazily_equal_to do match { actual == block_arg.call } description do "be lazily equal to #{block_arg.call}" end end end it "it is used in a passing condition" do expect(1).to be_lazily_equal_to { 1 } end it "it is used in a failing condition" do expect { expect(1).to be_lazily_equal_to { 2 } }.to fail_with(/be lazily equal to 2/) end end it "warns when passing block to the block of define", :if => (RUBY_VERSION.to_f > 1.8) do expect(RSpec).to receive(:warning).with(/be_warning.*a_block.*block_arg/) RSpec::Matchers.define :be_warning do |&a_block| match { a_block } end end describe "#respond_to?" do it "returns true for methods in example scope" do RSpec::Matchers.define(:matcher_c) {} expect(matcher_c).to respond_to(:question?) end it "returns false for methods not defined in matcher or example scope" do RSpec::Matchers.define(:matcher_d) {} expect(matcher_d).not_to respond_to(:i_dont_exist) end end end class UnexpectedError < StandardError; end module MatcherHelperModule def self.included(base) base.module_exec do def included_method; end end end def self.extended(base) base.instance_exec do def extended_method; end end end def greeting "Hello, World" end end module RSpec::Matchers::DSL RSpec.describe "#alias_matcher" do describe "an alias matcher defined in the current scope" do alias_matcher :be_untrue_in_this_scope, :be_falsy it "is available only in the current scope" do expect(false).to be_untrue_in_this_scope end end describe "an aliased matcher defined in another scope" do it "is not available in the current scope" do expect { expect(false).to be_untrue_in_this_scope }.to fail_with("expected false to respond to `untrue_in_this_scope?`") end end end RSpec.describe "#define_negated_matcher" do describe "a negated matcher defined in the current scope" do define_negated_matcher :be_untrue_in_this_scope, :be_truthy it "is available only in the current scope" do expect(false).to be_untrue_in_this_scope end end describe "a negated matcher defined in another scope" do it "is not available in the current scope" do expect { expect(false).to be_untrue_in_this_scope }.to fail_with("expected false to respond to `untrue_in_this_scope?`") end end end RSpec.describe Matcher do def new_matcher(name, *expected, &block) RSpec::Matchers::DSL::Matcher.new(name, block, self, *expected) end it_behaves_like "an RSpec value matcher", :valid_value => 1, :invalid_value => 2 do let(:matcher) do new_matcher(:equal_to_1) do match { |v| v == 1 } end end end it "can be stored aside and used later" do # Supports using rspec-expectation matchers as argument matchers in # rspec-mocks. RSpec::Matchers.define :example_matcher do |expected| match do |actual| actual == expected end end m1 = example_matcher(1) m2 = example_matcher(2) expect(m1.matches?(1)).to be_truthy expect(m2.matches?(2)).to be_truthy end context 'using deprecated APIs' do before { allow_deprecation } describe "failure_message_for_should" do let(:matcher) do new_matcher(:foo) do match { false } failure_message_for_should { "failed" } end end line = __LINE__ - 3 it 'defines the failure message for a positive expectation' do expect { expect(nil).to matcher }.to fail_with("failed") end it 'prints a deprecation warning' do expect_deprecation_with_call_site(__FILE__, line, /failure_message_for_should/) matcher end end describe "failure_message_for_should_not" do let(:matcher) do new_matcher(:foo) do match { true } failure_message_for_should_not { "failed" } end end line = __LINE__ - 3 it 'defines the failure message for a negative expectation' do expect { expect(nil).not_to matcher }.to fail_with("failed") end it 'prints a deprecation warning' do expect_deprecation_with_call_site(__FILE__, line, /failure_message_for_should_not/) matcher end end describe "match_for_should" do let(:matcher) do new_matcher(:foo) do match_for_should { |arg| arg } end end line = __LINE__ - 3 it 'defines the positive expectation match logic' do expect(true).to matcher expect { expect(false).to matcher }.to fail_with(/foo/) end it 'prints a deprecation warning' do expect_deprecation_with_call_site(__FILE__, line, /match_for_should/) matcher end end describe "match_for_should_not" do let(:matcher) do new_matcher(:foo) do match_for_should_not { |arg| !arg } end end line = __LINE__ - 3 it 'defines the positive expectation match logic' do expect(false).not_to matcher expect { expect(true).not_to matcher }.to fail_with(/foo/) end it 'prints a deprecation warning' do expect_deprecation_with_call_site(__FILE__, line, /match_for_should_not/) matcher end end end context "with an included module" do let(:matcher) do new_matcher(:be_a_greeting) do include MatcherHelperModule match { |actual| actual == greeting } end end it "has access to the module's methods" do matcher.matches?("Hello, World") end it "runs the module's included hook" do expect(matcher).to respond_to(:included_method) end it "does not run the module's extended hook" do expect(matcher).not_to respond_to(:extended_method) end it 'allows multiple modules to be included at once' do m = new_matcher(:multiple_modules) do include Enumerable include Comparable end expect(m).to be_a(Enumerable) expect(m).to be_a(Comparable) end end context "without overrides" do let(:matcher) do new_matcher(:be_a_multiple_of, 3) do |multiple| match do |actual| actual % multiple == 0 end end end it "provides a default description" do expect(matcher.description).to eq "be a multiple of 3" end it "provides a default positive expectation failure message" do expect { expect(8).to matcher }.to fail_with 'expected 8 to be a multiple of 3' end it "provides a default negative expectation failure message" do expect { expect(9).to_not matcher }.to fail_with 'expected 9 not to be a multiple of 3' end end context "without overrides with chained matchers" do let(:matcher) do new_matcher(:be_bigger_than, 5) do |five| match do |to_match| (to_match > five) && smaller_than_ceiling?(to_match) && divisible_by_divisor?(to_match) end match_when_negated do |to_match| (to_match <= five) || greater_than_ceiling(to_match) && not_divisible_by_divisor?(to_match) end chain :and_smaller_than do |ceiling| @ceiling = ceiling end chain :and_divisible_by do |divisor| @divisor = divisor end private def smaller_than_ceiling?(to_match) to_match < @ceiling end def greater_than_ceiling(to_match) to_match >= @ceiling end def divisible_by_divisor?(to_match) @divisor % to_match == 0 end def not_divisible_by_divisor?(to_match) @divisor % to_match != 0 end end end context "when the matchers are chained" do include_context "isolate include_chain_clauses_in_custom_matcher_descriptions" context "without include_chain_clauses_in_custom_matcher_descriptions configured" do before { RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions = false } let(:match) { matcher.and_smaller_than(10).and_divisible_by(3) } it "provides a default description that does not include any of the chained matchers' descriptions" do expect(match.description).to eq 'be bigger than 5' end it "provides a default positive expectation failure message that does not include any of the chained matchers' descriptions" do expect { expect(8).to match }.to fail_with 'expected 8 to be bigger than 5' end it "provides a default negative expectation failure message that does not include the any of the chained matchers's descriptions" do expect { expect(9).to_not match }.to fail_with 'expected 9 not to be bigger than 5' end end context "with include_chain_clauses_in_custom_matcher_descriptions configured to be true" do before do expect(RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions?).to be true end it "provides a default description that includes the chained matchers' descriptions in they were used" do expect(matcher.and_divisible_by(3).and_smaller_than(29).and_smaller_than(20).and_divisible_by(5).description).to \ eq 'be bigger than 5 and divisible by 3 and smaller than 29 and smaller than 20 and divisible by 5' end it "provides a default positive expectation failure message that includes the chained matchers' failures" do expect { expect(30).to matcher.and_smaller_than(29).and_divisible_by(3) }.to \ fail_with 'expected 30 to be bigger than 5 and smaller than 29 and divisible by 3' end it "provides a default negative expectation failure message that includes the chained matchers' failures" do expect { expect(21).to_not matcher.and_smaller_than(29).and_divisible_by(3) }.to \ fail_with 'expected 21 not to be bigger than 5 and smaller than 29 and divisible by 3' end end it 'only decides if to include the chained clauses at the time description is invoked' do matcher.and_divisible_by(3) expect { RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions = false }.to change { matcher.description }. from('be bigger than 5 and divisible by 3'). to('be bigger than 5') end end end context "with separate match logic for positive and negative expectations" do let(:matcher) do new_matcher(:to_be_composed_of, 7, 11) do |a, b| match do |actual| actual == a * b end match_when_negated do |actual| actual == a + b end end end it "invokes the match block for #matches?" do expect(matcher.matches?(77)).to be_truthy expect(matcher.matches?(18)).to be_falsey end it "invokes the match_when_negated block for #does_not_match?" do expect(matcher.does_not_match?(77)).to be_falsey expect(matcher.does_not_match?(18)).to be_truthy end it "provides a default failure message for negative expectations" do matcher.does_not_match?(77) expect(matcher.failure_message_when_negated).to eq "expected 77 not to to be composed of 7 and 11" end it 'can access helper methods from `match_when_negated`' do matcher = new_matcher(:be_foo) do def foo :foo end match_when_negated do |actual| actual != foo end end expect(matcher.does_not_match?(:bar)).to be true end end it "allows helper methods to be defined with #define_method to have access to matcher parameters" do matcher = new_matcher(:name, 3, 4) do |a, b| define_method(:sum) { a + b } end expect(matcher.sum).to eq 7 end it "is not diffable by default" do matcher = new_matcher(:name) {} expect(matcher).not_to be_diffable end it "is diffable when told to be" do matcher = new_matcher(:name) { diffable } expect(matcher).to be_diffable end it 'handles multiline string diffs' do actual = "LINE1\nline2\n" expected = "line1\nline2\n" matcher = new_matcher(:custom_match, expected) do match { |act| act == expected } diffable end diff = nil begin allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false) expect(actual).to matcher rescue RSpec::Expectations::ExpectationNotMetError => e diff = e.message.sub(/\A.*Diff:/m, "Diff:").gsub(/^\s*/, '') end if Diff::LCS::VERSION.to_f < 1.4 expected_diff = "Diff:\n@@ -1,3 +1,3 @@\n-line1\n+LINE1\nline2\n" else expected_diff = "Diff:\n@@ -1 +1 @@\n-line1\n+LINE1\n" end expect(diff).to eq expected_diff end it 'does not confuse the diffability of different matchers' do # Necessary to guard against a regression that involved # using a class variable to store the diffable state, # which had the side effect of causing all custom matchers # to share that state m1 = new_matcher(:m1) { diffable } m2 = new_matcher(:m2) {} m3 = new_matcher(:m3) { diffable } expect(m1).to be_diffable expect(m2).not_to be_diffable expect(m3).to be_diffable end it "provides expected" do matcher = new_matcher(:name, "expected string") {} expect(matcher.expected).to eq 'expected string' end it "provides expected when there is more than one argument" do matcher = new_matcher(:name, "expected string", "another arg") {} expect(matcher.expected).to eq ['expected string', "another arg"] end it "provides expected_as_array which returns an array regardless of expected" do matcher = new_matcher(:name, "expected string") {} expect(matcher.expected_as_array).to eq ['expected string'] matcher = new_matcher(:name, "expected\nstring") {} expect(matcher.expected_as_array).to eq ["expected\nstring"] matcher = new_matcher(:name, "expected string", "another arg") {} expect(matcher.expected_as_array).to eq ['expected string', "another arg"] end it "provides actual when `match` is used" do matcher = new_matcher(:name, 'expected string') do match { |actual| } end matcher.matches?('actual string') expect(matcher.actual).to eq 'actual string' end it "provides actual when the `match` block accepts splat args" do matcher = new_matcher(:actual) do match { |*actual| actual == [5] } end expect(matcher.matches?(5)).to be true expect(matcher.matches?(4)).to be false end it 'allows an early `return` to be used from a `match` block' do matcher = new_matcher(:with_return, 5) do |expected| match { |actual| return true if expected == actual } end expect(matcher.matches?(5)).to be true expect(matcher.matches?(4)).to be_falsey end it 'provides actual when `match_unless_raises` is used' do matcher = new_matcher(:name, 'expected string') do match_unless_raises(SyntaxError) { |actual| } end matcher.matches?('actual string') expect(matcher.actual).to eq 'actual string' end it 'allows an early `return` to be used from a `match_unless_raises` block' do matcher = new_matcher(:with_return) do match_unless_raises(ArgumentError) do |actual| return actual if [true, false].include?(actual) raise ArgumentError end end expect(matcher.matches?(true)).to be true # It should match even if it returns false, because no error was raised. expect(matcher.matches?(false)).to be true expect(matcher.matches?(4)).to be_falsey end it 'provides actual when `match_when_negated` is used' do matcher = new_matcher(:name, 'expected string') do match_when_negated { |actual| } end matcher.does_not_match?('actual string') expect(matcher.actual).to eq 'actual string' end it 'allows an early `return` to be used from a `match_when_negated` block' do matcher = new_matcher(:with_return, 5) do |expected| match_when_negated { |actual| return true if expected != actual } end expect(matcher.does_not_match?(5)).to be_falsey expect(matcher.does_not_match?(4)).to be true end context "wrapping another expectation in a `match` block" do context "with a positive expectation" do let(:matcher) do new_matcher(:name, "value") do |expected| match do |actual| expect(actual).to eq expected end end end specify "`match?` returns true if the wrapped expectation passes" do expect(matcher.matches?('value')).to be_truthy end specify "`match?` returns false if the wrapped expectation fails" do expect(matcher.matches?('other value')).to be_falsey end end context "with a negative expectation" do let(:matcher) do new_matcher(:name, "purposely_the_same") do |expected| match do |actual| expect(actual).not_to eq expected end end end specify "`match?` returns true if the wrapped expectation passes" do expect(matcher.matches?('purposely_different')).to be_truthy end specify "`match?` returns false if the wrapped expectation fails" do expect(matcher.matches?('purposely_the_same')).to be_falsey end end it "can use the `include` matcher from a `match` block" do RSpec::Matchers.define(:descend_from) do |mod| match do |klass| expect(klass.ancestors).to include(mod) end end expect(Integer).to descend_from(Object) expect(Integer).not_to descend_from(Array) expect { expect(Integer).to descend_from(Array) }.to fail_with(/expected Integer to descend from Array/) expect { expect(Integer).not_to descend_from(Object) }.to fail_with(/expected Integer not to descend from Object/) end it "can use the `match` matcher from a `match` block" do RSpec::Matchers.define(:be_a_phone_number_string) do match do |string| expect(string).to match(/\A\d{3}\-\d{3}\-\d{4}\z/) end end expect("206-123-1234").to be_a_phone_number_string expect("foo").not_to be_a_phone_number_string expect { expect("foo").to be_a_phone_number_string }.to fail_with(/expected "foo" to be a phone number string/) expect { expect("206-123-1234").not_to be_a_phone_number_string }.to fail_with(/expected "206-123-1234" not to be a phone number string/) end context "when used within an `aggregate_failures` block" do it 'does not aggregate the inner expectation failure' do use_an_internal_expectation = new_matcher(:use_an_internal_expectation) do match do |actual| expect(actual).to end_with "z" end end expect { aggregate_failures do expect(1).to be_even expect("foo").to use_an_internal_expectation end }.to fail do |error| expect(error).to have_attributes(:failures => [ an_object_having_attributes(:message => "expected `1.even?` to return true, got false"), an_object_having_attributes(:message => 'expected "foo" to use an internal expectation') ]) end end it 'does not aggregate the inner expectation failure (negation)' do use_an_internal_expectation = new_matcher(:use_an_internal_expectation) do match_when_negated do |actual| expect(actual).not_to end_with "o" end end expect { aggregate_failures do expect(1).to be_even expect("foo").not_to use_an_internal_expectation end }.to fail do |error| expect(error).to have_attributes(:failures => [ an_object_having_attributes(:message => "expected `1.even?` to return true, got false"), an_object_having_attributes(:message => 'expected "foo" not to use an internal expectation') ]) end end it 'still raises the expectation failure internally in case the matcher relies upon rescuing the error' do error_rescued = false rescue_failure = new_matcher(:rescue_failure) do match do |actual| begin expect(actual).to eq(2) rescue RSpec::Expectations::ExpectationNotMetError error_rescued = true end end end begin aggregate_failures do expect(1).to rescue_failure end rescue RSpec::Expectations::ExpectationNotMetError # rubocop:disable Lint/SuppressedException end expect(error_rescued).to be true end end end context "wrapping another expectation in a `match_when_negated` block" do context "with a positive expectation" do let(:matcher) do new_matcher(:name, "purposely_the_same") do |expected| match_when_negated do |actual| expect(actual).to eq expected end end end specify "`does_not_match?` returns true if the wrapped expectation passes" do expect(matcher.does_not_match?('purposely_the_same')).to be_truthy end specify "`does_not_match?` returns false if the wrapped expectation fails" do expect(matcher.does_not_match?('purposely_different')).to be_falsey end end context "with a negative expectation" do let(:matcher) do new_matcher(:name, "value") do |expected| match_when_negated do |actual| expect(actual).not_to eq expected end end end specify "`does_not_match?` returns true if the wrapped expectation passes" do expect(matcher.does_not_match?('other value')).to be_truthy end specify "`does_not_match?` returns false if the wrapped expectation fails" do expect(matcher.does_not_match?('value')).to be_falsey end end end context "with overrides" do let(:matcher) do new_matcher(:be_boolean, true) do |boolean| match do |actual| actual end description do |actual| "be the boolean #{boolean} (actual was #{actual})" end failure_message do |actual| "expected #{actual} to be the boolean #{boolean}" end failure_message_when_negated do |actual| "expected #{actual} not to be the boolean #{boolean}" end end end it "does not hide result of match block when true" do expect(matcher.matches?(true)).to be_truthy end it "does not hide result of match block when false" do expect(matcher.matches?(false)).to be_falsey end it "overrides the description (which yields `actual`)" do matcher.matches?(true) expect(matcher.description).to eq "be the boolean true (actual was true)" end it "overrides the failure message for positive expectations" do matcher.matches?(false) expect(matcher.failure_message).to eq "expected false to be the boolean true" end it "overrides the failure message for negative expectations" do matcher.matches?(true) expect(matcher.failure_message_when_negated).to eq "expected true not to be the boolean true" end it 'can access helper methods from `description`' do matcher = new_matcher(:desc) do def subdesc() "sub description" end description { "Desc (#{subdesc})" } end expect(matcher.description).to eq("Desc (sub description)") end it 'can access helper methods from `failure_message`' do matcher = new_matcher(:positive_failure_message) do def helper() "helper" end failure_message { helper } end expect(matcher.failure_message).to eq("helper") end it 'can access helper methods from `failure_message_when_negated`' do matcher = new_matcher(:negative_failure_message) do def helper() "helper" end failure_message_when_negated { helper } end expect(matcher.failure_message_when_negated).to eq("helper") end it 'can exit early with a `return` from `description` just like in a method' do matcher = new_matcher(:desc) do description { return "Desc" } end expect(matcher.description).to eq("Desc") end it 'can exit early with a `return` from `failure_message` just like in a method' do matcher = new_matcher(:positive_failure_message) do failure_message { return "msg" } end expect(matcher.failure_message).to eq("msg") end it 'can exit early with a `return` from `failure_message_when_negated` just like in a method' do matcher = new_matcher(:negative_failure_message) do failure_message_when_negated { return "msg" } end expect(matcher.failure_message_when_negated).to eq("msg") end end context "with description override and chained matcher" do context "by default" do let(:matcher) do new_matcher(:be_even) do match do |to_match| to_match.even? && (to_match % @divisible_by == 0) end chain :and_divisible_by do |divisible_by| @divisible_by = divisible_by end description { super() + " and divisible by #{@divisible_by}" } end end context "with include_chain_clauses_in_custom_matcher_descriptions configured to false" do include_context "isolate include_chain_clauses_in_custom_matcher_descriptions" before { RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions = false } it "provides a default description that does not include any of the chained matchers' descriptions" do expect(matcher.and_divisible_by(10).description).to eq 'be even and divisible by 10' end end context "with include_chain_clauses_in_custom_matcher_descriptions configured to true" do it "provides a default description that does includes the chained matchers' descriptions" do expect(matcher.and_divisible_by(10).description).to eq 'be even and divisible by 10 and divisible by 10' end end end end context "matching blocks" do it 'cannot match blocks by default' do matcher = new_matcher(:foo) { match { true } } expect(3).to matcher expect { expect { 3 }.to matcher }.to fail_with(/must pass an argument/) end it 'can match blocks if it declares `supports_block_expectations`' do matcher = new_matcher(:foo) do match { true } supports_block_expectations end expect(3).to matcher expect { 3 }.to matcher end it 'will not swallow expectation errors from blocks when told to' do matcher = new_matcher(:foo) do match(:notify_expectation_failures => true) do |actual| actual.call true end supports_block_expectations end expect { expect { raise RSpec::Expectations::ExpectationNotMetError.new('original') }.to matcher }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /original/) end end context "matching blocks when negated" do it 'cannot match blocks by default' do matcher = new_matcher(:foo) { match_when_negated { true } } expect(3).to_not matcher expect { expect { 3 }.to_not matcher }.to fail_with(/must pass an argument/) end it 'can match blocks if it declares `supports_block_expectations`' do matcher = new_matcher(:foo) do match_when_negated { true } supports_block_expectations end expect(3).to_not matcher expect { 3 }.to_not matcher end it 'will not swallow expectation errors from blocks when told to' do matcher = new_matcher(:foo) do match_when_negated(:notify_expectation_failures => true) do |actual| actual.call true end supports_block_expectations end expect { expect { raise RSpec::Expectations::ExpectationNotMetError.new('original') }.to_not matcher }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /original/) end end context "#new" do it "passes matches? arg to match block" do matcher = new_matcher(:ignore) do match do |actual| actual == 5 end end expect(matcher.matches?(5)).to be_truthy end it "exposes arg submitted through #new to matcher block" do matcher = new_matcher(:ignore, 4) do |expected| match do |actual| actual > expected end end expect(matcher.matches?(5)).to be_truthy end end context "with no args" do let(:matcher) do new_matcher(:matcher_name) do match do |actual| actual == 5 end end end it "matches" do expect(matcher.matches?(5)).to be_truthy end it "describes" do expect(matcher.description).to eq "matcher name" end end context "with 1 arg" do let(:matcher) do new_matcher(:matcher_name, 1) do |expected| match do |actual| actual == 5 && expected == 1 end end end it "matches" do expect(matcher.matches?(5)).to be_truthy end it "describes" do expect(matcher.description).to eq "matcher name 1" end end context "with multiple args" do let(:matcher) do new_matcher(:matcher_name, 1, 2, 3, 4) do |a, b, c, d| match do |sum| a + b + c + d == sum end end end it "matches" do expect(matcher.matches?(10)).to be_truthy end it "describes" do expect(matcher.description).to eq "matcher name 1, 2, 3, and 4" end end it "supports helper methods" do matcher = new_matcher(:be_similar_to, [1, 2, 3]) do |sample| match do |actual| similar?(sample, actual) end def similar?(a, b) a.sort == b.sort end end expect(matcher.matches?([2, 3, 1])).to be_truthy end it "supports fluent interface" do matcher = new_matcher(:first_word) do def second_word self end end expect(matcher.second_word).to eq matcher end it "treats method missing normally for undeclared methods" do matcher = new_matcher(:ignore) {} expect { matcher.non_existent_method }.to raise_error(NoMethodError) end it "has access to other matchers" do matcher = new_matcher(:ignore, 3) do |expected| match do |actual| extend RSpec::Matchers expect(actual).to eql(5 + expected) end end expect(matcher.matches?(8)).to be_truthy end context 'when multiple instances of the same matcher are used in the same example' do RSpec::Matchers.define(:be_like_a) do |expected| match { |actual| actual == expected } description { "be like a #{expected}" } failure_message { "expected to be like a #{expected}" } failure_message_when_negated { "expected not to be like a #{expected}" } end # Note: these bugs were only exposed when creating both instances # first, then checking their descriptions/failure messages. # # That's why we eager-instantiate them here. let!(:moose) { be_like_a("moose") } let!(:horse) { be_like_a("horse") } it 'allows them to use the expected value in the description' do expect(horse.description).to eq("be like a horse") expect(moose.description).to eq("be like a moose") end it 'allows them to use the expected value in the positive failure message' do expect(moose.failure_message).to eq("expected to be like a moose") expect(horse.failure_message).to eq("expected to be like a horse") end it 'allows them to use the expected value in the negative failure message' do expect(moose.failure_message_when_negated).to eq("expected not to be like a moose") expect(horse.failure_message_when_negated).to eq("expected not to be like a horse") end it 'allows them to match separately' do expect("moose").to moose expect("horse").to horse expect("horse").not_to moose expect("moose").not_to horse end end describe "#match_unless_raises" do context "with an assertion" do mod = Module.new do def assert_equal(a, b) raise UnexpectedError.new("#{b} does not equal #{a}") unless a == b end end let(:matcher) do new_matcher(:equal, 4) do |expected| include mod match_unless_raises UnexpectedError do assert_equal expected, actual end end end context "with passing assertion" do it "passes" do expect(matcher.matches?(4)).to be_truthy end end context "with failing assertion" do it "fails" do expect(matcher.matches?(5)).to be_falsey end it "provides the raised exception" do matcher.matches?(5) expect(matcher.rescued_exception.message).to eq("5 does not equal 4") end end end context "with an unexpected error" do it "raises the error" do matcher = new_matcher(:foo, :bar) do |_expected| match_unless_raises SyntaxError do |_actual| raise "unexpected exception" end end expect { matcher.matches?(:bar) }.to raise_error("unexpected exception") end end context "without a specified error class" do let(:matcher) do new_matcher(:foo) do match_unless_raises do |actual| raise Exception unless actual == 5 end end end it 'passes if no error is raised' do expect(matcher.matches?(5)).to be true end it 'fails if an exception is raised' do expect(matcher.matches?(4)).to be false end end end it "can define chainable methods" do matcher = new_matcher(:name) do chain(:expecting) do |expected_value| @expected_value = expected_value end match { |actual| actual == @expected_value } end expect(matcher.expecting('value').matches?('value')).to be_truthy expect(matcher.expecting('value').matches?('other value')).to be_falsey end it "can define chainable setters" do matcher = new_matcher(:name) do chain(:expecting, :expected_value) match { |actual| actual == expected_value } end expect(matcher.expecting('value').matches?('value')).to be_truthy expect(matcher.expecting('value').matches?('other value')).to be_falsey end it "can define chainable setters for several attributes" do matcher = new_matcher(:name) do chain(:expecting, :expected_value, :min_value, :max_value) match { |actual| actual == expected_value && actual >= min_value && actual <= max_value } end expect(matcher.expecting('value', 'apple', 'zebra').matches?('value')).to be_truthy expect(matcher.expecting('value', 'apple', 'zebra').matches?('other value')).to be_falsey expect(matcher.expecting('other value', 'parrot', 'zebra').matches?('other value')).to be_falsey end it "raises when neither a `chain` block nor attribute name is provided" do expect do new_matcher(:name) do chain(:expecting) end end.to raise_error(ArgumentError) end it "raises when both a `chain` block and attribute name are provided" do expect do new_matcher(:name) do chain(:expecting, :expected_value) do |expected_value| @expected_value = expected_value end end end.to raise_error(ArgumentError) end it 'can use an early return from a `chain` block' do matcher = new_matcher(:name) do chain(:expecting) do |expected_value| @expected_value = expected_value return end match { |actual| actual == @expected_value } end expect(matcher.expecting('value').matches?('value')).to be_truthy expect(matcher.expecting('value').matches?('other value')).to be_falsey end it 'allows chainable methods to accept blocks' do matcher = new_matcher(:name) do chain(:for_block) { |&b| @block = b } match { |value| @block.call == value } end expect(matcher.for_block { 5 }.matches?(5)).to be true expect(matcher.for_block { 3 }.matches?(4)).to be false end it "prevents name collisions on chainable methods from different matchers" do m1 = new_matcher(:m1) { chain(:foo) { raise "foo in m1" } } m2 = new_matcher(:m2) { chain(:foo) { raise "foo in m2" } } expect { m1.foo }.to raise_error("foo in m1") expect { m2.foo }.to raise_error("foo in m2") end context "defined using the dsl" do def a_method_in_the_example "method defined in the example" end it "can access methods in the running example" do |example| RSpec::Matchers.define(:__access_running_example) do match do |_actual| a_method_in_the_example == "method defined in the example" end end expect(example).to __access_running_example end it 'can get a method object for methods in the running example', :if => (RUBY_VERSION.to_f > 1.8) do matcher = new_matcher(:get_method_object) {} method = matcher.method(:a_method_in_the_example) expect(method.call).to eq("method defined in the example") end it 'indicates that it responds to a method from the running example' do matcher = new_matcher(:respond_to) {} expect(matcher).to respond_to(:a_method_in_the_example) expect(matcher).not_to respond_to(:a_method_not_in_the_example) end it "raises NoMethodError for methods not in the running_example" do |example| RSpec::Matchers.define(:__raise_no_method_error) do match do |_actual| self.a_method_not_in_the_example == "method defined in the example" # rubocop:disable Style/RedundantSelf RuboCop bug, should disappear on version update end end expected_msg = "RSpec::Matchers::DSL::Matcher" expected_msg = "#{expected_msg} __raise_no_method_error" unless rbx? || RUBY_VERSION.to_f > 3.2 expect { expect(example).to __raise_no_method_error }.to raise_error(NoMethodError, /#{expected_msg}/) end def rbx? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' end end end end rspec-expectations-3.13.0/spec/rspec/matchers/english_phrasing_spec.rb000066400000000000000000000054011455770000100261540ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe EnglishPhrasing do describe ".split_words" do it "replaces underscores with spaces" do expect( described_class.split_words(:banana_creme_pie) ).to eq("banana creme pie") end it "first casts its argument to string" do arg = double(:to_s => "banana") expect(described_class.split_words(arg)).to eq("banana") end end describe ".list" do context "given nil" do it "returns value from inspect, and a leading space" do expect(described_class.list(nil)).to eq(" nil") end end context "given a Struct" do it "returns value from inspect, and a leading space" do banana = Struct.new("Banana", :flavor).new expect( described_class.list(banana) ).to eq(" #{banana.inspect}") end end context "given a Hash" do it "returns value from inspect, and a leading space" do banana = { :flavor => 'Banana' } expect( described_class.list(banana) ).to eq(" #{banana.inspect}") end end context "given an Enumerable other than a Hash" do before do allow(RSpec::Support::ObjectFormatter).to( receive(:format).and_return("Banana") ) end context "with zero items" do it "returns the empty string" do expect(described_class.list([])).to eq("") end end context "with one item" do let(:list) { [double] } it "returns description, and a leading space" do expect(described_class.list(list)).to eq(" Banana") expect(RSpec::Support::ObjectFormatter).to( have_received(:format).once ) end end context "with two items" do let(:list) { [double, double] } it "returns descriptions, and a leading space" do expect(described_class.list(list)).to eq(" Banana and Banana") expect(RSpec::Support::ObjectFormatter).to( have_received(:format).twice ) end end context "with three items" do let(:list) { [double, double, double] } it "returns descriptions, and a leading space" do expect( described_class.list(list) ).to eq(" Banana, Banana, and Banana") expect(RSpec::Support::ObjectFormatter).to( have_received(:format).exactly(3).times ) end end end end end end end rspec-expectations-3.13.0/spec/rspec/matchers/legacy_spec.rb000066400000000000000000000074601455770000100241030ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe "Legacy matchers" do it 'still provides a `LegacyMacherAdapter` constant because 3.0 was released with ' \ 'it and it would be a SemVer violation to remove it before 4.0' do expect(Expectations::LegacyMacherAdapter).to be(Expectations::LegacyMatcherAdapter) end shared_examples "a matcher written against a legacy protocol" do |matcher_class| matcher = matcher_class.new before { allow_deprecation } backwards_compat_matcher = Class.new(matcher_class) do def failure_message; "failure when positive"; end def failure_message_when_negated; "failure when negative"; end end.new it 'is still considered to be a matcher' do expect(Matchers.is_a_matcher?(matcher)).to be true end context 'when matched positively' do it 'returns the positive expectation failure message' do expect { expect(false).to matcher }.to fail_with("failure when positive") end it 'warns about the deprecated protocol' do expect_warn_deprecation(/legacy\s+RSpec\s+matcher.+#{__FILE__}:#{__LINE__ + 1}/m) expect(true).to matcher end it 'does not warn when it also defines the current methods (i.e. to be compatible on multiple RSpec versions)' do expect_no_deprecations expect { expect(false).to backwards_compat_matcher }.to fail_with("failure when positive") end end context 'when matched negatively' do it 'returns the negative expectation failure message' do expect { expect(true).not_to matcher }.to fail_with("failure when negative") end it 'warns about the deprecated protocol' do expect_warn_deprecation(/legacy\s+RSpec\s+matcher.+#{__FILE__}:#{__LINE__ + 1}/m) expect(false).not_to matcher end it 'does not warn when it also defines the current methods (i.e. to be compatible on multiple RSpec versions)' do expect_no_deprecations expect { expect(true).not_to backwards_compat_matcher }.to fail_with("failure when negative") end def pending_on_rbx return unless defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' pending "intermittently fails on RBX due to https://github.com/rubinius/rubinius/issues/2845" end it 'calls `does_not_match?` if it is defined on the matcher' do pending_on_rbx called = false with_does_not_match = Class.new(matcher_class) do define_method(:does_not_match?) { |actual| called = true; !actual } end.new expect(false).not_to with_does_not_match expect(called).to be true end end end context "written using the RSpec 2.x `failure_message_for_should` and `failure_message_for_should_not` protocol" do matcher_class = Class.new do def matches?(actual); actual; end def failure_message_for_should; "failure when positive"; end def failure_message_for_should_not; "failure when negative"; end end it_behaves_like "a matcher written against a legacy protocol", matcher_class end context "written using the older `failure_message` and `negative_failure_message` protocol" do matcher_class = Class.new do def matches?(actual); actual; end def failure_message; "failure when positive"; end def negative_failure_message; "failure when negative"; end end it_behaves_like "a matcher written against a legacy protocol", matcher_class end end end end rspec-expectations-3.13.0/spec/rspec/matchers/multi_matcher_diff_spec.rb000066400000000000000000000102571455770000100264620ustar00rootroot00000000000000module RSpec module Matchers RSpec.describe MultiMatcherDiff do before do stub_const("::RSpec::Matchers::MultiMatcherDiff::DESCRIPTION_MAX_LENGTH", 30) end class FakeDiffer def self.diff(actual, expected) [actual, expected].inspect end end let(:differ) { FakeDiffer } let(:message) { "a message" } let(:actual) { "actual value" } let(:wrapped_value) { described_class.from("expected value", actual) } def create_matcher(stubs) instance_double(BuiltIn::BaseMatcher, stubs.merge( :matches? => true, :actual => actual, :failure_message => "" )) end let(:matcher_1) { create_matcher(:description => "matcher 1 description", :expected => "expected 1") } let(:matcher_2) { create_matcher(:description => "matcher 2 description", :expected => "expected 2") } let(:matcher_3) { create_matcher(:description => "matcher 3 description", :expected => "expected 3") } let(:long_description) { "a very very long description for my custom smart matcher, which can be used for everything" } let(:truncated_description) { "a very very long descriptio..." } let(:matcher_with_long_description) { create_matcher(:description => long_description, :expected => "expected value") } describe ".from" do it "wraps provided value in MultiMatcherDiff" do expect(wrapped_value).to be_a(described_class) end it "returns original value if it was already wrapped" do expect(described_class.from(wrapped_value, actual)).to be(wrapped_value) end end describe ".for_many_matchers" do let(:wrapped_value) { described_class.for_many_matchers([matcher_1, matcher_2, matcher_3]) } it "has a diff for all matchers with their description" do expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message |Diff for (matcher 1 description):["actual value", "expected 1"] |Diff for (matcher 2 description):["actual value", "expected 2"] |Diff for (matcher 3 description):["actual value", "expected 3"] EOS end end describe "#message_with_diff" do it "returns a message warning if the diff is empty" do allow(FakeDiffer).to receive(:diff) { "\e[0m\n\e[0m" } expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message |Diff: | EOS end it "returns just provided message if diff is just whitespace" do allow(FakeDiffer).to receive(:diff) { " \n \t" } expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message EOS end it "returns regular message with diff when single expected" do expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message |Diff:["actual value", "expected value"] EOS end it "returns message with diff and matcher description when single expected with matcher" do matcher = include("expected value") matcher.matches?(actual) wrapped_value = described_class.for_many_matchers([matcher]) expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message |Diff for (include "expected value"):["actual value", ["expected value"]] EOS end it "returns message with diff and truncated matcher description if it is too long" do wrapped_value = described_class.for_many_matchers([matcher_with_long_description]) expect(wrapped_value.message_with_diff( message, differ )).to eq(dedent <<-EOS) |a message |Diff for (#{truncated_description}):["actual value", "expected value"] EOS end end end end end rspec-expectations-3.13.0/spec/rspec/matchers_spec.rb000066400000000000000000000122561455770000100226360ustar00rootroot00000000000000main = self RSpec.describe RSpec::Matchers do include ::RSpec::Support::InSubProcess describe ".configuration" do it 'returns a memoized configuration instance' do expect(RSpec::Matchers.configuration).to be_a(RSpec::Expectations::Configuration) expect(RSpec::Matchers.configuration).to be(RSpec::Matchers.configuration) end end it 'can be mixed into `main`' do in_sub_process do allow_warning if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9' main.instance_eval do include RSpec::Matchers include RSpec::Matchers::FailMatchers expect(3).to eq(3) expect(3).to be_odd expect { expect(4).to be_zero }.to fail_with("expected `4.zero?` to return true, got false") end end end context "when included into a superclass after a subclass has already included it" do if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9' desc_start = "print" matcher_method = :output else desc_start = "does not print" matcher_method = :avoid_outputting end it "#{desc_start} a warning so the user is made aware of the MRI 1.9 bug that can cause infinite recursion" do superclass = stub_const("Superclass", Class.new) stub_const("Subclass", Class.new(superclass) { include RSpec::Matchers }) expect { superclass.send(:include, RSpec::Matchers) }.to send(matcher_method, a_string_including( "Superclass", "Subclass", "has been included" )).to_stderr end it "does not warn when this is a re-inclusion" do superclass = stub_const("Superclass", Class.new { include RSpec::Matchers }) stub_const("Subclass", Class.new(superclass) { include RSpec::Matchers }) expect { superclass.send(:include, RSpec::Matchers) }.to avoid_outputting.to_stderr end end describe "#respond_to?" do it "handles dynamic matcher methods" do expect(self).to respond_to(:be_happy, :have_eyes_closed) end it "supports the optional `include_private` arg" do expect(respond_to?(:puts, true)).to eq true expect(respond_to?(:puts, false)).to eq false expect(respond_to?(:puts)).to eq false end it "allows `method` to get dynamic matcher methods", :if => RUBY_VERSION.to_f >= 1.9 do expect(method(:be_happy).call).to be_a(be_happy.class) end end end module RSpec module Matchers RSpec.describe ".is_a_matcher?" do it 'does not match BasicObject', :if => RUBY_VERSION.to_f > 1.8 do expect(RSpec::Matchers.is_a_matcher?(BasicObject.new)).to eq(false) end it 'is registered with RSpec::Support' do expect(RSpec::Support.is_a_matcher?(be_even)).to eq(true) end it 'does not match a multi-element array' do # our original implementation regsitered the matcher definition as # `&RSpec::Matchers.method(:is_a_matcher?)`, which has a bug # on 1.8.7: # # irb(main):001:0> def foo(x); end # => nil # irb(main):002:0> method(:foo).call([1, 2, 3]) # => nil # irb(main):003:0> method(:foo).to_proc.call([1, 2, 3]) # ArgumentError: wrong number of arguments (3 for 1) # from (irb):1:in `foo' # from (irb):1:in `to_proc' # from (irb):3:in `call' # # This spec guards against a regression for that case. expect(RSpec::Support.is_a_matcher?([1, 2, 3])).to eq(false) end end RSpec.describe "built in matchers" do let(:matchers) do BuiltIn.constants.map { |n| BuiltIn.const_get(n) }.select do |m| m.method_defined?(:matches?) && m.method_defined?(:failure_message) end end specify "they all have defined #=== so they can be composable" do missing_threequals = matchers.select do |m| m.instance_method(:===).owner == ::Kernel end # This spec is merely to make sure we don't forget to make # a built-in matcher implement `===`. It doesn't check the # semantics of that. Use the "an RSpec value matcher" and # "an RSpec block-only matcher" shared example groups to # actually check the semantics. expect(missing_threequals).to eq([]) end specify "they all have defined #and and #or so they support compound expectations" do noncompound_matchers = matchers.reject do |m| m.method_defined?(:and) || m.method_defined?(:or) end expect(noncompound_matchers).to eq([]) end shared_examples "a well-behaved method_missing hook" do include MinitestIntegration it "raises a NoMethodError (and not SystemStackError) for an undefined method" do with_minitest_loaded do expect { subject.some_undefined_method }.to raise_error(NoMethodError) end end end describe "RSpec::Matchers method_missing hook", :slow do subject { self } it_behaves_like "a well-behaved method_missing hook" context 'when invoked in a Minitest::Test' do subject { Minitest::Test.allocate } it_behaves_like "a well-behaved method_missing hook" end end end end end rspec-expectations-3.13.0/spec/spec_helper.rb000066400000000000000000000076011455770000100211710ustar00rootroot00000000000000require 'rspec/support/spec' require 'rspec/support/spec/in_sub_process' RSpec::Support::Spec.setup_simplecov do minimum_coverage 92 end Dir['./spec/support/**/*.rb'].each do |f| require f.sub(%r{\./spec/}, '') end module CommonHelperMethods def with_env_vars(vars) original = ENV.to_hash vars.each { |k, v| ENV[k] = v } begin yield ensure ENV.replace(original) end end def dedent(string) string.gsub(/^\s+\|/, '').chomp end # We have to use Hash#inspect in examples that have multi-entry # hashes because the #inspect output on 1.8.7 is non-deterministic # due to the fact that hashes are not ordered. So we can't simply # put a literal string for what we expect because it varies. if RUBY_VERSION.to_f == 1.8 def hash_inspect(hash) "\\{(#{hash.map { |key, value| "#{key.inspect} => #{value.inspect}.*" }.join "|"}){#{hash.size}}\\}" end else def hash_inspect(hash) RSpec::Matchers::BuiltIn::BaseMatcher::HashFormatting. improve_hash_formatting hash.inspect end end end RSpec.configure do |config| config.color = true config.order = :random config.include CommonHelperMethods config.include RSpec::Support::InSubProcess config.expect_with :rspec do |expectations| $default_expectation_syntax = expectations.syntax # rubocop:disable Style/GlobalVars expectations.syntax = :expect expectations.include_chain_clauses_in_custom_matcher_descriptions = true expectations.strict_predicate_matchers = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end config.disable_monkey_patching! # We don't want rspec-core to look in our `lib` for failure snippets. # When it does that, it inevitably finds this line: # `RSpec::Support.notify_failure(RSpec::Expectations::ExpectationNotMetError.new message)` # ...which isn't very helpful. Far better for it to find the expectation # call site in the spec. config.project_source_dirs -= ["lib"] end RSpec.shared_context "with #should enabled", :uses_should do orig_syntax = nil before(:all) do orig_syntax = RSpec::Matchers.configuration.syntax RSpec::Matchers.configuration.syntax = [:expect, :should] end after(:context) do RSpec::Matchers.configuration.syntax = orig_syntax end end RSpec.shared_context "with the default expectation syntax" do orig_syntax = nil before(:context) do orig_syntax = RSpec::Matchers.configuration.syntax RSpec::Matchers.configuration.reset_syntaxes_to_default end after(:context) do RSpec::Matchers.configuration.syntax = orig_syntax end end RSpec.shared_context "with #should exclusively enabled", :uses_only_should do orig_syntax = nil before(:context) do orig_syntax = RSpec::Matchers.configuration.syntax RSpec::Matchers.configuration.syntax = :should end after(:context) do RSpec::Matchers.configuration.syntax = orig_syntax end end RSpec.shared_context "isolate include_chain_clauses_in_custom_matcher_descriptions" do around do |ex| orig = RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions? ex.run RSpec::Expectations.configuration.include_chain_clauses_in_custom_matcher_descriptions = orig end end RSpec.shared_context "with warn_about_potential_false_positives set to false", :warn_about_potential_false_positives do original_value = RSpec::Expectations.configuration.warn_about_potential_false_positives? after(:context) { RSpec::Expectations.configuration.warn_about_potential_false_positives = original_value } end module MinitestIntegration include ::RSpec::Support::InSubProcess def with_minitest_loaded in_sub_process do with_isolated_stderr do require 'minitest/autorun' end require 'rspec/expectations/minitest_integration' yield end end end RSpec::Matchers.define_negated_matcher :avoid_outputting, :output rspec-expectations-3.13.0/spec/support/000077500000000000000000000000001455770000100200635ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/support/matchers.rb000066400000000000000000000020611455770000100222150ustar00rootroot00000000000000require 'rspec/matchers/fail_matchers' RSpec::Matchers.define :include_method do |expected| match do |actual| actual.map { |m| m.to_s }.include?(expected.to_s) end end RSpec::Matchers.define :custom_include do |*args| match { |actual| expect(actual).to include(*args) } end RSpec::Matchers.define :be_a_clone_of do |expected| match do |actual| !actual.equal?(expected) && actual.class.equal?(expected.class) && state_of(actual) == state_of(expected) end def state_of(object) ivar_names = object.instance_variables Hash[ivar_names.map { |n| [n, object.instance_variable_get(n)] }] end end RSpec::Matchers.define :have_string_length do |expected| match do |actual| @actual = actual string_length == expected end def string_length @string_length ||= @actual.length end end RSpec.configure do |config| config.include RSpec::Matchers::FailMatchers end RSpec::Matchers.define_negated_matcher :a_string_excluding, :a_string_including RSpec::Matchers.define_negated_matcher :a_string_not_matching, :match rspec-expectations-3.13.0/spec/support/shared_examples/000077500000000000000000000000001455770000100232275ustar00rootroot00000000000000rspec-expectations-3.13.0/spec/support/shared_examples/block_matcher.rb000066400000000000000000000064541455770000100263620ustar00rootroot00000000000000RSpec.shared_examples "an RSpec block-only matcher" do |*options| # Note: Ruby 1.8 expects you to call a block with arguments if it is # declared that accept arguments. In this case, some of the specs # that include examples from this shared example group do not pass # arguments. A workaround is to use splat and pick the first argument # if it was passed. options = options.first || {} # Note: do not use `matcher` in 2 expectation expressions in a single # example here. In some cases (such as `change { x += 2 }.to(2)`), it # will fail because using it a second time will apply `x += 2` twice, # changing the value to 4. matcher :always_passes do supports_block_expectations match do |actual| actual.call true end end matcher :always_fails do supports_block_expectations match do |actual| actual.call false end end let(:valid_expectation) { expect { valid_block } } let(:invalid_expectation) { expect { invalid_block } } let(:valid_block_lambda) { lambda { valid_block } } let(:invalid_block_lambda) { lambda { invalid_block } } include_examples "an RSpec matcher", options it 'preserves the symmetric property of `==`' do expect(matcher).to eq(matcher) expect(matcher).not_to eq(valid_block_lambda) expect(valid_block_lambda).not_to eq(matcher) end it 'matches a valid block when using #=== so it can be composed' do expect(matcher).to be === valid_block_lambda end it 'does not match an invalid block when using #=== so it can be composed' do expect(matcher).not_to be === invalid_block_lambda end it 'matches a valid block when using #=== so it can be composed' do expect(matcher).to be === valid_block_lambda end it 'does not match an invalid block when using #=== so it can be composed' do expect(matcher).not_to be === invalid_block_lambda end it 'uses the `ObjectFormatter` for `failure_message`' do allow(RSpec::Support::ObjectFormatter).to receive(:format).and_return("detailed inspect") expect { invalid_expectation.to matcher }.to raise_error do |error| # Undo our stub so it doesn't affect the `include` matcher below. allow(RSpec::Support::ObjectFormatter).to receive(:format).and_call_original expect(error.message).to include("detailed inspect") end end unless options[:failure_message_uses_no_inspect] it 'fails gracefully when given a value' do expect { expect(3).to matcher }.to fail_with(/was not( given)? a block/) unless options[:disallows_negation] expect { expect(3).not_to matcher }.to fail_with(/was not( given)? a block/) end end it 'prints a deprecation warning when given a value' do expect_warn_deprecation(/The implicit block expectation syntax is deprecated, you should pass/) expect { expect(3).to matcher }.to fail end unless options[:skip_deprecation_check] || options[:expects_lambda] it 'prints a deprecation warning when given a value and negated' do expect_warn_deprecation(/The implicit block expectation syntax is deprecated, you should pass/) expect { expect(3).not_to matcher }.to fail end unless options[:disallows_negation] || options[:expects_lambda] it 'allows lambda expectation target' do allow_deprecation expect(valid_block_lambda).to matcher end end rspec-expectations-3.13.0/spec/support/shared_examples/matcher.rb000066400000000000000000000025451455770000100252050ustar00rootroot00000000000000RSpec.shared_examples "an RSpec matcher" do |options| # Note: do not use `matcher` in 2 expectation expressions in a single # example here. In some cases (such as `change { }.to(2)`), it will fail # because using it a second time will apply `x += 2` twice, changing # the value to 4. it 'allows additional matchers to be chained off it using `and`' do valid_expectation.to matcher.and always_passes end it 'can be chained off of an existing matcher using `and`' do valid_expectation.to always_passes.and matcher end it 'allows additional matchers to be chained off it using `or`' do valid_expectation.to matcher.or always_fails end it 'can be chained off of an existing matcher using `or`' do valid_expectation.to always_fails.or matcher end it 'implements the full matcher protocol' do expect(matcher).to respond_to( :matches?, :failure_message, :description, :supports_block_expectations?, :supports_value_expectations?, :expects_call_stack_jump? ) # We do not require failure_message_when_negated and does_not_match? # Because some matchers purposefully do not support negation. end it 'can match negatively properly' do invalid_expectation.not_to matcher expect { valid_expectation.not_to matcher }.to fail end unless options[:disallows_negation] end rspec-expectations-3.13.0/spec/support/shared_examples/value_matcher.rb000066400000000000000000000035601455770000100263770ustar00rootroot00000000000000RSpec.shared_examples "an RSpec value matcher" do |options| let(:valid_value) { options.fetch(:valid_value) } let(:invalid_value) { options.fetch(:invalid_value) } matcher :always_passes do match { |_actual| true } end matcher :always_fails do match { |_actual| false } end def valid_expectation expect(valid_value) end def invalid_expectation expect(invalid_value) end include_examples "an RSpec matcher", options it 'preserves the symmetric property of `==`' do expect(matcher).to eq(matcher) expect(matcher).not_to eq(valid_value) expect(valid_value).not_to eq(matcher) end it 'matches a valid value when using #=== so it can be composed' do expect(matcher).to be === valid_value end it 'does not match an invalid value when using #=== so it can be composed' do expect(matcher).not_to be === invalid_value end it 'can be used in a composed matcher expression' do expect([valid_value, invalid_value]).to include(matcher) expect { expect([invalid_value]).to include(matcher) }.to fail_including("include (#{matcher.description})") end it 'uses the `ObjectFormatter` for `failure_message`' do allow(RSpec::Support::ObjectFormatter).to receive(:format).and_return("detailed inspect") matcher.matches?(invalid_value) message = matcher.failure_message # Undo our stub so it doesn't affect the `include` matcher below. allow(RSpec::Support::ObjectFormatter).to receive(:format).and_call_original expect(message).to include("detailed inspect") end it 'fails when given a block' do expect { expect { 2 + 2 }.to matcher }.to fail_with(/must pass an argument rather than a block/) unless options[:disallows_negation] expect { expect { 2 + 2 }.not_to matcher }.to fail_with(/must pass an argument rather than a block/) end end end