pax_global_header00006660000000000000000000000064145661420770014526gustar00rootroot0000000000000052 comment=38e40fec3f2bda7074f76b1f9b4c96be613df6d1 rspec-support-3.13.1/000077500000000000000000000000001456614207700144415ustar00rootroot00000000000000rspec-support-3.13.1/.github/000077500000000000000000000000001456614207700160015ustar00rootroot00000000000000rspec-support-3.13.1/.github/FUNDING.yml000066400000000000000000000003351456614207700176170ustar00rootroot00000000000000# This file was generated on 2023-04-16T20:53:24+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-support-3.13.1/.github/dependabot.yml000066400000000000000000000004371456614207700206350ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/.github/workflows/000077500000000000000000000000001456614207700200365ustar00rootroot00000000000000rspec-support-3.13.1/.github/workflows/ci.yml000066400000000000000000000114301456614207700211530ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/.gitignore000066400000000000000000000003211456614207700164250ustar00rootroot00000000000000*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp bin bundle Gemfile-custom spec/examples.txt specs.out rspec-support-3.13.1/.rspec000066400000000000000000000000611456614207700155530ustar00rootroot00000000000000--order random --color --warnings -r spec_helper rspec-support-3.13.1/.rubocop.yml000066400000000000000000000016651456614207700167230ustar00rootroot00000000000000inherit_from: - .rubocop_rspec_base.yml - .rubocop_todo.yml # Over time we'd like to get this down, but this is what we're at now. Metrics/AbcSize: Max: 28 # Over time we'd like to get this down, but this is what we're at now. Metrics/BlockLength: Max: 86 Exclude: - spec/**/* # Over time we'd like to get this down, but this is what we're at now. Metrics/PerceivedComplexity: Max: 10 Security/MarshalLoad: Exclude: - 'lib/rspec/support/spec/in_sub_process.rb' Style/EvalWithLocation: Exclude: # eval is only used here to check syntax - 'lib/rspec/support/ruby_features.rb' - 'benchmarks/skip_frames_for_caller_filter.rb' - 'spec/rspec/support/method_signature_verifier_spec.rb' Lint/AssignmentInCondition: Exclude: # The pattern makes sense here - 'lib/rspec/support/mutex.rb' Style/FrozenStringLiteralComment: Include: - lib/**/*.rb Layout/EmptyLineAfterMagicComment: Enabled: true rspec-support-3.13.1/.rubocop_rspec_base.yml000066400000000000000000000150051456614207700211020ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/.rubocop_todo.yml000066400000000000000000000300601456614207700177370ustar00rootroot00000000000000# This configuration was generated by # `rubocop --auto-gen-config` # on 2022-01-09 17:43:27 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: 1 # Configuration parameters: Include. # Include: **/*.gemspec Gemspec/RequiredRubyVersion: Exclude: - 'rspec-support.gemspec' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: with_first_argument, with_fixed_indentation Layout/ArgumentAlignment: Exclude: - 'spec/rspec/support_spec.rb' # Offense count: 17 # Cop supports --auto-correct. Layout/EmptyLineAfterGuardClause: Exclude: - 'benchmarks/caller_vs_caller_locations_vs_raise.rb' - 'lib/rspec/support.rb' - 'lib/rspec/support/differ.rb' - 'lib/rspec/support/method_signature_verifier.rb' - 'lib/rspec/support/mutex.rb' - 'lib/rspec/support/recursive_const_methods.rb' - 'lib/rspec/support/reentrant_mutex.rb' - 'lib/rspec/support/source.rb' - 'lib/rspec/support/source/location.rb' - 'lib/rspec/support/source/token.rb' - 'lib/rspec/support/spec/library_wide_checks.rb' - 'lib/rspec/support/spec/stderr_splitter.rb' # Offense count: 3 # Cop supports --auto-correct. Layout/EmptyLines: Exclude: - 'benchmarks/caller.rb' - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: AllowAliasSyntax, AllowedMethods. # AllowedMethods: alias_method, public, protected, private Layout/EmptyLinesAroundAttributeAccessor: Exclude: - 'spec/rspec/support/fuzzy_matcher_spec.rb' - 'spec/rspec/support/method_signature_verifier_spec.rb' # Offense count: 8 # 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/support/source/token.rb' - 'rspec-support.gemspec' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: normal, indented_internal_methods Layout/IndentationConsistency: Exclude: - 'spec/rspec/support/differ_spec.rb' # Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: Width, IgnoredPatterns. Layout/IndentationWidth: Exclude: - 'lib/rspec/support/method_signature_verifier.rb' - 'lib/rspec/support/ruby_features.rb' # Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Layout/LineLength: Max: 156 # Offense count: 13 # Cop supports --auto-correct. Layout/SpaceAfterComma: Exclude: - 'rspec-support.gemspec' - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: space, no_space Layout/SpaceAroundEqualsInParameterDefault: Exclude: - 'spec/rspec/support/encoded_string_spec.rb' - 'spec/rspec/support/method_signature_verifier_spec.rb' # Offense count: 8 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. # SupportedStyles: space, no_space, compact # SupportedStylesForEmptyBrackets: space, no_space Layout/SpaceInsideArrayLiteralBrackets: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/fuzzy_matcher_spec.rb' # Offense count: 20 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. # SupportedStyles: space, no_space, compact # SupportedStylesForEmptyBraces: space, no_space Layout/SpaceInsideHashLiteralBraces: Exclude: - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. # SupportedStyles: space, no_space # SupportedStylesForEmptyBrackets: space, no_space Layout/SpaceInsideReferenceBrackets: Exclude: - 'benchmarks/map_hash.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: final_newline, final_blank_line Layout/TrailingEmptyLines: Exclude: - 'spec/rspec/support/fuzzy_matcher_spec.rb' # Offense count: 4 Lint/AmbiguousBlockAssociation: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/encoded_string_spec.rb' - 'spec/rspec/support/ruby_features_spec.rb' - 'spec/rspec/support_spec.rb' # Offense count: 2 Lint/BinaryOperatorWithIdenticalOperands: Exclude: - 'spec/rspec/support/object_formatter_spec.rb' - 'spec/rspec/support/source/token_spec.rb' # Offense count: 3 # Configuration parameters: AllowedMethods. # AllowedMethods: enums Lint/ConstantDefinitionInBlock: Exclude: - 'spec/rspec/support/fuzzy_matcher_spec.rb' - 'spec/rspec/support/recursive_const_methods_spec.rb' - 'spec/rspec/support/spec/in_sub_process_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowedImplicitNamespaces. # AllowedImplicitNamespaces: Gem Lint/RaiseException: Exclude: - 'spec/rspec/support_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Lint/RedundantCopDisableDirective: Exclude: - 'lib/rspec/support/spec/in_sub_process.rb' # Offense count: 1 Lint/StructNewOverride: Exclude: - 'spec/rspec/support_spec.rb' # Offense count: 3 # Configuration parameters: AllowComments. Lint/SuppressedException: Exclude: - 'spec/rspec/support_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: ContextCreatingMethods, MethodCreatingMethods. Lint/UselessAccessModifier: Exclude: - 'lib/rspec/support/encoded_string.rb' # Offense count: 12 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. # IgnoredMethods: refine Metrics/BlockLength: Max: 834 # Offense count: 8 # Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: Max: 836 # Offense count: 1 # Configuration parameters: IgnoredMethods. Metrics/PerceivedComplexity: Max: 10 # Offense count: 6 # 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_caller_locations_vs_raise.rb' - 'spec/rspec/support/method_signature_verifier_spec.rb' # Offense count: 5 # Cop supports --auto-correct. # Configuration parameters: PreferredName. Naming/RescuedExceptionsVariableName: Exclude: - 'benchmarks/caller_vs_caller_locations_vs_raise.rb' - 'lib/rspec/support.rb' - 'lib/rspec/support/spec/in_sub_process.rb' # Offense count: 1 Security/Eval: Exclude: - 'Gemfile' # Offense count: 7 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/object_formatter_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Style/CaseLikeIf: Exclude: - 'lib/rspec/support/directory_maker.rb' # Offense count: 7 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: nested, compact Style/ClassAndModuleChildren: Exclude: - 'spec/rspec/support/comparable_version_spec.rb' - 'spec/rspec/support/directory_maker_spec.rb' - 'spec/rspec/support/encoded_string_spec.rb' - 'spec/rspec/support/source/node_spec.rb' - 'spec/rspec/support/source/token_spec.rb' - 'spec/rspec/support/source_spec.rb' - 'spec/rspec/support/with_keywords_when_needed_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: ==, equal?, eql? Style/ClassEqualityComparison: Exclude: - 'lib/rspec/support/comparable_version.rb' # Offense count: 1 # Cop supports --auto-correct. Style/ColonMethodCall: Exclude: - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. Style/EmptyLiteral: Exclude: - 'spec/rspec/support/method_signature_verifier_spec.rb' # Offense count: 3 # Cop supports --auto-correct. Style/Encoding: Exclude: - 'rspec-support.gemspec' - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/encoded_string_spec.rb' # Offense count: 4 # Cop supports --auto-correct. Style/ExpandPathArguments: Exclude: - 'Gemfile' - 'benchmarks/caller.rb' - 'rspec-support.gemspec' - 'spec/rspec/support/caller_filter_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: format, sprintf, percent Style/FormatString: Exclude: - 'spec/rspec/support/encoded_string_spec.rb' # Offense count: 1 # Cop supports --auto-correct. Style/GlobalStdStream: Exclude: - 'spec/rspec/support/spec/stderr_splitter_spec.rb' # Offense count: 3 # Configuration parameters: AllowedVariables. Style/GlobalVars: Exclude: - 'spec/rspec/support/caller_filter_spec.rb' - 'spec/rspec/support/spec/stderr_splitter_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys Style/HashSyntax: Exclude: - 'benchmarks/class_exec_vs_klass_exec.rb' # Offense count: 2 # Cop supports --auto-correct. Style/LineEndConcatenation: Exclude: - 'spec/rspec/support_spec.rb' # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. Style/MethodCallWithoutArgsParentheses: Exclude: - 'spec/rspec/support/method_signature_verifier_spec.rb' # Offense count: 8 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/object_formatter_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: Strict. Style/NumericLiterals: MinDigits: 6 # Offense count: 1 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - 'lib/rspec/support/spec/in_sub_process.rb' # Offense count: 7 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/object_formatter_spec.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: lower_case_q, upper_case_q Style/PercentQLiterals: Exclude: - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. Style/RedundantPercentQ: Exclude: - 'spec/rspec/support/differ_spec.rb' # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods. # AllowedMethods: present?, blank?, presence, try, try! Style/SafeNavigation: Exclude: - 'lib/rspec/support/mutex.rb' # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowAsExpressionSeparator. Style/Semicolon: Exclude: - 'spec/rspec/support/fuzzy_matcher_spec.rb' # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: AllowIfMethodIsEmpty. Style/SingleLineMethods: Exclude: - 'spec/rspec/support/differ_spec.rb' - 'spec/rspec/support/fuzzy_matcher_spec.rb' # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: WordRegex. # SupportedStyles: percent, brackets Style/WordArray: EnforcedStyle: percent MinSize: 3 rspec-support-3.13.1/BUILD_DETAIL.md000066400000000000000000000124431456614207700166500ustar00rootroot00000000000000 # The CI build, in detail The [Travis CI build](https://travis-ci.org/rspec/rspec-support) 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-support-3.13.1/CODE_OF_CONDUCT.md000066400000000000000000000054441456614207700172470ustar00rootroot00000000000000 # 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-support-3.13.1/CONTRIBUTING.md000066400000000000000000000103361456614207700166750ustar00rootroot00000000000000 # 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-support/issues/new) with [report template](#report-template) - by [suggesting new features](https://github.com/rspec/rspec-support/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-support/issues) - by adding a failing test for reproducible [reported bugs](https://github.com/rspec/rspec-support/issues) - by reviewing [pull requests](https://github.com/rspec/rspec-support/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-support-3.13.1/Changelog.md000066400000000000000000000311671456614207700166620ustar00rootroot00000000000000### Development [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.13.1...main) ### 3.13.1 / 2024-02-23 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.13.0...v3.13.1) Bug Fixes: * Exclude ruby internal require warnings from `RSpec::Support::CallerFilter#first_non_rspec_line`. (Jon Rowe, #593) ### 3.13.0 / 2024-02-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.12.2...v3.13.0) Enchancements * Add `RubyFeatures#supports_syntax_suggest?`. (Jon Rowe, #571) ### 3.12.2 / 2024-02-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.12.1...v3.12.2) Bug Fixes: * Properly surface errors from `in_sub_process`. (Jon Rowe, #575) * Add magic comment for freezing string literals. (Josh Nichols, #586) * Allow string keys for keyword arguments during verification of method signatures, (but only on Ruby 3+). (@malcolmohare, #591) ### 3.12.1 / 2023-06-26 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.12.0...v3.12.1) Bug Fixes: * Fix `RSpec::Support.thread_local_data` to be Thread local but not Fiber local. (Jon Rowe, #581) ### 3.12.0 / 2022-10-26 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.11.1...v3.12.0) Enhancements: * Add `RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash?` (Jean byroot Boussier, #535) ### 3.11.1 / 2022-09-12 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.11.0...v3.11.1) Bug Fixes: * Fix ripper detection on TruffleRuby. (Brandon Fish, #541) ### 3.11.0 / 2022-02-09 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.3...v3.11.0) No changes. Released to support other RSpec releases. ### 3.10.3 / 2021-11-03 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.2...v3.10.3) Bug Fixes: * Use `Mutex#owned?` to allow `RSpec::Support::ReentrantMutex` to work in nested Fibers on Ruby 3.0 and later. (Benoit Daloze, #503, #504) * Support `end`-less methods in `RSpec::Support::Source::Token` so that RSpec won't hang when an `end`-less method raises an error. (Yuji Nakayama, #505) ### 3.10.2 / 2021-01-28 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.1...v3.10.2) Bug Fixes: * Fix issue with `RSpec::Support.define_optimized_require_for_rspec` on JRuby 9.1.17.0 (Jon Rowe, #492) ### 3.10.1 / 2020-12-27 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.0...v3.10.1) Bug Fixes: * Fix deprecation expectations to fail correctly when asserting on messages. (Phil Pirozhkov, #453) ### 3.10.0 / 2020-10-30 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.9.4...v3.10.0) No changes. Released to support other RSpec releases. ### 3.9.4 / 2020-10-23 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.9.3...v3.9.4) Bug Fixes: * Flag ripper as supported on Truffle Ruby. (Brandon Fish, #427) * Prevent stubbing `File.read` from breaking source extraction. (Jon Rowe, #431) ### 3.9.3 / 2020-05-02 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.9.2...v3.9.3) Bug Fixes: * Mark ripper as unsupported on Truffle Ruby. (Brandon Fish, #395) * Mark ripper as unsupported on JRuby 9.2.0.0. (Brian Hawley, #400) * Capture `Mutex.new` for our `RSpec::Support:Mutex` in order to allow stubbing `Mutex.new`. (Jon Rowe, #411) ### 3.9.2 / 2019-12-30 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.9.1...v3.9.2) Bug Fixes: * Remove unneeded eval. (Matijs van Zuijlen, #394) ### 3.9.1 / 2019-12-28 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.9.0...v3.9.1) Bug Fixes: * Remove warning caused by keyword arguments on Ruby 2.7.0. (Jon Rowe, #392) ### 3.9.0 / 2019-10-07 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.3...v3.9.0) *NO CHANGES* Version 3.9.0 was released to allow other RSpec gems to release 3.9.0. ### 3.8.3 / 2019-10-02 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.2...v3.8.3) Bug Fixes: * Escape \r when outputting strings inside arrays. (Tomita Masahiro, Jon Rowe, #378) * Ensure that optional hash arguments are recognised correctly vs keyword arguments. (Evgeni Dzhelyov, #366) ### 3.8.2 / 2019-06-10 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.1...v3.8.2) Bug Fixes: * Ensure that an empty hash is recognised as empty keyword arguments when applicable. (Thomas Walpole, #375) * Ensure that diffing truthy values produce diffs consistently. (Lucas Nestor, #377) ### 3.8.1 / 2019-03-03 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.0...v3.8.1) Bug Fixes: * Ensure that inspecting a `SimpleDelegator` based object works regardless of visibility of the `__getobj__` method. (Jon Rowe, #369) ### 3.8.0 / 2018-08-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.7.1...v3.8.0) Bug Fixes: * Order hash keys before diffing to improve diff accuracy when using mocked calls. (James Crisp, #334) ### 3.7.1 / 2018-01-29 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.7.0...v3.7.1) Bug Fixes: * Fix source extraction logic so that it does not trigger a `SystemStackError` when processing deeply nested example groups. (Craig Bass, #343) ### 3.7.0 / 2017-10-17 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0...v3.7.0) Enhancements: * Improve compatibility with `--enable-frozen-string-literal` option on Ruby 2.3+. (Pat Allan, #320) * Add `Support.class_of` for extracting class of any object. (Yuji Nakayama, #325) Bug Fixes: * Fix recursive const support to not blow up when given buggy classes that raise odd errors from `#to_str`. (Myron Marston, #317) ### 3.6.0 / 2017-05-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta2...3.6.0) Enhancements: * Import `Source` classes from rspec-core. (Yuji Nakayama, #315) ### 3.6.0.beta2 / 2016-12-12 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta1...v3.6.0.beta2) No user-facing changes. ### 3.6.0.beta1 / 2016-10-09 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0...v3.6.0.beta1) Bug Fixes: * Prevent truncated formatted object output from mangling console codes. (#294, Anson Kelly) ### 3.5.0 / 2016-07-01 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta4...v3.5.0) **No user facing changes since beta4** ### 3.5.0.beta4 / 2016-06-05 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta3...v3.5.0.beta4) Enhancements: * Improve `MethodSignature` to better support keyword arguments. (#250, Rob Smith). ### 3.5.0.beta3 / 2016-04-02 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta2...v3.5.0.beta3) Bug Fixes: * Fix `EncodedString` to properly handle the behavior of `String#split` on JRuby when the string contains invalid bytes. (Jon Rowe, #268) * Fix `ObjectFormatter` so that formatting objects that don't respond to `#inspect` (such as `BasicObject`) does not cause `NoMethodError`. (Yuji Nakayama, #269) * Fix `ObjectFormatter` so that formatting recursive array or hash does not cause `SystemStackError`. (Yuji Nakayama, #270, #272) ### 3.5.0.beta2 / 2016-03-10 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta1...v3.5.0.beta2) No user-facing changes. ### 3.5.0.beta1 / 2016-02-06 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.4.1...v3.5.0.beta1) Enhancements: * Improve formatting of objects by allowing truncation to a pre-configured length. (Liam M, #256) ### 3.4.1 / 2015-11-20 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.4.0...v3.4.1) Bug Fixes: * Fix `RSpec::Support::RubyFeature.ripper_supported?` so it returns `false` on Rubinius since the Rubinius team has no plans to support it. This prevents rspec-core from trying to load and use ripper to extract failure snippets. (Aaron Stone, #251) Changes: * Remove `VersionChecker` in favor of `ComparableVersion`. (Yuji Nakayama, #266) ### 3.4.0 / 2015-11-11 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.3.0...v3.4.0) Enhancements: * Improve formatting of `Delegator` based objects (e.g. `SimpleDelegator`) in failure messages and diffs. (Andrew Horner, #215) * Add `ComparableVersion`. (Yuji Nakayama, #245) * Add `Ripper` support detection. (Yuji Nakayama, #245) Bug Fixes: * Work around bug in JRuby that reports that `attr_writer` methods have no parameters, causing RSpec's verifying doubles to wrongly fail when mocking or stubbing a writer method on JRuby. (Myron Marston, #225) ### 3.3.0 / 2015-06-12 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.2.2...v3.3.0) Enhancements: * Improve formatting of arrays and hashes in failure messages so they use our custom formatting of matchers, time objects, etc. (Myron Marston, Nicholas Chmielewski, #205) * Use improved formatting for diffs as well. (Nicholas Chmielewski, #205) Bug Fixes: * Fix `FuzzyMatcher` so that it checks `expected == actual` rather than `actual == expected`, which avoids errors in situations where the `actual` object's `==` is improperly implemented to assume that only objects of the same type will be given. This allows rspec-mocks' `anything` to match against objects with buggy `==` definitions. (Myron Marston, #193) ### 3.2.2 / 2015-02-23 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.2.1...v3.2.2) Bug Fixes: * Fix an encoding issue with `EncodedString#split` when encountering an invalid byte string. (Benjamin Fleischer, #1760) ### 3.2.1 / 2015-02-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.2.0...v3.2.1) Bug Fixes: * Fix `RSpec::CallerFilter` to work on Rubinius 2.2. (Myron Marston, #169) ### 3.2.0 / 2015-02-03 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.1.2...v3.2.0) Enhancements: * Add extra Ruby type detection. (Jon Rowe, #133) * Make differ instance re-usable. (Alexey Fedorov, #160) Bug Fixes: * Do not consider `[]` and `{}` to match when performing fuzzy matching. (Myron Marston, #157) ### 3.1.2 / 2014-10-08 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.1.1...v3.1.2) Bug Fixes: * Fix method signature to not blow up with a `NoMethodError` on 1.8.7 when verifying against an RSpec matcher. (Myron Marston, #116) ### 3.1.1 / 2014-09-26 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.1.0...v3.1.1) Bug Fixes: * Fix `RSpec::Support::DirectoryMaker` (used by `rspec --init` and `rails generate rspec:install`) so that it detects absolute paths on Windows properly. (Scott Archer, #107, #108, #109) (Jon Rowe, #110) ### 3.1.0 / 2014-09-04 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.4...v3.1.0) Bug Fixes: * Fix `FuzzyMatcher` so that it does not wrongly match a struct against an array. (Myron Marston, #97) * Prevent infinitely recursing `#flatten` methods from causing the differ to hang. (Jon Rowe, #101) ### 3.0.4 / 2014-08-14 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.3...v3.0.4) Bug Fixes: * Fix `FuzzyMatcher` so that it does not silence `ArgumentError` raised from broken implementations of `==`. (Myron Marston, #94) ### 3.0.3 / 2014-07-21 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.2...v3.0.3) Bug Fixes: * Fix regression in `Support#method_handle_for` where proxy objects with method delegated would wrongly not return a method handle. (Jon Rowe, #90) * Properly detect Module#prepend support in Ruby 2.1+ (Ben Langfeld, #91) * Fix `rspec/support/warnings.rb` so it can be loaded and used in isolation. (Myron Marston, #93) ### 3.0.2 / 2014-06-20 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.1...v3.0.2) * Revert `BlockSignature` change from 3.0.1 because of a ruby bug that caused it to change the block's behavior (https://bugs.ruby-lang.org/issues/9967). (Myron Marston, rspec-mocks#721) ### 3.0.1 / 2014-06-19 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.0...v3.0.1) * Fix `BlockSignature` so that it correctly differentiates between required and optional block args. (Myron Marston, rspec-mocks#714) ### 3.0.0 / 2014-06-01 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.0.rc1...v3.0.0) ### 3.0.0.rc1 / 2014-05-18 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.0.beta2...v3.0.0.rc1) ### 3.0.0.beta2 / 2014-02-17 [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.0.0.beta1...v3.0.0.beta2) Bug Fixes: * Issue message when :replacement is passed to `RSpec.warn_with`. (Jon Rowe) ### 3.0.0.beta1 / 2013-11-07 [Full Changelog](https://github.com/rspec/rspec-support/compare/0dc12d1bdbbacc757a9989f8c09cd08ef3a4837e...v3.0.0.beta1) Initial release. rspec-support-3.13.1/DEVELOPMENT.md000066400000000000000000000115301456614207700165450ustar00rootroot00000000000000 # 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-support 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-support.git ``` Install the dependencies using [Bundler](https://bundler.io/): ``` $ cd rspec-support $ 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-support 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-support) 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-support-3.13.1/Gemfile000066400000000000000000000043511456614207700157370ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in rspec-support.gemspec gemspec branch = File.read(File.expand_path("../maintenance-branch", __FILE__)).chomp %w[rspec rspec-core rspec-expectations rspec-mocks].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 if lib == 'rspec' gem 'rspec', :git => "https://github.com/rspec/rspec-metagem.git", :branch => branch else gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => branch end 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 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 if RUBY_VERSION >= '3.3.0' # This is being extracted in Ruby 3.4 and issues a warning on 3.3 gem 'bigdecimal', :require => false 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" elsif RUBY_VERSION < '2.3.0' gem "childprocess", "< 3.0.0" else gem "childprocess", ">= 3.0.0" end group :coverage do ### dep for ci/coverage gem 'simplecov', '~> 0.8' 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 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 < '2.0' # ffi dropped Ruby 1.8 support in 1.9.19 and Ruby 1.9 support in 1.11.0 gem 'ffi', '< 1.9.19' elsif RUBY_VERSION < '2.3.0' gem 'ffi', '~> 1.12.0' else gem 'ffi', '~> 1.13.0' end # No need to run rubocop on earlier versions if RUBY_VERSION >= '2.4' && RUBY_ENGINE == 'ruby' gem 'rubocop', "~> 1.0", "< 1.12" end eval File.read('Gemfile-custom') if File.exist?('Gemfile-custom') rspec-support-3.13.1/ISSUE_TEMPLATE.md000066400000000000000000000010311456614207700171410ustar00rootroot00000000000000 ### Subject of the issue ### Your environment * Ruby version: * rspec-support version: ### Steps to reproduce ### Expected behavior ### Actual behavior rspec-support-3.13.1/LICENSE.md000066400000000000000000000022251456614207700160460ustar00rootroot00000000000000The MIT License (MIT) ==================== * Copyright © 2013 David Chelimsky, Myron Marston, Jon Rowe, Sam Phippen, Xavier Shay, Bradley Schaefer 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-support-3.13.1/README.md000066400000000000000000000026121456614207700157210ustar00rootroot00000000000000# RSpec::Support [![Build Status](https://github.com/rspec/rspec-support/workflows/RSpec%20CI/badge.svg)](https://github.com/rspec/rspec-support/actions) `RSpec::Support` provides common functionality to `RSpec::Core`, `RSpec::Expectations` and `RSpec::Mocks`. It is considered suitable for internal use only at this time. ## Installation / Usage Install one or more of the `RSpec` gems. 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 ``` ## 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) ## Patches Please submit a pull request or a github issue. If you submit an issue, please include a link to either of: * a gist (or equivalent) of the patch * a branch or commit in your github fork of the repo rspec-support-3.13.1/REPORT_TEMPLATE.md000066400000000000000000000021171456614207700172720ustar00rootroot00000000000000 # 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-support-3.13.1/Rakefile000066400000000000000000000014001456614207700161010ustar00rootroot00000000000000require "bundler" Bundler.setup Bundler::GemHelper.install_tasks require "rake" require "rspec/core/rake_task" require "rspec/core/version" desc "Run all examples" RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = %w[-w] end task :default => [:spec] 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 begin require 'rubocop/rake_task' desc 'Run RuboCop on the lib directory' RuboCop::RakeTask.new(:rubocop) do |task| task.patterns = ['lib/**/*.rb'] end rescue LoadError # No rubocop means no rubocop rake task end rspec-support-3.13.1/SECURITY.md000066400000000000000000000003011456614207700162240ustar00rootroot00000000000000## Security contact information To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. rspec-support-3.13.1/benchmarks/000077500000000000000000000000001456614207700165565ustar00rootroot00000000000000rspec-support-3.13.1/benchmarks/caller.rb000066400000000000000000000045101456614207700203450ustar00rootroot00000000000000$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__)) require 'benchmark' require 'rspec/support/caller_filter' n = 10000 puts "#{n} times - ruby #{RUBY_VERSION}" puts puts "* Using a chunked fetch is quicker than the old method of array-access." Benchmark.bm(20) do |bm| bm.report("CallerFilter") do n.times do RSpec::CallerFilter.first_non_rspec_line end end bm.report("Direct caller access") do n.times do caller(1)[4] end end end puts puts "* Chunking fetches of caller adds a ~17% overhead." Benchmark.bm(20) do |bm| bm.report("Chunked") do n.times do caller(1, 2) caller(3, 2) caller(5, 2) end end bm.report("All at once") do n.times do caller(1, 6) end end end puts puts "* `caller` scales linearly with length parameter." Benchmark.bm(20) do |bm| (1..10).each do |x| bm.report(x) do n.times do caller(1, x) end end end end # > ruby benchmarks/caller.rb # 10000 times - ruby 2.0.0 # # * Using a chunked fetch is quicker than the old method of array-access. # user system total real # CallerFilter 0.140000 0.010000 0.150000 ( 0.145381) # Direct caller access 0.170000 0.000000 0.170000 ( 0.180610) # # * Chunking fetches of caller adds a ~17% overhead. # user system total real # Chunked 0.150000 0.000000 0.150000 ( 0.181162) # All at once 0.130000 0.010000 0.140000 ( 0.138732) # # * `caller` scales linearly with length parameter. # user system total real # 1 0.030000 0.000000 0.030000 ( 0.035000) # 2 0.050000 0.000000 0.050000 ( 0.059879) # 3 0.080000 0.000000 0.080000 ( 0.098468) # 4 0.090000 0.010000 0.100000 ( 0.097619) # 5 0.110000 0.000000 0.110000 ( 0.126220) # 6 0.130000 0.000000 0.130000 ( 0.136739) # 7 0.150000 0.000000 0.150000 ( 0.159055) # 8 0.160000 0.010000 0.170000 ( 0.172416) # 9 0.180000 0.000000 0.180000 ( 0.203038) # 10 0.200000 0.000000 0.200000 ( 0.210551) rspec-support-3.13.1/benchmarks/caller_vs_caller_locations.rb000066400000000000000000000011201456614207700244440ustar00rootroot00000000000000require 'benchmark/ips' Benchmark.ips do |x| x.report("caller() ") { caller } x.report("caller_locations() ") { caller_locations } x.report("caller(1, 2) ") { caller(1, 2) } x.report("caller_locations(1, 2)") { caller_locations(1, 2) } end __END__ caller() 118.586k (±17.7%) i/s - 573.893k caller_locations() 355.988k (±17.8%) i/s - 1.709M caller(1, 2) 336.841k (±18.6%) i/s - 1.615M caller_locations(1, 2) 781.330k (±23.5%) i/s - 3.665M rspec-support-3.13.1/benchmarks/caller_vs_caller_locations_vs_raise.rb000066400000000000000000000125071456614207700263520ustar00rootroot00000000000000# This benchmark arose from rspec/rspec-support#199 where we experimented with # faster ways of generating / capturing a backtrace and whether it made sense # to lazily generate it using `raise` to capture the backtrace via an exception. # See also rspec/rspec-mocks#937 require 'benchmark/ips' def use_raise_to_capture_caller use_raise_lazily.backtrace end def use_raise_lazily raise "nope" rescue StandardError => exception return exception end def create_stack_trace(n, &block) return create_stack_trace(n - 1, &block) if n > 0 yield end [10, 50, 100].each do |frames| puts "-" * 80 puts "With #{frames} extra stack frames" puts "-" * 80 create_stack_trace(frames) do Benchmark.ips do |x| x.report("caller() ") { caller } x.report("caller_locations() ") { caller_locations } x.report("raise with backtrace ") { use_raise_to_capture_caller } x.report("raise and store (lazy)") { use_raise_lazily } x.report("caller(1, 2) ") { caller(1, 2) } x.report("caller_locations(1, 2)") { caller_locations(1, 2) } x.compare! end end end __END__ -------------------------------------------------------------------------------- With 10 extra stack frames -------------------------------------------------------------------------------- Calculating ------------------------------------- caller() 5.583k i/100ms caller_locations() 14.540k i/100ms raise with backtrace 4.544k i/100ms raise and store (lazy) 27.028k i/100ms caller(1, 2) 25.739k i/100ms caller_locations(1, 2) 48.848k i/100ms ------------------------------------------------- caller() 61.386k (±11.6%) i/s - 307.065k caller_locations() 176.033k (±12.8%) i/s - 872.400k raise with backtrace 48.348k (±10.5%) i/s - 240.832k raise and store (lazy) 425.768k (±10.7%) i/s - 2.108M caller(1, 2) 368.142k (±18.9%) i/s - 1.776M caller_locations(1, 2) 834.431k (±17.8%) i/s - 4.054M Comparison: caller_locations(1, 2): 834431.2 i/s raise and store (lazy): 425767.6 i/s - 1.96x slower caller(1, 2) : 368142.0 i/s - 2.27x slower caller_locations() : 176032.6 i/s - 4.74x slower caller() : 61386.0 i/s - 13.59x slower raise with backtrace : 48348.2 i/s - 17.26x slower -------------------------------------------------------------------------------- With 50 extra stack frames -------------------------------------------------------------------------------- Calculating ------------------------------------- caller() 2.282k i/100ms caller_locations() 6.446k i/100ms raise with backtrace 2.138k i/100ms raise and store (lazy) 23.649k i/100ms caller(1, 2) 22.113k i/100ms caller_locations(1, 2) 36.586k i/100ms ------------------------------------------------- caller() 24.105k (± 9.9%) i/s - 120.946k caller_locations() 68.610k (± 7.9%) i/s - 341.638k raise with backtrace 21.458k (± 9.6%) i/s - 106.900k raise and store (lazy) 341.152k (± 8.1%) i/s - 1.703M caller(1, 2) 297.805k (±12.5%) i/s - 1.482M caller_locations(1, 2) 557.278k (±16.6%) i/s - 2.744M Comparison: caller_locations(1, 2): 557278.2 i/s raise and store (lazy): 341151.6 i/s - 1.63x slower caller(1, 2) : 297804.8 i/s - 1.87x slower caller_locations() : 68610.3 i/s - 8.12x slower caller() : 24105.5 i/s - 23.12x slower raise with backtrace : 21458.2 i/s - 25.97x slower -------------------------------------------------------------------------------- With 100 extra stack frames -------------------------------------------------------------------------------- Calculating ------------------------------------- caller() 1.327k i/100ms caller_locations() 3.773k i/100ms raise with backtrace 1.235k i/100ms raise and store (lazy) 19.990k i/100ms caller(1, 2) 18.269k i/100ms caller_locations(1, 2) 29.668k i/100ms ------------------------------------------------- caller() 13.879k (± 9.9%) i/s - 69.004k caller_locations() 39.070k (± 7.6%) i/s - 196.196k raise with backtrace 12.703k (±12.7%) i/s - 62.985k raise and store (lazy) 243.959k (± 8.3%) i/s - 1.219M caller(1, 2) 230.289k (± 8.2%) i/s - 1.151M caller_locations(1, 2) 406.804k (± 8.8%) i/s - 2.047M Comparison: caller_locations(1, 2): 406804.3 i/s raise and store (lazy): 243958.7 i/s - 1.67x slower caller(1, 2) : 230288.9 i/s - 1.77x slower caller_locations() : 39069.8 i/s - 10.41x slower caller() : 13879.4 i/s - 29.31x slower raise with backtrace : 12702.9 i/s - 32.02x slower rspec-support-3.13.1/benchmarks/class_exec_vs_klass_exec.rb000066400000000000000000000022741456614207700241320ustar00rootroot00000000000000require 'benchmark/ips' require 'rspec/support' require 'rspec/support/with_keywords_when_needed' Klass = Class.new do def test(*args, **kwargs) end end def class_exec_args Klass.class_exec(:a, :b) { } end def klass_exec_args RSpec::Support::WithKeywordsWhenNeeded.class_exec(Klass, :a, :b) { } end def class_exec_kw_args Klass.class_exec(a: :b) { |a:| } end def klass_exec_kw_args RSpec::Support::WithKeywordsWhenNeeded.class_exec(Klass, a: :b) { |a:| } end Benchmark.ips do |x| x.report("class_exec(*args) ") { class_exec_args } x.report("klass_exec(*args) ") { klass_exec_args } x.report("class_exec(*args, **kwargs)") { class_exec_kw_args } x.report("klass_exec(*args, **kwargs)") { klass_exec_kw_args } end __END__ Calculating ------------------------------------- class_exec(*args) 5.555M (± 1.6%) i/s - 27.864M in 5.017682s klass_exec(*args) 657.945k (± 4.6%) i/s - 3.315M in 5.051511s class_exec(*args, **kwargs) 2.882M (± 3.3%) i/s - 14.555M in 5.056905s klass_exec(*args, **kwargs) 52.710k (± 4.1%) i/s - 265.188k in 5.041218s rspec-support-3.13.1/benchmarks/map_hash.rb000066400000000000000000000036041456614207700206660ustar00rootroot00000000000000require 'benchmark/ips' def use_map_and_hash_bracket(input) Hash[ input.map { |k, v| [k.to_s, v.to_s] } ] end def use_inject(input) input.inject({}) do |hash, (k, v)| hash[k.to_s] = v.to_s hash end end [10, 100, 1000].each do |size| hash = Hash[1.upto(size).map { |i| [i, i] }] unless use_map_and_hash_bracket(hash) == use_inject(hash) raise "Not the same!" end puts puts "A hash of #{size} pairs" Benchmark.ips do |x| x.report("Use map and Hash[]") { use_map_and_hash_bracket(hash) } x.report("Use inject") { use_inject(hash) } x.compare! end end __END__ `inject` appears to be slightly faster. A hash of 10 pairs Calculating ------------------------------------- Use map and Hash[] 8.742k i/100ms Use inject 9.565k i/100ms ------------------------------------------------- Use map and Hash[] 98.220k (± 6.8%) i/s - 489.552k Use inject 110.130k (± 6.1%) i/s - 554.770k Comparison: Use inject: 110129.9 i/s Use map and Hash[]: 98219.8 i/s - 1.12x slower A hash of 100 pairs Calculating ------------------------------------- Use map and Hash[] 1.080k i/100ms Use inject 1.124k i/100ms ------------------------------------------------- Use map and Hash[] 10.931k (± 4.5%) i/s - 55.080k Use inject 11.494k (± 5.0%) i/s - 57.324k Comparison: Use inject: 11494.4 i/s Use map and Hash[]: 10930.7 i/s - 1.05x slower A hash of 1000 pairs Calculating ------------------------------------- Use map and Hash[] 106.000 i/100ms Use inject 111.000 i/100ms ------------------------------------------------- Use map and Hash[] 1.081k (± 5.1%) i/s - 5.406k Use inject 1.111k (± 4.8%) i/s - 5.550k Comparison: Use inject: 1111.2 i/s Use map and Hash[]: 1080.8 i/s - 1.03x slower rspec-support-3.13.1/benchmarks/ripper.rb000066400000000000000000000017701456614207700204110ustar00rootroot00000000000000require 'benchmark/ips' require 'ripper' ruby_version = defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION puts "#{RUBY_ENGINE} #{ruby_version}" source = File.read(__FILE__) Benchmark.ips do |x| x.report("Ripper") do Ripper.sexp(source) Ripper.lex(source) end end __END__ ruby 1.9.3 Calculating ------------------------------------- Ripper 284.000 i/100ms ruby 2.2.3 Calculating ------------------------------------- Ripper 320.000 i/100ms jruby 1.7.5 Calculating ------------------------------------- Ripper 24.000 i/100ms jruby 1.7.13 Calculating ------------------------------------- Ripper 25.000 i/100ms jruby 1.7.14 Calculating ------------------------------------- Ripper 239.000 i/100ms jruby 1.7.22 Calculating ------------------------------------- Ripper 231.000 i/100ms jruby 9.0.1.0 Calculating ------------------------------------- Ripper 218.000 i/100ms rspec-support-3.13.1/benchmarks/skip_frames_for_caller_filter.rb000066400000000000000000000014651456614207700251510ustar00rootroot00000000000000require 'rspec/support/caller_filter' eval <<-EOS, binding, "/lib/rspec/core/some_file.rb", 1 # make it think this code is in rspec-core class Recurser def self.recurse(times, *args) return RSpec::CallerFilter.first_non_rspec_line(*args) if times.zero? recurse(times - 1, *args) end end EOS # Ensure the correct first_non_rspec_line is found in these cases. puts Recurser.recurse(20, 19) puts Recurser.recurse(20) require 'benchmark/ips' Benchmark.ips do |x| x.report("(no args)") { Recurser.recurse(20) } x.report("(19)") { Recurser.recurse(20, 19) } x.report("(19, 2)") { Recurser.recurse(20, 19, 2) } end __END__ (no args) 13.789k (± 7.8%) i/s - 69.377k (19) 55.410k (± 8.4%) i/s - 275.123k (19, 2) 61.076k (± 8.6%) i/s - 303.637k rspec-support-3.13.1/lib/000077500000000000000000000000001456614207700152075ustar00rootroot00000000000000rspec-support-3.13.1/lib/rspec/000077500000000000000000000000001456614207700163235ustar00rootroot00000000000000rspec-support-3.13.1/lib/rspec/support.rb000066400000000000000000000125321456614207700203670ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # @api private # # Defines a helper method that is optimized to require files from the # named lib. The passed block MUST be `{ |f| require_relative f }` # because for `require_relative` to work properly from within the named # lib the line of code must be IN that lib. # # `require_relative` is preferred when available because it is always O(1), # regardless of the number of dirs in $LOAD_PATH. `require`, on the other # hand, does a linear O(N) search over the dirs in the $LOAD_PATH until # it can resolve the file relative to one of the dirs. def self.define_optimized_require_for_rspec(lib, &require_relative) name = "require_rspec_#{lib}" if RUBY_PLATFORM == 'java' && !Kernel.respond_to?(:require) # JRuby 9.1.17.0 has developed a regression for require (class << self; self; end).__send__(:define_method, name) do |f| Kernel.send(:require, "rspec/#{lib}/#{f}") end elsif Kernel.respond_to?(:require_relative) (class << self; self; end).__send__(:define_method, name) do |f| require_relative.call("#{lib}/#{f}") end else (class << self; self; end).__send__(:define_method, name) do |f| require "rspec/#{lib}/#{f}" end end end define_optimized_require_for_rspec(:support) { |f| require_relative(f) } require_rspec_support "version" require_rspec_support "ruby_features" # @api private KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method) # @api private # # Used internally to get a method handle for a particular object # and method name. # # Includes handling for a few special cases: # # - Objects that redefine #method (e.g. an HTTPRequest struct) # - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator) # - Objects that undefine method and delegate everything to another # object (e.g. Mongoid association objects) if RubyFeatures.supports_rebinding_module_methods? def self.method_handle_for(object, method_name) KERNEL_METHOD_METHOD.bind(object).call(method_name) rescue NameError => original begin handle = object.method(method_name) raise original unless handle.is_a? Method handle rescue Support::AllExceptionsExceptOnesWeMustNotRescue raise original end end else def self.method_handle_for(object, method_name) if ::Kernel === object KERNEL_METHOD_METHOD.bind(object).call(method_name) else object.method(method_name) end rescue NameError => original begin handle = object.method(method_name) raise original unless handle.is_a? Method handle rescue Support::AllExceptionsExceptOnesWeMustNotRescue raise original end end end # @api private # # Used internally to get a class of a given object, even if it does not respond to #class. def self.class_of(object) object.class rescue NoMethodError singleton_class = class << object; self; end singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) } end # A single thread local variable so we don't excessively pollute that namespace. if RUBY_VERSION.to_f >= 2 def self.thread_local_data Thread.current.thread_variable_get(:__rspec) || Thread.current.thread_variable_set(:__rspec, {}) end else def self.thread_local_data Thread.current[:__rspec] ||= {} end end # @api private def self.failure_notifier=(callable) thread_local_data[:failure_notifier] = callable end # @private DEFAULT_FAILURE_NOTIFIER = lambda { |failure, _opts| raise failure } # @api private def self.failure_notifier thread_local_data[:failure_notifier] || DEFAULT_FAILURE_NOTIFIER end # @api private def self.notify_failure(failure, options={}) failure_notifier.call(failure, options) end # @api private def self.with_failure_notifier(callable) orig_notifier = failure_notifier self.failure_notifier = callable yield ensure self.failure_notifier = orig_notifier end class << self # @api private attr_writer :warning_notifier end # @private DEFAULT_WARNING_NOTIFIER = lambda { |warning| ::Kernel.warn warning } # @api private def self.warning_notifier @warning_notifier ||= DEFAULT_WARNING_NOTIFIER end # @private module AllExceptionsExceptOnesWeMustNotRescue # These exceptions are dangerous to rescue as rescuing them # would interfere with things we should not interfere with. AVOID_RESCUING = [NoMemoryError, SignalException, Interrupt, SystemExit] def self.===(exception) AVOID_RESCUING.none? { |ar| ar === exception } end end # The Differ is only needed when a spec fails with a diffable failure. # In the more common case of all specs passing or the only failures being # non-diffable, we can avoid the extra cost of loading the differ, diff-lcs, # pp, etc by avoiding an unnecessary require. Instead, autoload will take # care of loading the differ on first use. autoload :Differ, "rspec/support/differ" end end rspec-support-3.13.1/lib/rspec/support/000077500000000000000000000000001456614207700200375ustar00rootroot00000000000000rspec-support-3.13.1/lib/rspec/support/caller_filter.rb000066400000000000000000000077761456614207700232140ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support "ruby_features" module RSpec # Consistent implementation for "cleaning" the caller method to strip out # non-rspec lines. This enables errors to be reported at the call site in # the code using the library, which is far more useful than the particular # internal method that raised an error. class CallerFilter RSPEC_LIBS = %w[ core mocks expectations support matchers rails ] ADDITIONAL_TOP_LEVEL_FILES = %w[ autorun ] LIB_REGEX = %r{/lib/rspec/(#{(RSPEC_LIBS + ADDITIONAL_TOP_LEVEL_FILES).join('|')})(\.rb|/)} # rubygems/core_ext/kernel_require.rb isn't actually part of rspec (obviously) but we want # it ignored when we are looking for the first meaningful line of the backtrace outside # of RSpec. It can show up in the backtrace as the immediate first caller # when `CallerFilter.first_non_rspec_line` is called from the top level of a required # file, but it depends on if rubygems is loaded or not. We don't want to have to deal # with this complexity in our `RSpec.deprecate` calls, so we ignore it here. IGNORE_REGEX = Regexp.union(LIB_REGEX, "rubygems/core_ext/kernel_require.rb", "(other) other = self.class.new(other) unless other.is_a?(self.class) return 0 if string == other.string longer_segment_count = [self, other].map { |version| version.segments.count }.max longer_segment_count.times do |index| self_segment = segments[index] || 0 other_segment = other.segments[index] || 0 if self_segment.class == other_segment.class result = self_segment <=> other_segment return result unless result == 0 else return self_segment.is_a?(String) ? -1 : 1 end end 0 end def segments @segments ||= string.scan(/[a-z]+|\d+/i).map do |segment| if segment =~ /\A\d+\z/ segment.to_i else segment end end end end end end rspec-support-3.13.1/lib/rspec/support/differ.rb000066400000000000000000000132561456614207700216320ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'encoded_string' RSpec::Support.require_rspec_support 'hunk_generator' RSpec::Support.require_rspec_support "object_formatter" require 'pp' module RSpec module Support # rubocop:disable Metrics/ClassLength class Differ def diff(actual, expected) diff = "" unless actual.nil? || expected.nil? if all_strings?(actual, expected) if any_multiline_strings?(actual, expected) diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected)) end elsif no_procs?(actual, expected) && no_numbers?(actual, expected) diff = diff_as_object(actual, expected) end end diff.to_s end # rubocop:disable Metrics/MethodLength def diff_as_string(actual, expected) encoding = EncodedString.pick_encoding(actual, expected) actual = EncodedString.new(actual, encoding) expected = EncodedString.new(expected, encoding) output = EncodedString.new("\n", encoding) hunks = build_hunks(actual, expected) hunks.each_cons(2) do |prev_hunk, current_hunk| begin if current_hunk.overlaps?(prev_hunk) add_old_hunk_to_hunk(current_hunk, prev_hunk) else add_to_output(output, prev_hunk.diff(format_type).to_s) end ensure add_to_output(output, "\n") end end finalize_output(output, hunks.last.diff(format_type).to_s) if hunks.last color_diff output rescue Encoding::CompatibilityError handle_encoding_errors(actual, expected) end # rubocop:enable Metrics/MethodLength def diff_as_object(actual, expected) actual_as_string = object_to_string(actual) expected_as_string = object_to_string(expected) diff_as_string(actual_as_string, expected_as_string) end def color? @color end def initialize(opts={}) @color = opts.fetch(:color, false) @object_preparer = opts.fetch(:object_preparer, lambda { |string| string }) end private def no_procs?(*args) safely_flatten(args).none? { |a| Proc === a } end def all_strings?(*args) safely_flatten(args).all? { |a| String === a } end def any_multiline_strings?(*args) all_strings?(*args) && safely_flatten(args).any? { |a| multiline?(a) } end def no_numbers?(*args) safely_flatten(args).none? { |a| Numeric === a } end def coerce_to_string(string_or_array) return string_or_array unless Array === string_or_array diffably_stringify(string_or_array).join("\n") end def diffably_stringify(array) array.map do |entry| if Array === entry entry.inspect else entry.to_s.gsub("\n", "\\n").gsub("\r", "\\r") end end end if String.method_defined?(:encoding) def multiline?(string) string.include?("\n".encode(string.encoding)) end else def multiline?(string) string.include?("\n") end end def build_hunks(actual, expected) HunkGenerator.new(actual, expected).hunks end def finalize_output(output, final_line) add_to_output(output, final_line) add_to_output(output, "\n") end def add_to_output(output, string) output << string end def add_old_hunk_to_hunk(hunk, oldhunk) hunk.merge(oldhunk) end def safely_flatten(array) array = array.flatten(1) until (array == array.flatten(1)) array end def format_type :unified end def color(text, color_code) "\e[#{color_code}m#{text}\e[0m" end def red(text) color(text, 31) end def green(text) color(text, 32) end def blue(text) color(text, 34) end def normal(text) color(text, 0) end def color_diff(diff) return diff unless color? diff.lines.map do |line| case line[0].chr when "+" green line when "-" red line when "@" line[1].chr == "@" ? blue(line) : normal(line) else normal(line) end end.join end def object_to_string(object) object = @object_preparer.call(object) case object when Hash hash_to_string(object) when Array PP.pp(ObjectFormatter.prepare_for_inspection(object), "".dup) when String object =~ /\n/ ? object : object.inspect else PP.pp(object, "".dup) end end def hash_to_string(hash) formatted_hash = ObjectFormatter.prepare_for_inspection(hash) formatted_hash.keys.sort_by { |k| k.to_s }.map do |key| pp_key = PP.singleline_pp(key, "".dup) pp_value = PP.singleline_pp(formatted_hash[key], "".dup) "#{pp_key} => #{pp_value}," end.join("\n") end def handle_encoding_errors(actual, expected) if actual.source_encoding != expected.source_encoding "Could not produce a diff because the encoding of the actual string " \ "(#{actual.source_encoding}) differs from the encoding of the expected " \ "string (#{expected.source_encoding})" else "Could not produce a diff because of the encoding of the string " \ "(#{expected.source_encoding})" end end end # rubocop:enable Metrics/ClassLength end end rspec-support-3.13.1/lib/rspec/support/directory_maker.rb000066400000000000000000000033411456614207700235500ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'ruby_features' module RSpec module Support # @api private # # Replacement for fileutils#mkdir_p because we don't want to require parts # of stdlib in RSpec. class DirectoryMaker # @api private # # Implements nested directory construction def self.mkdir_p(path) stack = generate_stack(path) path.split(File::SEPARATOR).each do |part| stack = generate_path(stack, part) begin Dir.mkdir(stack) unless directory_exists?(stack) rescue Errno::EEXIST => e raise e unless directory_exists?(stack) rescue Errno::ENOTDIR => e raise Errno::EEXIST, e.message end end end if OS.windows_file_path? def self.generate_stack(path) if path.start_with?(File::SEPARATOR) File::SEPARATOR elsif path[1] == ':' '' else '.' end end def self.generate_path(stack, part) if stack == '' part elsif stack == File::SEPARATOR File.join('', part) else File.join(stack, part) end end else def self.generate_stack(path) path.start_with?(File::SEPARATOR) ? File::SEPARATOR : "." end def self.generate_path(stack, part) File.join(stack, part) end end def self.directory_exists?(dirname) File.exist?(dirname) && File.directory?(dirname) end private_class_method :directory_exists? private_class_method :generate_stack private_class_method :generate_path end end end rspec-support-3.13.1/lib/rspec/support/encoded_string.rb000066400000000000000000000136771456614207700233710ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # @private class EncodedString # Reduce allocations by storing constants. UTF_8 = "UTF-8" US_ASCII = "US-ASCII" # Ruby's default replacement string is: # U+FFFD ("\xEF\xBF\xBD"), for Unicode encoding forms, else # ? ("\x3F") REPLACE = "?" def initialize(string, encoding=nil) @encoding = encoding @source_encoding = detect_source_encoding(string) @string = matching_encoding(string) end attr_reader :source_encoding delegated_methods = String.instance_methods.map(&:to_s) & %w[eql? lines == encoding empty?] delegated_methods.each do |name| define_method(name) { |*args, &block| @string.__send__(name, *args, &block) } end def <<(string) @string << matching_encoding(string) end if Ruby.jruby? def split(regex_or_string) @string.split(matching_encoding(regex_or_string)) rescue ArgumentError # JRuby raises an ArgumentError when splitting a source string that # contains invalid bytes. remove_invalid_bytes(@string).split regex_or_string end else def split(regex_or_string) @string.split(matching_encoding(regex_or_string)) end end def to_s @string end alias :to_str :to_s if String.method_defined?(:encoding) private # Encoding Exceptions: # # Raised by Encoding and String methods: # Encoding::UndefinedConversionError: # when a transcoding operation fails # if the String contains characters invalid for the target encoding # e.g. "\x80".encode('UTF-8','ASCII-8BIT') # vs "\x80".encode('UTF-8','ASCII-8BIT', undef: :replace, replace: '') # # => '' # Encoding::CompatibilityError # when Encoding.compatible?(str1, str2) is nil # e.g. utf_16le_emoji_string.split("\n") # e.g. valid_unicode_string.encode(utf8_encoding) << ascii_string # Encoding::InvalidByteSequenceError: # when the string being transcoded contains a byte invalid for # either the source or target encoding # e.g. "\x80".encode('UTF-8','US-ASCII') # vs "\x80".encode('UTF-8','US-ASCII', invalid: :replace, replace: '') # # => '' # ArgumentError # when operating on a string with invalid bytes # e.g."\x80".split("\n") # TypeError # when a symbol is passed as an encoding # Encoding.find(:"UTF-8") # when calling force_encoding on an object # that doesn't respond to #to_str # # Raised by transcoding methods: # Encoding::ConverterNotFoundError: # when a named encoding does not correspond with a known converter # e.g. 'abc'.force_encoding('UTF-8').encode('foo') # or a converter path cannot be found # e.g. "\x80".force_encoding('ASCII-8BIT').encode('Emacs-Mule') # # Raised by byte <-> char conversions # RangeError: out of char range # e.g. the UTF-16LE emoji: 128169.chr def matching_encoding(string) string = remove_invalid_bytes(string) string.encode(@encoding) rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError # Originally defined as a constant to avoid unneeded allocations, this hash must # be defined inline (without {}) to avoid warnings on Ruby 2.7 # # In MRI 2.1 'invalid: :replace' changed to also replace an invalid byte sequence # see https://github.com/ruby/ruby/blob/v2_1_0/NEWS#L176 # https://www.ruby-forum.com/topic/6861247 # https://twitter.com/nalsh/status/553413844685438976 # # For example, given: # "\x80".force_encoding("Emacs-Mule").encode(:invalid => :replace).bytes.to_a # # On MRI 2.1 or above: 63 # '?' # else : 128 # "\x80" # string.encode(@encoding, :invalid => :replace, :undef => :replace, :replace => REPLACE) rescue Encoding::ConverterNotFoundError # Originally defined as a constant to avoid unneeded allocations, this hash must # be defined inline (without {}) to avoid warnings on Ruby 2.7 string.dup.force_encoding(@encoding).encode(:invalid => :replace, :replace => REPLACE) end # Prevents raising ArgumentError if String.method_defined?(:scrub) # https://github.com/ruby/ruby/blob/eeb05e8c11/doc/NEWS-2.1.0#L120-L123 # https://github.com/ruby/ruby/blob/v2_1_0/string.c#L8242 # https://github.com/hsbt/string-scrub # https://github.com/rubinius/rubinius/blob/v2.5.2/kernel/common/string.rb#L1913-L1972 def remove_invalid_bytes(string) string.scrub(REPLACE) end else # http://stackoverflow.com/a/8711118/879854 # Loop over chars in a string replacing chars # with invalid encoding, which is a pretty good proxy # for the invalid byte sequence that causes an ArgumentError def remove_invalid_bytes(string) string.chars.map do |char| char.valid_encoding? ? char : REPLACE end.join end end def detect_source_encoding(string) string.encoding end def self.pick_encoding(source_a, source_b) Encoding.compatible?(source_a, source_b) || Encoding.default_external end else def self.pick_encoding(_source_a, _source_b) end private def matching_encoding(string) string end def detect_source_encoding(_string) US_ASCII end end end end end rspec-support-3.13.1/lib/rspec/support/fuzzy_matcher.rb000066400000000000000000000027571456614207700232710ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # Provides a means to fuzzy-match between two arbitrary objects. # Understands array/hash nesting. Uses `===` or `==` to # perform the matching. module FuzzyMatcher # @api private def self.values_match?(expected, actual) if Hash === actual return hashes_match?(expected, actual) if Hash === expected elsif Array === expected && Enumerable === actual && !(Struct === actual) return arrays_match?(expected, actual.to_a) end return true if expected == actual begin expected === actual rescue ArgumentError # Some objects, like 0-arg lambdas on 1.9+, raise # ArgumentError for `expected === actual`. false end end # @private def self.arrays_match?(expected_list, actual_list) return false if expected_list.size != actual_list.size expected_list.zip(actual_list).all? do |expected, actual| values_match?(expected, actual) end end # @private def self.hashes_match?(expected_hash, actual_hash) return false if expected_hash.size != actual_hash.size expected_hash.all? do |expected_key, expected_value| actual_value = actual_hash.fetch(expected_key) { return false } values_match?(expected_value, actual_value) end end private_class_method :arrays_match?, :hashes_match? end end end rspec-support-3.13.1/lib/rspec/support/hunk_generator.rb000066400000000000000000000017041456614207700234010ustar00rootroot00000000000000# frozen_string_literal: true require 'diff/lcs' require 'diff/lcs/hunk' module RSpec module Support # @private class HunkGenerator def initialize(actual, expected) @actual = actual @expected = expected end def hunks @file_length_difference = 0 @hunks ||= diffs.map do |piece| build_hunk(piece) end end private def diffs Diff::LCS.diff(expected_lines, actual_lines) end def expected_lines @expected.split("\n").map! { |e| e.chomp } end def actual_lines @actual.split("\n").map! { |e| e.chomp } end def build_hunk(piece) Diff::LCS::Hunk.new( expected_lines, actual_lines, piece, context_lines, @file_length_difference ).tap do |h| @file_length_difference = h.file_length_difference end end def context_lines 3 end end end end rspec-support-3.13.1/lib/rspec/support/matcher_definition.rb000066400000000000000000000022421456614207700242170ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # @private def self.matcher_definitions @matcher_definitions ||= [] end # Used internally to break cyclic dependency between mocks, expectations, # and support. We don't currently have a consistent implementation of our # matchers, though we are considering changing that: # https://github.com/rspec/rspec-mocks/issues/513 # # @private def self.register_matcher_definition(&block) matcher_definitions << block end # Remove a previously registered matcher. Useful for cleaning up after # yourself in specs. # # @private def self.deregister_matcher_definition(&block) matcher_definitions.delete(block) end # @private def self.is_a_matcher?(object) matcher_definitions.any? { |md| md.call(object) } end # @api private # # gives a string representation of an object for use in RSpec descriptions def self.rspec_description_for_object(object) if RSpec::Support.is_a_matcher?(object) && object.respond_to?(:description) object.description else object end end end end rspec-support-3.13.1/lib/rspec/support/method_signature_verifier.rb000066400000000000000000000326761456614207700256360ustar00rootroot00000000000000# frozen_string_literal: true require 'rspec/support' RSpec::Support.require_rspec_support "ruby_features" RSpec::Support.require_rspec_support "matcher_definition" module RSpec module Support # Extracts info about the number of arguments and allowed/required # keyword args of a given method. # # @private class MethodSignature # rubocop:disable Metrics/ClassLength attr_reader :min_non_kw_args, :max_non_kw_args, :optional_kw_args, :required_kw_args def initialize(method) @method = method @optional_kw_args = [] @required_kw_args = [] classify_parameters end def non_kw_args_arity_description case max_non_kw_args when min_non_kw_args then min_non_kw_args.to_s when INFINITY then "#{min_non_kw_args} or more" else "#{min_non_kw_args} to #{max_non_kw_args}" end end def valid_non_kw_args?(positional_arg_count, optional_max_arg_count=positional_arg_count) return true if positional_arg_count.nil? min_non_kw_args <= positional_arg_count && optional_max_arg_count <= max_non_kw_args end def classify_arity(arity=@method.arity) if arity < 0 # `~` inverts the one's complement and gives us the # number of required args @min_non_kw_args = ~arity @max_non_kw_args = INFINITY else @min_non_kw_args = arity @max_non_kw_args = arity end end if RubyFeatures.optional_and_splat_args_supported? def description @description ||= begin parts = [] unless non_kw_args_arity_description == "0" parts << "arity of #{non_kw_args_arity_description}" end if @optional_kw_args.any? parts << "optional keyword args (#{@optional_kw_args.map(&:inspect).join(", ")})" end if @required_kw_args.any? parts << "required keyword args (#{@required_kw_args.map(&:inspect).join(", ")})" end parts << "any additional keyword args" if @allows_any_kw_args parts.join(" and ") end end def missing_kw_args_from(given_kw_args) @required_kw_args - given_kw_args end def invalid_kw_args_from(given_kw_args) return [] if @allows_any_kw_args given_kw_args - @allowed_kw_args end # If the last argument is Hash, Ruby will treat only symbol keys as keyword arguments # the rest will be grouped in another Hash and passed as positional argument. def has_kw_args_in?(args) Hash === args.last && could_contain_kw_args?(args) && (RubyFeatures.kw_arg_separation? || args.last.empty? || args.last.keys.any? { |x| x.is_a?(Symbol) }) end # Without considering what the last arg is, could it # contain keyword arguments? def could_contain_kw_args?(args) return false if args.count <= min_non_kw_args @allows_any_kw_args || @allowed_kw_args.any? end def arbitrary_kw_args? @allows_any_kw_args end def unlimited_args? @max_non_kw_args == INFINITY end def classify_parameters optional_non_kw_args = @min_non_kw_args = 0 @allows_any_kw_args = false @method.parameters.each do |(type, name)| case type # def foo(a:) when :keyreq then @required_kw_args << name # def foo(a: 1) when :key then @optional_kw_args << name # def foo(**kw_args) when :keyrest then @allows_any_kw_args = true # def foo(a) when :req then @min_non_kw_args += 1 # def foo(a = 1) when :opt then optional_non_kw_args += 1 # def foo(*a) when :rest then optional_non_kw_args = INFINITY end end @max_non_kw_args = @min_non_kw_args + optional_non_kw_args @allowed_kw_args = @required_kw_args + @optional_kw_args end else def description "arity of #{non_kw_args_arity_description}" end def missing_kw_args_from(_given_kw_args) [] end def invalid_kw_args_from(_given_kw_args) [] end def has_kw_args_in?(_args) false end def could_contain_kw_args?(*) false end def arbitrary_kw_args? false end def unlimited_args? false end alias_method :classify_parameters, :classify_arity end INFINITY = 1 / 0.0 end if RSpec::Support::Ruby.jruby? # JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity # https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817 if RubyFeatures.optional_and_splat_args_supported? && Java::JavaLang::String.instance_method(:char_at).parameters == [] class MethodSignature < remove_const(:MethodSignature) private def classify_parameters super if (arity = @method.arity) != 0 && @method.parameters.empty? classify_arity(arity) end end end end # JRuby used to always report -1 arity for Java proxy methods. # The workaround essentially makes use of Java's introspection to figure # out matching methods (which could be more than one partly because Java # supports multiple overloads, and partly because JRuby introduces # aliases to make method names look more Rubyesque). If there is only a # single match, we can use that methods arity directly instead of the # default -1 arity. # # This workaround only works for Java proxy methods, and in order to # support regular methods and blocks, we need to be careful about calling # owner and java_class as they might not be available if Java::JavaLang::String.instance_method(:char_at).arity == -1 class MethodSignature < remove_const(:MethodSignature) private def classify_parameters super return unless @method.arity == -1 return unless @method.respond_to?(:owner) return unless @method.owner.respond_to?(:java_class) java_instance_methods = @method.owner.java_class.java_instance_methods compatible_overloads = java_instance_methods.select do |java_method| @method == @method.owner.instance_method(java_method.name) end if compatible_overloads.size == 1 classify_arity(compatible_overloads.first.arity) end end end end end # Encapsulates expectations about the number of arguments and # allowed/required keyword args of a given method. # # @api private class MethodSignatureExpectation def initialize @min_count = nil @max_count = nil @keywords = [] @expect_unlimited_arguments = false @expect_arbitrary_keywords = false end attr_reader :min_count, :max_count, :keywords attr_accessor :expect_unlimited_arguments, :expect_arbitrary_keywords def max_count=(number) raise ArgumentError, 'must be a non-negative integer or nil' \ unless number.nil? || (number.is_a?(Integer) && number >= 0) @max_count = number end def min_count=(number) raise ArgumentError, 'must be a non-negative integer or nil' \ unless number.nil? || (number.is_a?(Integer) && number >= 0) @min_count = number end def empty? @min_count.nil? && @keywords.to_a.empty? && !@expect_arbitrary_keywords && !@expect_unlimited_arguments end def keywords=(values) @keywords = values.to_a || [] end end # Deals with the slightly different semantics of block arguments. # For methods, arguments are required unless a default value is provided. # For blocks, arguments are optional, even if no default value is provided. # # However, we want to treat block args as required since you virtually # always want to pass a value for each received argument and our # `and_yield` has treated block args as required for many years. # # @api private class BlockSignature < MethodSignature if RubyFeatures.optional_and_splat_args_supported? def classify_parameters super @min_non_kw_args = @max_non_kw_args unless @max_non_kw_args == INFINITY end end end # Abstract base class for signature verifiers. # # @api private class MethodSignatureVerifier attr_reader :non_kw_args, :kw_args, :min_non_kw_args, :max_non_kw_args def initialize(signature, args=[]) @signature = signature @non_kw_args, @kw_args = split_args(*args) @min_non_kw_args = @max_non_kw_args = @non_kw_args @arbitrary_kw_args = @unlimited_args = false end def with_expectation(expectation) # rubocop:disable Metrics/MethodLength return self unless MethodSignatureExpectation === expectation if expectation.empty? @min_non_kw_args = @max_non_kw_args = @non_kw_args = nil @kw_args = [] else @min_non_kw_args = @non_kw_args = expectation.min_count || 0 @max_non_kw_args = expectation.max_count || @min_non_kw_args if RubyFeatures.optional_and_splat_args_supported? @unlimited_args = expectation.expect_unlimited_arguments else @unlimited_args = false end if RubyFeatures.kw_args_supported? @kw_args = expectation.keywords @arbitrary_kw_args = expectation.expect_arbitrary_keywords else @kw_args = [] @arbitrary_kw_args = false end end self end def valid? missing_kw_args.empty? && invalid_kw_args.empty? && valid_non_kw_args? && arbitrary_kw_args? && unlimited_args? end def error_message if missing_kw_args.any? "Missing required keyword arguments: %s" % [ missing_kw_args.join(", ") ] elsif invalid_kw_args.any? "Invalid keyword arguments provided: %s" % [ invalid_kw_args.join(", ") ] elsif !valid_non_kw_args? "Wrong number of arguments. Expected %s, got %s." % [ @signature.non_kw_args_arity_description, non_kw_args ] end end private def valid_non_kw_args? @signature.valid_non_kw_args?(min_non_kw_args, max_non_kw_args) end def missing_kw_args @signature.missing_kw_args_from(kw_args) end def invalid_kw_args @signature.invalid_kw_args_from(kw_args) end def arbitrary_kw_args? !@arbitrary_kw_args || @signature.arbitrary_kw_args? end def unlimited_args? !@unlimited_args || @signature.unlimited_args? end def split_args(*args) kw_args = if @signature.has_kw_args_in?(args) && !RubyFeatures.kw_arg_separation? last = args.pop non_kw_args = last.reject { |k, _| k.is_a?(Symbol) } if non_kw_args.empty? last.keys else args << non_kw_args last.select { |k, _| k.is_a?(Symbol) }.keys end elsif @signature.has_kw_args_in?(args) && RubyFeatures.kw_arg_separation? args.pop.keys else [] end [args.length, kw_args] end end # Figures out whether a given method can accept various arguments. # Surprisingly non-trivial. # # @private StrictSignatureVerifier = MethodSignatureVerifier # Allows matchers to be used instead of providing keyword arguments. In # practice, when this happens only the arity of the method is verified. # # @private class LooseSignatureVerifier < MethodSignatureVerifier private def split_args(*args) if RSpec::Support.is_a_matcher?(args.last) && @signature.could_contain_kw_args?(args) args.pop @signature = SignatureWithKeywordArgumentsMatcher.new(@signature) end super(*args) end # If a matcher is used in a signature in place of keyword arguments, all # keyword argument validation needs to be skipped since the matcher is # opaque. # # Instead, keyword arguments will be validated when the method is called # and they are actually known. # # @private class SignatureWithKeywordArgumentsMatcher def initialize(signature) @signature = signature end def missing_kw_args_from(_kw_args) [] end def invalid_kw_args_from(_kw_args) [] end def non_kw_args_arity_description @signature.non_kw_args_arity_description end def valid_non_kw_args?(*args) @signature.valid_non_kw_args?(*args) end def has_kw_args_in?(args) @signature.has_kw_args_in?(args) end end end end end rspec-support-3.13.1/lib/rspec/support/mutex.rb000066400000000000000000000033511456614207700215300ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # On 1.8.7, it's in the stdlib. # We don't want to load the stdlib, b/c this is a test tool, and can affect # the test environment, causing tests to pass where they should fail. # # So we're transcribing/modifying it from # https://github.com/ruby/ruby/blob/v1_8_7_374/lib/thread.rb#L56 # Some methods we don't need are deleted. Anything I don't # understand (there's quite a bit, actually) is left in. # # Some formatting changes are made to appease the robot overlord: # https://travis-ci.org/rspec/rspec-core/jobs/54410874 # @private class Mutex def initialize @waiting = [] @locked = false @waiting.taint taint end # @private def lock while Thread.critical = true && @locked @waiting.push Thread.current Thread.stop end @locked = true Thread.critical = false self end # @private def unlock return unless @locked Thread.critical = true @locked = false wakeup_and_run_waiting_thread self end # @private def synchronize lock begin yield ensure unlock end end private def wakeup_and_run_waiting_thread begin t = @waiting.shift t.wakeup if t rescue ThreadError retry end Thread.critical = false begin t.run if t rescue ThreadError :noop end end # Avoid warnings for library wide checks spec end unless defined?(::RSpec::Support::Mutex) || defined?(::Mutex) end end rspec-support-3.13.1/lib/rspec/support/object_formatter.rb000066400000000000000000000175401456614207700237240ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'matcher_definition' module RSpec module Support # Provide additional output details beyond what `inspect` provides when # printing Time, DateTime, or BigDecimal # @api private class ObjectFormatter # rubocop:disable Metrics/ClassLength ELLIPSIS = "..." attr_accessor :max_formatted_output_length # Methods are deferred to a default instance of the class to maintain the interface # For example, calling ObjectFormatter.format is still possible def self.default_instance @default_instance ||= new end def self.format(object) default_instance.format(object) end def self.prepare_for_inspection(object) default_instance.prepare_for_inspection(object) end def initialize(max_formatted_output_length=200) @max_formatted_output_length = max_formatted_output_length @current_structure_stack = [] end def format(object) if max_formatted_output_length.nil? prepare_for_inspection(object).inspect else formatted_object = prepare_for_inspection(object).inspect if formatted_object.length < max_formatted_output_length formatted_object else beginning = truncate_string formatted_object, 0, max_formatted_output_length / 2 ending = truncate_string formatted_object, -max_formatted_output_length / 2, -1 beginning + ELLIPSIS + ending end end end # Prepares the provided object to be formatted by wrapping it as needed # in something that, when `inspect` is called on it, will produce the # desired output. # # This allows us to apply the desired formatting to hash/array data structures # at any level of nesting, simply by walking that structure and replacing items # with custom items that have `inspect` defined to return the desired output # for that item. Then we can just use `Array#inspect` or `Hash#inspect` to # format the entire thing. def prepare_for_inspection(object) case object when Array prepare_array(object) when Hash prepare_hash(object) else inspector_class = INSPECTOR_CLASSES.find { |inspector| inspector.can_inspect?(object) } inspector_class.new(object, self) end end def prepare_array(array) with_entering_structure(array) do array.map { |element| prepare_element(element) } end end def prepare_hash(input_hash) with_entering_structure(input_hash) do sort_hash_keys(input_hash).inject({}) do |output_hash, key_and_value| key, value = key_and_value.map { |element| prepare_element(element) } output_hash[key] = value output_hash end end end def sort_hash_keys(input_hash) if input_hash.keys.all? { |k| k.is_a?(String) || k.is_a?(Symbol) } Hash[input_hash.sort_by { |k, _v| k.to_s }] else input_hash end end def prepare_element(element) if recursive_structure?(element) case element when Array then InspectableItem.new('[...]') when Hash then InspectableItem.new('{...}') else raise # This won't happen end else prepare_for_inspection(element) end end def with_entering_structure(structure) @current_structure_stack.push(structure) return_value = yield @current_structure_stack.pop return_value end def recursive_structure?(object) @current_structure_stack.any? { |seen_structure| seen_structure.equal?(object) } end InspectableItem = Struct.new(:text) do def inspect text end def pretty_print(pp) pp.text(text) end end BaseInspector = Struct.new(:object, :formatter) do def self.can_inspect?(_object) raise NotImplementedError end def inspect raise NotImplementedError end def pretty_print(pp) pp.text(inspect) end end class TimeInspector < BaseInspector FORMAT = "%Y-%m-%d %H:%M:%S" def self.can_inspect?(object) Time === object end if Time.method_defined?(:nsec) def inspect object.strftime("#{FORMAT}.#{"%09d" % object.nsec} %z") end else # for 1.8.7 def inspect object.strftime("#{FORMAT}.#{"%06d" % object.usec} %z") end end end class DateTimeInspector < BaseInspector FORMAT = "%a, %d %b %Y %H:%M:%S.%N %z" def self.can_inspect?(object) defined?(DateTime) && DateTime === object end # ActiveSupport sometimes overrides inspect. If `ActiveSupport` is # defined use a custom format string that includes more time precision. def inspect if defined?(ActiveSupport) object.strftime(FORMAT) else object.inspect end end end class BigDecimalInspector < BaseInspector def self.can_inspect?(object) defined?(BigDecimal) && BigDecimal === object end def inspect "#{object.to_s('F')} (#{object.inspect})" end end class DescribableMatcherInspector < BaseInspector def self.can_inspect?(object) Support.is_a_matcher?(object) && object.respond_to?(:description) end def inspect object.description end end class UninspectableObjectInspector < BaseInspector OBJECT_ID_FORMAT = '%#016x' def self.can_inspect?(object) object.inspect false rescue NoMethodError true end def inspect "#<#{klass}:#{native_object_id}>" end def klass Support.class_of(object) end # http://stackoverflow.com/a/2818916 def native_object_id OBJECT_ID_FORMAT % (object.__id__ << 1) rescue NoMethodError # In Ruby 1.9.2, BasicObject responds to none of #__id__, #object_id, #id... '-' end end class DelegatorInspector < BaseInspector def self.can_inspect?(object) defined?(Delegator) && Delegator === object end def inspect "#<#{object.class}(#{formatter.format(object.send(:__getobj__))})>" end end class InspectableObjectInspector < BaseInspector def self.can_inspect?(object) object.inspect true rescue NoMethodError false end def inspect object.inspect end end INSPECTOR_CLASSES = [ TimeInspector, DateTimeInspector, BigDecimalInspector, UninspectableObjectInspector, DescribableMatcherInspector, DelegatorInspector, InspectableObjectInspector ].tap do |classes| # 2.4 has improved BigDecimal formatting so we do not need # to provide our own. # https://github.com/ruby/bigdecimal/pull/42 classes.delete(BigDecimalInspector) if RUBY_VERSION >= '2.4' end private # Returns the substring defined by the start_index and end_index # If the string ends with a partial ANSI code code then that # will be removed as printing partial ANSI # codes to the terminal can lead to corruption def truncate_string(str, start_index, end_index) cut_str = str[start_index..end_index] # ANSI color codes are like: \e[33m so anything with \e[ and a # number without a 'm' is an incomplete color code cut_str.sub(/\e\[\d+$/, '') end end end end rspec-support-3.13.1/lib/rspec/support/recursive_const_methods.rb000066400000000000000000000050441456614207700253270ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # Provides recursive constant lookup methods useful for # constant stubbing. module RecursiveConstMethods # We only want to consider constants that are defined directly on a # particular module, and not include top-level/inherited constants. # Unfortunately, the constant API changed between 1.8 and 1.9, so # we need to conditionally define methods to ignore the top-level/inherited # constants. # # Given: # class A; B = 1; end # class C < A; end # # On 1.8: # - C.const_get("Hash") # => ::Hash # - C.const_defined?("Hash") # => false # - C.constants # => ["B"] # - None of these methods accept the extra `inherit` argument # On 1.9: # - C.const_get("Hash") # => ::Hash # - C.const_defined?("Hash") # => true # - C.const_get("Hash", false) # => raises NameError # - C.const_defined?("Hash", false) # => false # - C.constants # => [:B] # - C.constants(false) #=> [] if Module.method(:const_defined?).arity == 1 def const_defined_on?(mod, const_name) mod.const_defined?(const_name) end def get_const_defined_on(mod, const_name) return mod.const_get(const_name) if const_defined_on?(mod, const_name) raise NameError, "uninitialized constant #{mod.name}::#{const_name}" end def constants_defined_on(mod) mod.constants.select { |c| const_defined_on?(mod, c) } end else def const_defined_on?(mod, const_name) mod.const_defined?(const_name, false) end def get_const_defined_on(mod, const_name) mod.const_get(const_name, false) end def constants_defined_on(mod) mod.constants(false) end end def recursive_const_get(const_name) normalize_const_name(const_name).split('::').inject(Object) do |mod, name| get_const_defined_on(mod, name) end end def recursive_const_defined?(const_name) parts = normalize_const_name(const_name).split('::') parts.inject([Object, '']) do |(mod, full_name), name| yield(full_name, name) if block_given? && !(Module === mod) return false unless const_defined_on?(mod, name) [get_const_defined_on(mod, name), [mod.name, name].join('::')] end end def normalize_const_name(const_name) const_name.sub(/\A::/, '') end end end end rspec-support-3.13.1/lib/rspec/support/reentrant_mutex.rb000066400000000000000000000041431456614207700236120ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support # Allows a thread to lock out other threads from a critical section of code, # while allowing the thread with the lock to reenter that section. # # Based on Monitor as of 2.2 - # https://github.com/ruby/ruby/blob/eb7ddaa3a47bf48045d26c72eb0f263a53524ebc/lib/monitor.rb#L9 # # Depends on Mutex, but Mutex is only available as part of core since 1.9.1: # exists - http://ruby-doc.org/core-1.9.1/Mutex.html # dne - http://ruby-doc.org/core-1.9.0/Mutex.html # # @private class ReentrantMutex def initialize @owner = nil @count = 0 @mutex = Mutex.new end def synchronize enter yield ensure exit end private # This is fixing a bug #501 that is specific to Ruby 3.0. The new implementation # depends on `owned?` that was introduced in Ruby 2.0, so both should work for Ruby 2.x. if RUBY_VERSION.to_f >= 3.0 def enter @mutex.lock unless @mutex.owned? @count += 1 end def exit unless @mutex.owned? raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber" end @count -= 1 @mutex.unlock if @count == 0 end else def enter @mutex.lock if @owner != Thread.current @owner = Thread.current @count += 1 end def exit @count -= 1 return unless @count == 0 @owner = nil @mutex.unlock end end end if defined? ::Mutex # On 1.9 and up, this is in core, so we just use the real one class Mutex < ::Mutex # If you mock Mutex.new you break our usage of Mutex, so # instead we capture the original method to return Mutexes. NEW_MUTEX_METHOD = Mutex.method(:new) def self.new NEW_MUTEX_METHOD.call end end else # For 1.8.7 # :nocov: RSpec::Support.require_rspec_support "mutex" # :nocov: end end end rspec-support-3.13.1/lib/rspec/support/ruby_features.rb000066400000000000000000000124341456614207700232470ustar00rootroot00000000000000# frozen_string_literal: true require 'rbconfig' RSpec::Support.require_rspec_support "comparable_version" module RSpec module Support # @api private # # Provides query methods for different OS or OS features. module OS module_function def windows? !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/) end def windows_file_path? ::File::ALT_SEPARATOR == '\\' end end # @api private # # Provides query methods for different rubies module Ruby module_function def jruby? RUBY_PLATFORM == 'java' end def jruby_version @jruby_version ||= ComparableVersion.new(JRUBY_VERSION) end def jruby_9000? jruby? && JRUBY_VERSION >= '9.0.0.0' end def rbx? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' end def non_mri? !mri? end def mri? !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby' end def truffleruby? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'truffleruby' end end # @api private # # Provides query methods for ruby features that differ among # implementations. module RubyFeatures module_function if Ruby.jruby? && RUBY_VERSION.to_f < 1.9 # On JRuby 1.7 `--1.8` mode, `Process.respond_to?(:fork)` returns true, # but when you try to fork, it raises an error: # NotImplementedError: fork is not available on this platform # # When we drop support for JRuby 1.7 and/or Ruby 1.8, we can drop # this special case. def fork_supported? false end else def fork_supported? Process.respond_to?(:fork) end end def optional_and_splat_args_supported? Method.method_defined?(:parameters) end def caller_locations_supported? respond_to?(:caller_locations, true) end if Exception.method_defined?(:cause) def supports_exception_cause? true end else def supports_exception_cause? false end end if RUBY_VERSION.to_f >= 3.2 def supports_syntax_suggest? true end else def supports_syntax_suggest? false end end if RUBY_VERSION.to_f >= 3.0 # https://rubyreferences.github.io/rubychanges/3.0.html#keyword-arguments-are-now-fully-separated-from-positional-arguments def kw_arg_separation? true end else def kw_arg_separation? false end end if RUBY_VERSION.to_f >= 2.7 def supports_taint? false end else def supports_taint? true end end ripper_requirements = [ComparableVersion.new(RUBY_VERSION) >= '1.9.2'] ripper_requirements.push(false) if Ruby.rbx? if Ruby.jruby? ripper_requirements.push(Ruby.jruby_version >= '1.7.5') # Ripper on JRuby 9.0.0.0.rc1 - 9.1.8.0 reports wrong line number # or cannot parse source including `:if`. # Ripper on JRuby 9.x.x.x < 9.1.17.0 can't handle keyword arguments # Neither can JRuby 9.2, e.g. < 9.2.1.0 ripper_requirements.push(!Ruby.jruby_version.between?('9.0.0.0.rc1', '9.2.0.0')) end # TruffleRuby disables ripper due to low performance ripper_requirements.push(false) if Ruby.truffleruby? if ripper_requirements.all? def ripper_supported? true end else def ripper_supported? false end end def distincts_kw_args_from_positional_hash? RUBY_VERSION >= '3.0.0' end if Ruby.mri? def kw_args_supported? RUBY_VERSION >= '2.0.0' end def required_kw_args_supported? RUBY_VERSION >= '2.1.0' end def supports_rebinding_module_methods? RUBY_VERSION.to_i >= 2 end else # RBX / JRuby et al support is unknown for keyword arguments begin eval("o = Object.new; def o.m(a: 1); end;"\ " raise SyntaxError unless o.method(:m).parameters.include?([:key, :a])") def kw_args_supported? true end rescue SyntaxError def kw_args_supported? false end end begin eval("o = Object.new; def o.m(a: ); end;"\ "raise SyntaxError unless o.method(:m).parameters.include?([:keyreq, :a])") def required_kw_args_supported? true end rescue SyntaxError def required_kw_args_supported? false end end begin Module.new { def foo; end }.instance_method(:foo).bind(Object.new) def supports_rebinding_module_methods? true end rescue TypeError def supports_rebinding_module_methods? false end end end def module_refinement_supported? Module.method_defined?(:refine) || Module.private_method_defined?(:refine) end def module_prepends_supported? Module.method_defined?(:prepend) || Module.private_method_defined?(:prepend) end end end end rspec-support-3.13.1/lib/rspec/support/source.rb000066400000000000000000000047211456614207700216700ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'encoded_string' RSpec::Support.require_rspec_support 'ruby_features' module RSpec module Support # @private # Represents a Ruby source file and provides access to AST and tokens. class Source attr_reader :source, :path # This class protects us against having File read and expand_path # stubbed out within tests. class File class << self [:read, :expand_path].each do |method_name| define_method(method_name, &::File.method(method_name)) end end end def self.from_file(path) source = File.read(path) new(source, path) end if String.method_defined?(:encoding) def initialize(source_string, path=nil) @source = RSpec::Support::EncodedString.new(source_string, Encoding.default_external) @path = path ? File.expand_path(path) : '(string)' end else # for 1.8.7 # :nocov: def initialize(source_string, path=nil) @source = RSpec::Support::EncodedString.new(source_string) @path = path ? File.expand_path(path) : '(string)' end # :nocov: end def lines @lines ||= source.split("\n") end def inspect "#<#{self.class} #{path}>" end if RSpec::Support::RubyFeatures.ripper_supported? RSpec::Support.require_rspec_support 'source/node' RSpec::Support.require_rspec_support 'source/token' def ast @ast ||= begin require 'ripper' sexp = Ripper.sexp(source) raise SyntaxError unless sexp Node.new(sexp) end end def tokens @tokens ||= begin require 'ripper' tokens = Ripper.lex(source) Token.tokens_from_ripper_tokens(tokens) end end def nodes_by_line_number @nodes_by_line_number ||= begin nodes_by_line_number = ast.select(&:location).group_by { |node| node.location.line } Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number) end end def tokens_by_line_number @tokens_by_line_number ||= begin nodes_by_line_number = tokens.group_by { |token| token.location.line } Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number) end end end end end end rspec-support-3.13.1/lib/rspec/support/source/000077500000000000000000000000001456614207700213375ustar00rootroot00000000000000rspec-support-3.13.1/lib/rspec/support/source/location.rb000066400000000000000000000010671456614207700235000ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support class Source # @private # Represents a source location of node or token. Location = Struct.new(:line, :column) do include Comparable def self.location?(array) array.is_a?(Array) && array.size == 2 && array.all? { |e| e.is_a?(Integer) } end def <=>(other) line_comparison = (line <=> other.line) return line_comparison unless line_comparison == 0 column <=> other.column end end end end end rspec-support-3.13.1/lib/rspec/support/source/node.rb000066400000000000000000000052171456614207700226160ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'source/location' module RSpec module Support class Source # @private # A wrapper for Ripper AST node which is generated with `Ripper.sexp`. class Node include Enumerable attr_reader :sexp, :parent def self.sexp?(array) array.is_a?(Array) && array.first.is_a?(Symbol) end def initialize(ripper_sexp, parent=nil) @sexp = ripper_sexp.freeze @parent = parent end def type sexp[0] end def args @args ||= raw_args.map do |raw_arg| if Node.sexp?(raw_arg) Node.new(raw_arg, self) elsif Location.location?(raw_arg) Location.new(*raw_arg) elsif raw_arg.is_a?(Array) ExpressionSequenceNode.new(raw_arg, self) else raw_arg end end.freeze end def children @children ||= args.select { |arg| arg.is_a?(Node) }.freeze end def location @location ||= args.find { |arg| arg.is_a?(Location) } end # We use a loop here (instead of recursion) to prevent SystemStackError def each return to_enum(__method__) unless block_given? node_queue = [] node_queue << self while (current_node = node_queue.shift) yield current_node node_queue.concat(current_node.children) end end def each_ancestor return to_enum(__method__) unless block_given? current_node = self while (current_node = current_node.parent) yield current_node end end def inspect "#<#{self.class} #{type}>" end private def raw_args sexp[1..-1] || [] end end # @private # Basically `Ripper.sexp` generates arrays whose first element is a symbol (type of sexp), # but it exceptionally generates typeless arrays for expression sequence: # # Ripper.sexp('foo; bar') # => [ # :program, # [ # Typeless array # [:vcall, [:@ident, "foo", [1, 0]]], # [:vcall, [:@ident, "bar", [1, 5]]] # ] # ] # # We wrap typeless arrays in this pseudo type node # so that it can be handled in the same way as other type node. class ExpressionSequenceNode < Node def type :_expression_sequence end private def raw_args sexp end end end end end rspec-support-3.13.1/lib/rspec/support/source/token.rb000066400000000000000000000043611456614207700230100ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support 'source/location' module RSpec module Support class Source # @private # A wrapper for Ripper token which is generated with `Ripper.lex`. class Token CLOSING_TYPES_BY_OPENING_TYPE = { :on_lbracket => :on_rbracket, :on_lparen => :on_rparen, :on_lbrace => :on_rbrace, :on_heredoc_beg => :on_heredoc_end }.freeze CLOSING_KEYWORDS_BY_OPENING_KEYWORD = { 'def' => 'end', 'do' => 'end', }.freeze attr_reader :token def self.tokens_from_ripper_tokens(ripper_tokens) ripper_tokens.map { |ripper_token| new(ripper_token) }.freeze end def initialize(ripper_token) @token = ripper_token.freeze end def location @location ||= Location.new(*token[0]) end def type token[1] end def string token[2] end def ==(other) token == other.token end alias_method :eql?, :== def inspect "#<#{self.class} #{type} #{string.inspect}>" end def keyword? type == :on_kw end def equals_operator? type == :on_op && string == '=' end def opening? opening_delimiter? || opening_keyword? end def closed_by?(other) delimiter_closed_by?(other) || keyword_closed_by?(other) end private def opening_delimiter? CLOSING_TYPES_BY_OPENING_TYPE.key?(type) end def opening_keyword? return false unless keyword? CLOSING_KEYWORDS_BY_OPENING_KEYWORD.key?(string) end def delimiter_closed_by?(other) other.type == CLOSING_TYPES_BY_OPENING_TYPE[type] end def keyword_closed_by?(other) return false unless keyword? return true if other.string == CLOSING_KEYWORDS_BY_OPENING_KEYWORD[string] # Ruby 3's `end`-less method definition: `def method_name = body` string == 'def' && other.equals_operator? && location.line == other.location.line end end end end end rspec-support-3.13.1/lib/rspec/support/spec.rb000066400000000000000000000050371456614207700213230ustar00rootroot00000000000000# frozen_string_literal: true require 'rspec/support' require 'rspec/support/spec/in_sub_process' RSpec::Support.require_rspec_support "spec/deprecation_helpers" RSpec::Support.require_rspec_support "spec/diff_helpers" RSpec::Support.require_rspec_support "spec/with_isolated_stderr" RSpec::Support.require_rspec_support "spec/stderr_splitter" RSpec::Support.require_rspec_support "spec/formatting_support" RSpec::Support.require_rspec_support "spec/with_isolated_directory" RSpec::Support.require_rspec_support "ruby_features" warning_preventer = $stderr = RSpec::Support::StdErrSplitter.new($stderr) RSpec.configure do |c| c.include RSpecHelpers c.include RSpec::Support::WithIsolatedStdErr c.include RSpec::Support::FormattingSupport c.include RSpec::Support::InSubProcess unless defined?(Debugger) # debugger causes warnings when used c.before do warning_preventer.reset! end c.after do warning_preventer.verify_no_warnings! end end if c.files_to_run.one? c.full_backtrace = true c.default_formatter = 'doc' end c.filter_run_when_matching :focus c.example_status_persistence_file_path = "./spec/examples.txt" c.define_derived_metadata :failing_on_windows_ci do |meta| meta[:pending] ||= "This spec fails on Windows CI and needs someone to fix it." end if RSpec::Support::OS.windows? && ENV['CI'] end module RSpec module Support module Spec def self.setup_simplecov(&block) # Simplecov emits some ruby warnings when loaded, so silence them. old_verbose, $VERBOSE = $VERBOSE, false return if ENV['NO_COVERAGE'] || RUBY_VERSION < '1.9.3' return if RUBY_ENGINE != 'ruby' || RSpec::Support::OS.windows? # Don't load it when we're running a single isolated # test file rather than the whole suite. return if RSpec.configuration.files_to_run.one? require 'simplecov' start_simplecov(&block) rescue LoadError warn "Simplecov could not be loaded" ensure $VERBOSE = old_verbose end def self.start_simplecov(&block) SimpleCov.start do add_filter "bundle/" add_filter "tmp/" add_filter do |source_file| # Filter out `spec` directory except when it is under `lib` # (as is the case in rspec-support) source_file.filename.include?('/spec/') && !source_file.filename.include?('/lib/') end instance_eval(&block) if block end end private_class_method :start_simplecov end end end rspec-support-3.13.1/lib/rspec/support/spec/000077500000000000000000000000001456614207700207715ustar00rootroot00000000000000rspec-support-3.13.1/lib/rspec/support/spec/deprecation_helpers.rb000066400000000000000000000031621456614207700253370ustar00rootroot00000000000000# frozen_string_literal: true module RSpecHelpers def expect_deprecation_with_call_site(file, line, snippet=//) expect(RSpec.configuration.reporter).to receive(:deprecation). with(include(:deprecated => match(snippet), :call_site => include([file, line].join(':')))) end def expect_deprecation_without_call_site(snippet=//) expect(RSpec.configuration.reporter).to receive(:deprecation). with(include(:deprecated => match(snippet), :call_site => eq(nil))) end def expect_warn_deprecation_with_call_site(file, line, snippet=//) expect(RSpec.configuration.reporter).to receive(:deprecation). with(include(:message => match(snippet), :call_site => include([file, line].join(':')))) end def expect_warn_deprecation(snippet=//) expect(RSpec.configuration.reporter).to receive(:deprecation). with(include(:message => match(snippet))) end def allow_deprecation allow(RSpec.configuration.reporter).to receive(:deprecation) end def expect_no_deprecations expect(RSpec.configuration.reporter).not_to receive(:deprecation) end alias expect_no_deprecation expect_no_deprecations def expect_warning_without_call_site(expected=//) expect(::Kernel).to receive(:warn). with(match(expected).and(satisfy { |message| !(/Called from/ =~ message) })) end def expect_warning_with_call_site(file, line, expected=//) expect(::Kernel).to receive(:warn). with(match(expected).and(match(/Called from #{file}:#{line}/))) end def expect_no_warnings expect(::Kernel).not_to receive(:warn) end def allow_warning allow(::Kernel).to receive(:warn) end end rspec-support-3.13.1/lib/rspec/support/spec/diff_helpers.rb000066400000000000000000000014451456614207700237540ustar00rootroot00000000000000# frozen_string_literal: true require 'diff/lcs' module RSpec module Support module Spec module DiffHelpers # In the updated version of diff-lcs several diff headers change format slightly # compensate for this and change minimum version in RSpec 4 if ::Diff::LCS::VERSION.to_f < 1.4 def one_line_header(line_number=2) "-1,#{line_number} +1,#{line_number}" end else def one_line_header(_=2) "-1 +1" end end if Diff::LCS::VERSION.to_f < 1.4 || Diff::LCS::VERSION >= "1.4.4" def removing_two_line_header "-1,3 +1" end else def removing_two_line_header "-1,3 +1,5" end end end end end end rspec-support-3.13.1/lib/rspec/support/spec/formatting_support.rb000066400000000000000000000002671456614207700252710ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support module FormattingSupport def dedent(string) string.gsub(/^\s+\|/, '').chomp end end end end rspec-support-3.13.1/lib/rspec/support/spec/in_sub_process.rb000066400000000000000000000046401456614207700243370ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support module InSubProcess if Process.respond_to?(:fork) && !(Ruby.jruby? && RUBY_VERSION == '1.8.7') UnmarshableObject = Struct.new(:error) # Useful as a way to isolate a global change to a subprocess. def in_sub_process(prevent_warnings=true) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize exception_reader, exception_writer = IO.pipe result_reader, result_writer = IO.pipe # Set binary mode to avoid errors surrounding ascii-8bit to utf-8 conversion # this happens with warnings on rspec-rails for example [exception_reader, exception_writer, result_reader, result_writer].each { |io| io.binmode } pid = Process.fork do warning_preventer = $stderr = RSpec::Support::StdErrSplitter.new($stderr) begin result = yield warning_preventer.verify_no_warnings! if prevent_warnings # rubocop:disable Lint/HandleExceptions rescue Support::AllExceptionsExceptOnesWeMustNotRescue => exception # rubocop:enable Lint/HandleExceptions end exception_writer.write marshal_dump_with_unmarshable_object_handling(exception) exception_reader.close exception_writer.close result_writer.write marshal_dump_with_unmarshable_object_handling(result) result_reader.close result_writer.close exit! # prevent at_exit hooks from running (e.g. minitest) end exception_writer.close result_writer.close Process.waitpid(pid) exception = Marshal.load(exception_reader.read) exception_reader.close raise exception if exception result = Marshal.load(result_reader.read) result_reader.close result end alias :in_sub_process_if_possible :in_sub_process def marshal_dump_with_unmarshable_object_handling(object) Marshal.dump(object) rescue TypeError => error Marshal.dump(UnmarshableObject.new(error)) end else def in_sub_process(*) skip "This spec requires forking to work properly, " \ "and your platform does not support forking" end def in_sub_process_if_possible(*) yield end end end end end rspec-support-3.13.1/lib/rspec/support/spec/library_wide_checks.rb000066400000000000000000000124711456614207700253170ustar00rootroot00000000000000# frozen_string_literal: true require 'rspec/support/spec/shell_out' module RSpec module Support module WhitespaceChecks # This malformed whitespace detection logic has been borrowed from bundler: # https://github.com/bundler/bundler/blob/v1.8.0/spec/quality_spec.rb def check_for_tab_characters(filename) failing_lines = [] File.readlines(filename).each_with_index do |line, number| failing_lines << number + 1 if line =~ /\t/ end return if failing_lines.empty? "#{filename} has tab characters on lines #{failing_lines.join(', ')}" end def check_for_extra_spaces(filename) failing_lines = [] File.readlines(filename).each_with_index do |line, number| next if line =~ /^\s+#.*\s+\n$/ failing_lines << number + 1 if line =~ /\s+\n$/ end return if failing_lines.empty? "#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}" end end end end RSpec.shared_examples_for "library wide checks" do |lib, options| consider_a_test_env_file = options.fetch(:consider_a_test_env_file, /MATCHES NOTHING/) allowed_loaded_feature_regexps = options.fetch(:allowed_loaded_feature_regexps, []) preamble_for_lib = options[:preamble_for_lib] preamble_for_spec = "require 'rspec/core'; require 'spec_helper'" skip_spec_files = options.fetch(:skip_spec_files, /MATCHES NOTHING/) include RSpec::Support::ShellOut include RSpec::Support::WhitespaceChecks define_method :files_to_require_for do |sub_dir| slash = File::SEPARATOR lib_path_re = /#{slash + lib}[^#{slash}]*#{slash}lib/ load_path = $LOAD_PATH.grep(lib_path_re).first directory = load_path.sub(/lib$/, sub_dir) files = Dir["#{directory}/**/*.rb"] extract_regex = /#{Regexp.escape(directory) + File::SEPARATOR}(.+)\.rb$/ # We sort to ensure the files are loaded in a consistent order, regardless # of OS. Otherwise, it could load in a different order on Travis than # locally, and potentially trigger a "circular require considered harmful" # warning or similar. files.sort.map { |file| file[extract_regex, 1] } end def command_from(code_lines) code_lines.join("\n") end def load_all_files(files, preamble, postamble=nil) requires = files.map { |f| "require '#{f}'" } command = command_from(Array(preamble) + requires + Array(postamble)) stdout, stderr, status = with_env 'NO_COVERAGE' => '1' do options = %w[ -w ] options << "--disable=gem" if RUBY_VERSION.to_f >= 1.9 && RSpec::Support::Ruby.mri? run_ruby_with_current_load_path(command, *options) end [stdout, strip_known_warnings(stderr), status.exitstatus] end define_method :load_all_lib_files do files = all_lib_files - lib_test_env_files preamble = ['orig_loaded_features = $".dup', preamble_for_lib] postamble = ['puts(($" - orig_loaded_features).join("\n"))'] @loaded_feature_lines, stderr, exitstatus = load_all_files(files, preamble, postamble) ["", stderr, exitstatus] end define_method :load_all_spec_files do files = files_to_require_for("spec") + lib_test_env_files files = files.reject { |f| f =~ skip_spec_files } load_all_files(files, preamble_for_spec) end attr_reader :all_lib_files, :lib_test_env_files, :lib_file_results, :spec_file_results before(:context) do @all_lib_files = files_to_require_for("lib") @lib_test_env_files = all_lib_files.grep(consider_a_test_env_file) @lib_file_results, @spec_file_results = [ # Load them in parallel so it's faster... Thread.new { load_all_lib_files }, Thread.new { load_all_spec_files } ].map(&:join).map(&:value) end def have_successful_no_warnings_output eq ["", "", 0] end it "issues no warnings when loaded", :slow do expect(lib_file_results).to have_successful_no_warnings_output end it "issues no warnings when the spec files are loaded", :slow do expect(spec_file_results).to have_successful_no_warnings_output end it 'only loads a known set of stdlibs so gem authors are forced ' \ 'to load libs they use to have passing specs', :slow do loaded_features = @loaded_feature_lines.split("\n") if RUBY_VERSION == '1.8.7' # On 1.8.7, $" returns the relative require path if that was used # to require the file. LIB_REGEX will not match the relative version # since it has a `/lib` prefix. Here we deal with this by expanding # relative files relative to the $LOAD_PATH dir (lib). Dir.chdir("lib") { loaded_features.map! { |f| File.expand_path(f) } } end loaded_features.reject! { |feature| RSpec::CallerFilter::LIB_REGEX =~ feature } loaded_features.reject! { |feature| allowed_loaded_feature_regexps.any? { |r| r =~ feature } } expect(loaded_features).to eq([]) end RSpec::Matchers.define :be_well_formed do match do |actual| actual.empty? end failure_message do |actual| actual.join("\n") end end it "has no malformed whitespace", :slow do error_messages = [] `git ls-files -z`.split("\x0").each do |filename| error_messages << check_for_tab_characters(filename) error_messages << check_for_extra_spaces(filename) end expect(error_messages.compact).to be_well_formed end end rspec-support-3.13.1/lib/rspec/support/spec/shell_out.rb000066400000000000000000000064601456614207700233220ustar00rootroot00000000000000# frozen_string_literal: true require 'open3' require 'rake/file_utils' require 'shellwords' module RSpec module Support module ShellOut def with_env(vars) original = ENV.to_hash vars.each { |k, v| ENV[k] = v } begin yield ensure ENV.replace(original) end end if Open3.respond_to?(:capture3) # 1.9+ def shell_out(*command) stdout, stderr, status = Open3.capture3(*command) return stdout, filter(stderr), status end else # 1.8.7 # popen3 doesn't provide the exit status so we fake it out. FakeProcessStatus = Struct.new(:exitstatus) def shell_out(*command) stdout = stderr = nil Open3.popen3(*command) do |_in, out, err| stdout = out.read stderr = err.read end status = FakeProcessStatus.new(0) return stdout, filter(stderr), status end end def run_ruby_with_current_load_path(ruby_command, *flags) command = [ FileUtils::RUBY, "-I#{$LOAD_PATH.map(&:shellescape).join(File::PATH_SEPARATOR)}", "-e", ruby_command, *flags ] # Unset these env vars because `ruby -w` will issue warnings whenever # they are set to non-default values. with_env 'RUBY_GC_HEAP_FREE_SLOTS' => nil, 'RUBY_GC_MALLOC_LIMIT' => nil, 'RUBY_FREE_MIN' => nil do shell_out(*command) end end LINES_TO_IGNORE = [ # Ignore bundler warning. %r{bundler/source/rubygems}, # Ignore bundler + rubygems warning. %r{site_ruby/\d\.\d\.\d/rubygems}, %r{jruby-\d\.\d\.\d+\.\d/lib/ruby/stdlib/rubygems}, # This is required for windows for some reason %r{lib/bundler/rubygems}, # This is a JRuby file that generates warnings on 9.0.3.0 %r{lib/ruby/stdlib/jar}, # This is a JRuby file that generates warnings on 9.1.7.0 %r{org/jruby/RubyKernel\.java}, # This is a JRuby gem that generates warnings on 9.1.7.0 %r{ffi-1\.13\.\d+-java}, %r{uninitialized constant FFI}, # These are related to the above, there is a warning about io from FFI %r{jruby-\d\.\d\.\d+\.\d/lib/ruby/stdlib/io}, %r{io/console on JRuby shells out to stty for most operations}, # This is a JRuby 9.1.17.0 error on Github Actions %r{io/console not supported; tty will not be manipulated}, # This is a JRuby 9.2.1.x error %r{jruby/kernel/gem_prelude}, %r{lib/jruby\.jar!/jruby/preludes}, # Ignore some JRuby errors for gems %r{jruby/\d\.\d(\.\d)?/gems/aruba}, %r{jruby/\d\.\d(\.\d)?/gems/ffi}, ] def strip_known_warnings(input) input.split("\n").reject do |l| LINES_TO_IGNORE.any? { |to_ignore| l =~ to_ignore } || # Remove blank lines l == "" || l.nil? end.join("\n") end private if Ruby.jruby? def filter(output) output.each_line.reject do |line| line.include?("lib/ruby/shared/rubygems") end.join($/) end else def filter(output) output end end end end end rspec-support-3.13.1/lib/rspec/support/spec/stderr_splitter.rb000066400000000000000000000041071456614207700245510ustar00rootroot00000000000000# frozen_string_literal: true require 'stringio' module RSpec module Support class StdErrSplitter def initialize(original) @orig_stderr = original @output_tracker = ::StringIO.new @last_line = nil end respond_to_name = (::RUBY_VERSION.to_f < 1.9) ? :respond_to? : :respond_to_missing? define_method respond_to_name do |*args| @orig_stderr.respond_to?(*args) || super(*args) end def method_missing(name, *args, &block) @output_tracker.__send__(name, *args, &block) if @output_tracker.respond_to?(name) @orig_stderr.__send__(name, *args, &block) end def ==(other) @orig_stderr == other end def reopen(*args) reset! @orig_stderr.reopen(*args) end # To work around JRuby error: # can't convert RSpec::Support::StdErrSplitter into String def to_io @orig_stderr.to_io end # To work around JRuby error: # TypeError: $stderr must have write method, RSpec::StdErrSplitter given def write(line) return if line =~ %r{^\S+/gems/\S+:\d+: warning:} # http://rubular.com/r/kqeUIZOfPG # Ruby 2.7.0 warnings from keyword arguments span multiple lines, extend check above # to look for the next line. return if @last_line =~ %r{^\S+/gems/\S+:\d+: warning:} && line =~ %r{warning: The called method .* is defined here} # Ruby 2.7.0 complains about hashes used in place of keyword arguments # Aruba 0.14.2 uses this internally triggering that here return if line =~ %r{lib/ruby/2\.7\.0/fileutils\.rb:622: warning:} @orig_stderr.write(line) @output_tracker.write(line) ensure @last_line = line end def has_output? !output.empty? end def reset! @output_tracker = ::StringIO.new end def verify_no_warnings! raise "Warnings were generated: #{output}" if has_output? reset! end def output @output_tracker.string end end end end rspec-support-3.13.1/lib/rspec/support/spec/string_matcher.rb000066400000000000000000000026451456614207700243360ustar00rootroot00000000000000# frozen_string_literal: true require 'rspec/matchers' # Special matcher for comparing encoded strings so that # we don't run any expectation failures through the Differ, # which also relies on EncodedString. Instead, confirm the # strings have the same bytes. RSpec::Matchers.define :be_identical_string do |expected| if String.method_defined?(:encoding) match do expected_encoding? && actual.bytes.to_a == expected.bytes.to_a end failure_message do "expected\n#{actual.inspect} (#{actual.encoding.name}) to be identical to\n"\ "#{expected.inspect} (#{expected.encoding.name})\n"\ "The exact bytes are printed below for more detail:\n"\ "#{actual.bytes.to_a}\n"\ "#{expected.bytes.to_a}\n"\ end # Depends on chaining :with_same_encoding for it to # check for string encoding. def expected_encoding? if defined?(@expect_same_encoding) && @expect_same_encoding actual.encoding == expected.encoding else true end end else match do actual.split(//) == expected.split(//) end failure_message do "expected\n#{actual.inspect} to be identical to\n#{expected.inspect}\n" end end chain :with_same_encoding do @expect_same_encoding ||= true end end RSpec::Matchers.alias_matcher :a_string_identical_to, :be_identical_string RSpec::Matchers.alias_matcher :be_diffed_as, :be_identical_string rspec-support-3.13.1/lib/rspec/support/spec/with_isolated_directory.rb000066400000000000000000000004371456614207700262450ustar00rootroot00000000000000# frozen_string_literal: true require 'tmpdir' RSpec.shared_context "isolated directory" do around do |ex| Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir, &ex) end end end RSpec.configure do |c| c.include_context "isolated directory", :isolated_directory => true end rspec-support-3.13.1/lib/rspec/support/spec/with_isolated_stderr.rb000066400000000000000000000004061456614207700255400ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support module WithIsolatedStdErr def with_isolated_stderr original = $stderr $stderr = StringIO.new yield ensure $stderr = original end end end end rspec-support-3.13.1/lib/rspec/support/version.rb000066400000000000000000000001721456614207700220510ustar00rootroot00000000000000# frozen_string_literal: true module RSpec module Support module Version STRING = '3.13.1' end end end rspec-support-3.13.1/lib/rspec/support/warnings.rb000066400000000000000000000021531456614207700222150ustar00rootroot00000000000000# frozen_string_literal: true require 'rspec/support' RSpec::Support.require_rspec_support "caller_filter" module RSpec module Support module Warnings def deprecate(deprecated, options={}) warn_with "DEPRECATION: #{deprecated} is deprecated.", options end # @private # # Used internally to print deprecation warnings # when rspec-core isn't loaded def warn_deprecation(message, options={}) warn_with "DEPRECATION: \n #{message}", options end # @private # # Used internally to print warnings def warning(text, options={}) warn_with "WARNING: #{text}.", options end # @private # # Used internally to print longer warnings def warn_with(message, options={}) call_site = options.fetch(:call_site) { CallerFilter.first_non_rspec_line } message += " Use #{options[:replacement]} instead." if options[:replacement] message += " Called from #{call_site}." if call_site Support.warning_notifier.call message end end end extend RSpec::Support::Warnings end rspec-support-3.13.1/lib/rspec/support/with_keywords_when_needed.rb000066400000000000000000000020551456614207700256150ustar00rootroot00000000000000# frozen_string_literal: true RSpec::Support.require_rspec_support("method_signature_verifier") module RSpec module Support module WithKeywordsWhenNeeded # This module adds keyword sensitive support for core ruby methods # where we cannot use `ruby2_keywords` directly. module_function if RSpec::Support::RubyFeatures.kw_args_supported? # Remove this in RSpec 4 in favour of explicitly passed in kwargs where # this is used. Works around a warning in Ruby 2.7 def class_exec(klass, *args, &block) if MethodSignature.new(block).has_kw_args_in?(args) binding.eval(<<-CODE, __FILE__, __LINE__) kwargs = args.pop klass.class_exec(*args, **kwargs, &block) CODE else klass.class_exec(*args, &block) end end ruby2_keywords :class_exec if respond_to?(:ruby2_keywords, true) else def class_exec(klass, *args, &block) klass.class_exec(*args, &block) end end end end end rspec-support-3.13.1/maintenance-branch000066400000000000000000000000211456614207700200720ustar00rootroot000000000000003-13-maintenance rspec-support-3.13.1/rspec-support.gemspec000066400000000000000000000032341456614207700206360ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'rspec/support/version' Gem::Specification.new do |spec| spec.name = "rspec-support" spec.version = RSpec::Support::Version::STRING spec.authors = ["David Chelimsky","Myron Marson","Jon Rowe","Sam Phippen","Xaviery Shay","Bradley Schaefer"] spec.email = "rspec-users@rubyforge.org" spec.homepage = "https://github.com/rspec/rspec-support" spec.summary = "rspec-support-#{RSpec::Support::Version::STRING}" spec.description = "Support utilities for RSpec gems" spec.license = "MIT" spec.metadata = { 'bug_tracker_uri' => 'https://github.com/rspec/rspec-support/issues', 'changelog_uri' => "https://github.com/rspec/rspec-support/blob/v#{spec.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-support', } spec.files = `git ls-files -- lib/*`.split("\n") spec.files += %w[README.md LICENSE.md Changelog.md] spec.test_files = [] spec.rdoc_options = ["--charset=UTF-8"] spec.require_paths = ["lib"] private_key = File.expand_path('~/.gem/rspec-gem-private_key.pem') if File.exist?(private_key) spec.signing_key = private_key spec.cert_chain = [File.expand_path('~/.gem/rspec-gem-public_cert.pem')] end spec.required_ruby_version = '>= 1.8.7' spec.add_development_dependency "rake", "> 10.0.0" spec.add_development_dependency "thread_order", "~> 1.1.0" end rspec-support-3.13.1/script/000077500000000000000000000000001456614207700157455ustar00rootroot00000000000000rspec-support-3.13.1/script/ci_functions.sh000066400000000000000000000024471456614207700207730ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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}" fold() { local name="$1" local status=0 shift 1 echo "============= Starting $name ===============" "$@" status=$? if [ "$status" -eq 0 ]; then echo "============= Ending $name ===============" else STATUS="$status" fi return $status } rspec-support-3.13.1/script/clone_all_rspec_repos000077500000000000000000000011461456614207700222310ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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-metagem" "rspec" clone_repo "rspec-core" clone_repo "rspec-expectations" clone_repo "rspec-mocks" clone_repo "rspec-rails" "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-support-3.13.1/script/cucumber.sh000077500000000000000000000003421456614207700201100ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/script/functions.sh000066400000000000000000000141171456614207700203150ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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. 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 DIR_TARGET="$1" else DIR_TARGET="$2" fi if [ -z "$3" ]; then BRANCH_TO_CLONE="${MAINTENANCE_BRANCH?}"; else BRANCH_TO_CLONE="$3"; fi; ci_retry eval "git clone https://github.com/rspec/$1 --depth 1 --branch ${BRANCH_TO_CLONE?} ${DIR_TARGET?}" 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-support-3.13.1/script/legacy_setup.sh000077500000000000000000000007721456614207700207760ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/script/predicate_functions.sh000066400000000000000000000055511456614207700223370ustar00rootroot00000000000000# This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/script/run_build000077500000000000000000000015171456614207700176620ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/script/run_rubocop000077500000000000000000000006361456614207700202350ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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-support-3.13.1/script/update_rubygems_and_install_bundler000077500000000000000000000012361456614207700251570ustar00rootroot00000000000000#!/bin/bash # This file was generated on 2024-02-23T14:21:37+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 most recent rubygems / bundler" yes | gem update --no-document --system yes | gem install --no-document bundler 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-support-3.13.1/spec/000077500000000000000000000000001456614207700153735ustar00rootroot00000000000000rspec-support-3.13.1/spec/rspec/000077500000000000000000000000001456614207700165075ustar00rootroot00000000000000rspec-support-3.13.1/spec/rspec/support/000077500000000000000000000000001456614207700202235ustar00rootroot00000000000000rspec-support-3.13.1/spec/rspec/support/caller_filter_spec.rb000066400000000000000000000042331456614207700243730ustar00rootroot00000000000000require 'spec_helper' require 'fileutils' require 'rspec/support/caller_filter' module RSpec describe CallerFilter do it 'can receive skip_frames and increment arguments' do expect(RSpec::CallerFilter.first_non_rspec_line(1, 5)).to include("#{__FILE__}:#{__LINE__}") end it 'returns the immediate caller when called from a spec' do expect(RSpec::CallerFilter.first_non_rspec_line).to include("#{__FILE__}:#{__LINE__}") end describe "the filtering regex" do def ruby_files_in_lib(lib) # http://rubular.com/r/HYpUMftlG2 path = $LOAD_PATH.find { |p| p.match(/\/rspec-#{lib}(-[a-f0-9]+)?\/lib/) } Dir["#{path}/**/*.rb"].sort.tap do |files| # Just a sanity check... expect(files.count).to be > 5 end end def unmatched_from(files) files.reject { |file| file.match(CallerFilter::IGNORE_REGEX) } end %w[ core mocks expectations support ].each do |lib| it "matches all ruby files in rspec-#{lib}" do files = ruby_files_in_lib(lib) expect(unmatched_from files).to eq([]) end end it "does not match other ruby files" do files = %w[ /path/to/lib/rspec/some-extension/foo.rb /path/to/spec/rspec/core/some_spec.rb ] expect(unmatched_from files).to eq(files) end def in_rspec_support_lib(name) root = File.expand_path("../../../../lib/rspec/support", __FILE__) dir = "#{root}/#{name}" FileUtils.mkdir(dir) yield dir ensure FileUtils.rm_rf(dir) end it 'does not match rubygems lines from `require` statements' do with_isolated_stderr do require 'rubygems' # ensure rubygems is loaded end in_rspec_support_lib("test_dir") do |dir| File.open("#{dir}/file.rb", "w") do |file| file.write("$_caller_filter = RSpec::CallerFilter.first_non_rspec_line") end $_caller_filter = nil expect { require "rspec/support/test_dir/file" }.to change { $_caller_filter }.to(include __FILE__) end end end end end rspec-support-3.13.1/spec/rspec/support/comparable_version_spec.rb000066400000000000000000000026231456614207700254370ustar00rootroot00000000000000require 'rspec/support/comparable_version' module RSpec::Support RSpec.describe ComparableVersion do describe '#<=>' do [ ['1.2.3', '1.2.3', 0], ['1.2.4', '1.2.3', 1], ['1.3.0', '1.2.3', 1], ['1.2.3', '1.2.4', -1], ['1.2.3', '1.3.0', -1], ['1.2.10', '1.2.3', 1], ['1.2.3', '1.2.10', -1], ['1.2.3.0', '1.2.3', 0], ['1.2.3', '1.2.3.0', 0], ['1.2.3.1', '1.2.3', 1], ['1.2.3.1', '1.2.3.0', 1], ['1.2.3', '1.2.3.1', -1], ['1.2.3.0', '1.2.3.1', -1], ['1.2.3.rc1', '1.2.3', -1], ['1.2.3.rc1', '1.2.3.rc2', -1], ['1.2.3.rc2', '1.2.3.rc10', -1], ['1.2.3.alpha2', '1.2.3.beta1', -1], ['1.2.3', '1.2.3.rc1', 1], ['1.2.3.rc2', '1.2.3.rc1', 1], ['1.2.3.rc10', '1.2.3.rc2', 1], ['1.2.3.beta1', '1.2.3.alpha2', 1] ].each do |subject_string, other_string, expected| context "with #{subject_string.inspect} and #{other_string.inspect}" do subject do ComparableVersion.new(subject_string) <=> ComparableVersion.new(other_string) end it { is_expected.to eq(expected) } end end end end end rspec-support-3.13.1/spec/rspec/support/deprecation_helpers_spec.rb000066400000000000000000000051011456614207700255760ustar00rootroot00000000000000require 'rspec/matchers/fail_matchers' RSpec.describe RSpecHelpers do def deprecate!(message) RSpec.configuration.reporter.deprecation(:message => message) end def fail_with(snippet) raise_error(RSpec::Mocks::MockExpectationError, snippet) end def raise_unrelated_expectation! raise(RSpec::Expectations::ExpectationNotMetError, 'abracadabra') end describe '#expect_no_deprecations' do shared_examples_for 'expects no deprecations' do it 'passes when there were no deprecations' do expectation end it 'fails when there was a deprecation warning' do in_sub_process do expect { expectation deprecate!('foo') }.to fail_with(/received: 1 time/) end end it 'fails with a MockExpectationError when there was also an ExpectationNotMetError' do in_sub_process do expect { expectation deprecate!('bar') raise_unrelated_expectation! }.to fail_with(/received: 1 time/) end end end it_behaves_like 'expects no deprecations' do def expectation expect_no_deprecations end end # Alias it_behaves_like 'expects no deprecations' do def expectation expect_no_deprecation end end end describe '#expect_warn_deprecation' do it 'passes when there was a deprecation warning' do in_sub_process do expect_warn_deprecation(/bar/) deprecate!('bar') end end pending 'fails when there were no deprecations' do in_sub_process do expect { expect_warn_deprecation(/bar/) }.to raise_error(/received: 0 times/) end end it 'fails with a MockExpectationError when there was also an ExpectationNotMetError' do in_sub_process do expect { expect_warn_deprecation(/bar/) deprecate!('bar') raise_unrelated_expectation! }.to raise_error(RSpec::Expectations::ExpectationNotMetError) end end it 'fails when deprecation message is different' do in_sub_process do expect { expect_warn_deprecation(/bar/) deprecate!('foo') }.to raise_error(%r{match /bar/}) end end it 'fails when deprecation message is different and an ExpectationNotMetError was raised' do in_sub_process do expect { expect_warn_deprecation(/bar/) deprecate!('foo') raise_unrelated_expectation! }.to raise_error(%r{match /bar/}) end end end end rspec-support-3.13.1/spec/rspec/support/differ_spec.rb000066400000000000000000000427701456614207700230330ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' require 'ostruct' require 'timeout' require 'rspec/support/spec/string_matcher' module RSpec module Support RSpec.describe Differ do include Spec::DiffHelpers describe '#diff' do let(:differ) { RSpec::Support::Differ.new } it "outputs unified diff of two strings" do expected = "foo\nzap\nbar\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nanother\nline\n" actual = "foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n" if Diff::LCS::VERSION.to_f < 1.4 || Diff::LCS::VERSION >= "1.4.4" expected_diff = dedent(<<-'EOD') | | |@@ -1,6 +1,6 @@ | foo |-zap | bar |+zap | this | is | soo |@@ -9,6 +9,5 @@ | equal | insert | a |-another | line | EOD else expected_diff = dedent(<<-'EOD') | | |@@ -1,4 +1,6 @@ | foo |-zap | bar |+zap | this |@@ -9,6 +11,7 @@ | equal | insert | a |-another | line | EOD end diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff of two strings when used multiple times" do expected = "foo\nzap\nbar\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nanother\nline\n" actual = "foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n" if Diff::LCS::VERSION.to_f < 1.4 || Diff::LCS::VERSION >= "1.4.4" expected_diff = dedent(<<-'EOS') | | |@@ -1,6 +1,6 @@ | foo |-zap | bar |+zap | this | is | soo |@@ -9,6 +9,5 @@ | equal | insert | a |-another | line | EOS else expected_diff = dedent(<<-'EOS') | | |@@ -1,4 +1,6 @@ | foo |-zap | bar |+zap | this |@@ -9,6 +11,7 @@ | equal | insert | a |-another | line | EOS end diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) end it 'does not mutate any instance variables when diffing, so we can reason about it being reused' do expected = "foo\nzap\nbar\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nanother\nline\n" actual = "foo\nbar\nzap\nthis\nis\nsoo\nvery\nvery\nequal\ninsert\na\nline\n" expect { differ.diff(actual, expected) }.not_to change { differ_ivars } end def differ_ivars Hash[ differ.instance_variables.map do |ivar| [ivar, differ.instance_variable_get(ivar)] end ] end if String.method_defined?(:encoding) it "returns an empty string if strings are not multiline" do expected = "Tu avec carte {count} item has".encode('UTF-16LE') actual = "Tu avec carté {count} itém has".encode('UTF-16LE') diff = differ.diff(actual, expected) expect(diff).to be_empty end it 'copes with encoded strings', :skip => RSpec::Support::OS.windows? do expected = "Tu avec carte {count} item has\n".encode('UTF-16LE') actual = "Tu avec carté {count} itém has\n".encode('UTF-16LE') expected_diff = dedent(<<-EOD).encode('UTF-16LE') | |@@ #{one_line_header} @@ |-Tu avec carte {count} item has |+Tu avec carté {count} itém has | EOD diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) end it 'handles differently encoded strings that are compatible' do expected = "abc\n".encode('us-ascii') actual = "강인철\n".encode('UTF-8') expected_diff = "\n@@ #{one_line_header} @@\n-abc\n+강인철\n" diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) end it 'uses the default external encoding when the two strings have incompatible encodings' do expected = "Tu avec carte {count} item has\n" actual = "Tu avec carté {count} itém has\n".encode('UTF-16LE') expected_diff = "\n@@ #{one_line_header} @@\n-Tu avec carte {count} item has\n+Tu avec carté {count} itém has\n" diff = differ.diff(actual, expected) expect(diff).to be_diffed_as(expected_diff) expect(diff.encoding).to eq(Encoding.default_external) end it 'handles any encoding error that occurs with a helpful error message' do expect(RSpec::Support::HunkGenerator).to receive(:new). and_raise(Encoding::CompatibilityError) expected = "Tu avec carte {count} item has\n".encode('us-ascii') actual = "Tu avec carté {count} itém has\n" diff = differ.diff(actual, expected) expect(diff).to match(/Could not produce a diff/) expect(diff).to match(/actual string \(UTF-8\)/) expect(diff).to match(/expected string \(US-ASCII\)/) end end it "outputs unified diff message of two objects" do animal_class = Class.new do include RSpec::Support::FormattingSupport def initialize(name, species) @name, @species = name, species end def inspect dedent(<<-EOA) | EOA end end expected = animal_class.new "bob", "giraffe" actual = animal_class.new "bob", "tortoise" expected_diff = dedent(<<-'EOD') | |@@ -1,5 +1,5 @@ | | EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two arrays" do expected = [ :foo, 'bar', :baz, 'quux', :metasyntactic, 'variable', :delta, 'charlie', :width, 'quite wide' ] actual = [ :foo, 'bar', :baz, 'quux', :metasyntactic, 'variable', :delta, 'tango' , :width, 'very wide' ] expected_diff = dedent(<<-'EOD') | | |@@ -5,7 +5,7 @@ | :metasyntactic, | "variable", | :delta, |- "tango", |+ "charlie", | :width, |- "very wide"] |+ "quite wide"] | EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end it 'outputs a unified diff message for an array which flatten recurses' do klass = Class.new do def to_ary; [self]; end def inspect; ""; end end obj = klass.new diff = '' Timeout::timeout(1) do diff = differ.diff [obj], [] end expected_diff = dedent(<<-EOD) | |@@ #{one_line_header} @@ |-[] |+[] | EOD expect(diff).to be_diffed_as(expected_diff) end it 'outputs unified diff message of strings in arrays' do diff = differ.diff(["a\r\nb"], ["a\r\nc"]) expected_diff = dedent(<<-EOD) | |@@ #{one_line_header} @@ |-a\\r\\nc |+a\\r\\nb | EOD expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two hashes" do expected = { :foo => 'bar', :baz => 'quux', :metasyntactic => 'variable', :delta => 'charlie', :width =>'quite wide' } actual = { :foo => 'bar', :metasyntactic => 'variable', :delta => 'charlotte', :width =>'quite wide' } expected_diff = dedent(<<-'EOD') | |@@ -1,4 +1,5 @@ |-:delta => "charlotte", |+:baz => "quux", |+:delta => "charlie", | :foo => "bar", | :metasyntactic => "variable", | :width => "quite wide", | EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end unless RUBY_VERSION == '1.8.7' # We can't count on the ordering of the hash on 1.8.7... it "outputs unified diff message for hashes inside arrays with differing key orders" do expected = [{ :foo => 'bar', :baz => 'quux', :metasyntactic => 'variable', :delta => 'charlie', :width =>'quite wide' }] actual = [{ :metasyntactic => 'variable', :delta => 'charlotte', :width =>'quite wide', :foo => 'bar' }] expected_diff = dedent(<<-'EOD') | |@@ -1,4 +1,5 @@ |-[{:delta=>"charlotte", |+[{:baz=>"quux", |+ :delta=>"charlie", | :foo=>"bar", | :metasyntactic=>"variable", | :width=>"quite wide"}] | EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end end it 'outputs unified diff message of two hashes with differing encoding' do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-"a" => "a", |#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+"ö" => "ö"} : '+"\303\266" => "\303\266"' }, | EOD diff = differ.diff({'ö' => 'ö'}, {'a' => 'a'}) expect(diff).to be_diffed_as(expected_diff) end it 'outputs unified diff message of two hashes with encoding different to key encoding' do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-:a => "a", |#{ (RUBY_VERSION.to_f > 1.8) ? %Q{+\"한글\" => \"한글2\"} : '+"\355\225\234\352\270\200" => "\355\225\234\352\270\2002"' }, | EOD diff = differ.diff({ "한글" => "한글2"}, { :a => "a"}) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two hashes with object keys" do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-["a", "c"] => "b", |+["d", "c"] => "b", | EOD diff = differ.diff({ ['d','c'] => 'b'}, { ['a','c'] => 'b' }) expect(diff).to be_diffed_as(expected_diff) end context 'when special-case objects are inside hashes' do let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it "outputs unified diff message of two hashes with Time object keys" do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-#{formatted_time} => "b", |+#{formatted_time} => "c", | EOD diff = differ.diff({ time => 'c'}, { time => 'b' }) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two hashes with hashes inside them" do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-"b" => {"key_1"=>#{formatted_time}}, |+"c" => {"key_1"=>#{formatted_time}}, | EOD left_side_hash = {'c' => {'key_1' => time}} right_side_hash = {'b' => {'key_1' => time}} diff = differ.diff(left_side_hash, right_side_hash) expect(diff).to be_diffed_as(expected_diff) end end context 'when special-case objects are inside arrays' do let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it "outputs unified diff message of two arrays with Time object keys" do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-[#{formatted_time}, "b"] |+[#{formatted_time}, "c"] | EOD diff = differ.diff([time, 'c'], [time, 'b']) expect(diff).to be_diffed_as(expected_diff) end it "outputs unified diff message of two arrays with hashes inside them" do expected_diff = dedent(<<-"EOD") | |@@ #{one_line_header} @@ |-[{"b"=>#{formatted_time}}, "c"] |+[{"a"=>#{formatted_time}}, "c"] | EOD left_side_array = [{'a' => time}, 'c'] right_side_array = [{'b' => time}, 'c'] diff = differ.diff(left_side_array, right_side_array) expect(diff).to be_diffed_as(expected_diff) end end it "outputs unified diff of multi line strings" do expected = "this is:\n one string" actual = "this is:\n another string" expected_diff = dedent(<<-'EOD') | |@@ -1,3 +1,3 @@ | this is: |- another string |+ one string | EOD diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end it "splits items with newlines" do expected_diff = dedent(<<-"EOD") | |@@ #{removing_two_line_header} @@ |-a\\nb |-c\\nd | EOD diff = differ.diff [], ["a\nb", "c\nd"] expect(diff).to be_diffed_as(expected_diff) end it "shows inner arrays on a single line" do expected_diff = dedent(<<-"EOD") | |@@ #{removing_two_line_header} @@ |-a\\nb |-["c\\nd"] | EOD diff = differ.diff [], ["a\nb", ["c\nd"]] expect(diff).to be_diffed_as(expected_diff) end it "returns an empty string if no expected or actual" do diff = differ.diff nil, nil expect(diff).to be_empty end it "returns an empty string if expected is Numeric" do diff = differ.diff 1, "2" expect(diff).to be_empty end it "returns an empty string if actual is Numeric" do diff = differ.diff "1", 2 expect(diff).to be_empty end it "returns an empty string if expected or actual are procs" do diff = differ.diff lambda {}, lambda {} expect(diff).to be_empty end it "returns a String if no diff is returned" do diff = differ.diff 1, 2 expect(diff).to be_a(String) end it "returns a String if a diff is performed" do diff = differ.diff "a\n", "b\n" expect(diff).to be_a(String) end it "includes object delegation information in the diff output" do in_sub_process_if_possible do require "delegate" object = Object.new delegator = SimpleDelegator.new(object) expected_diff = dedent(<<-EOS) | |@@ #{one_line_header} @@ |-[#] |+[#{object.inspect}] | EOS diff = differ.diff [object], [delegator] expect(diff).to eq(expected_diff) end end context "with :object_preparer option set" do let(:differ) do RSpec::Support::Differ.new(:object_preparer => lambda { |s| s.to_s.reverse }) end it "uses the output of object_preparer for diffing" do expected = :foo actual = :poo expected_diff = dedent(<<-EOS) | |@@ #{one_line_header} @@ |-"oop" |+"oof" | EOS diff = differ.diff(expected, actual) expect(diff).to be_diffed_as(expected_diff) end end context "with :color option set" do let(:differ) { RSpec::Support::Differ.new(:color => true) } it "outputs colored diffs" 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" diff = differ.diff(expected,actual) expect(diff).to be_diffed_as(expected_diff) end end context 'when expected or actual is false' do it 'generates a diff' do expect(differ.diff(true, false)).to_not be_empty expect(differ.diff(false, true)).to_not be_empty end end end end end end rspec-support-3.13.1/spec/rspec/support/directory_maker_spec.rb000066400000000000000000000031201456614207700247410ustar00rootroot00000000000000require "spec_helper" require "fileutils" RSpec::Support.require_rspec_support("directory_maker") module RSpec::Support RSpec.describe DirectoryMaker do shared_examples_for "an mkdir_p implementation" do include_context "isolated directory" let(:dirname) { File.join(%w[tmp a recursive structure]) } def directory_exists?(dirname) File.exist?(dirname) && File.directory?(dirname) end it "makes directories recursively" do mkdir_p.call(dirname) expect(directory_exists?(dirname)).to be true end it "does not raise if the directory already exists" do Dir.mkdir("tmp") mkdir_p.call(dirname) expect(directory_exists?(dirname)).to be true end context "when a file already exists" do before { File.open("tmp", "w") } it "raises, as it can't make the directory", :failing_on_windows_ci do expect { mkdir_p.call(dirname) }.to raise_error(Errno::EEXIST) end end context "when the path specified is absolute" do let(:dirname) { "bees/ponies" } it "makes directories recursively" do mkdir_p.call(File.expand_path(dirname)) expect(directory_exists?(dirname)).to be true end end end describe ".mkdir_p" do subject(:mkdir_p) { DirectoryMaker.method(:mkdir_p) } it_behaves_like "an mkdir_p implementation" end describe "FileUtils.mkdir_p" do subject(:mkdir_p) { FileUtils.method(:mkdir_p) } it_behaves_like "an mkdir_p implementation" end end end rspec-support-3.13.1/spec/rspec/support/encoded_string_spec.rb000066400000000000000000000273451456614207700245640ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' require 'rspec/support/encoded_string' require 'rspec/support/spec/string_matcher' module RSpec::Support RSpec.describe EncodedString do let(:utf8_encoding) { 'UTF-8' } delegated_methods = String.instance_methods.map(&:to_s) & %w[eql? lines == encoding empty?] delegated_methods.each do |delegated_method| it "responds to #{delegated_method}" do encoded_string = EncodedString.new("abc", utf8_encoding) expect(encoded_string).to respond_to(delegated_method) end end describe '::pick_encoding' do if String.method_defined?(:encoding) it "picks the default external encoding for incompatible encodings" do str1 = forced_encoding("\xa1", "iso-8859-1") str2 = forced_encoding("\xa1\xa1", "euc-jp") expect(Encoding.compatible?(str1, str2)).to be_nil expect(EncodedString.pick_encoding(str1, str2)).to eq(Encoding.default_external) end # https://github.com/ruby/spec/blob/91ce9f6549/core/encoding/compatible_spec.rb#L31 it "picks a compatible encoding" do str1 = forced_encoding "abc", Encoding::US_ASCII str2 = "\u3042".encode("utf-8") expect(EncodedString.pick_encoding(str1, str2)).to eq(Encoding::UTF_8) end else it "returns nil" do str1 = "\xa1" str2 = "\xa1\xa1" expect(EncodedString.pick_encoding(str1, str2)).to be_nil end end end if String.method_defined?(:encoding) describe '#source_encoding' do it 'knows the original encoding of the string' do str = EncodedString.new("abc".encode('ASCII-8BIT'), "UTF-8") expect(str.source_encoding.to_s).to eq('ASCII-8BIT') end end describe '#to_s' do context 'when encoding a string with invalid bytes in the target encoding' do # see https://github.com/jruby/jruby/blob/c1be61a501/test/mri/ruby/test_transcode.rb#L13 let(:source_encoding) { Encoding.find('US-ASCII') } let(:target_encoding) { Encoding.find('UTF-8') } let(:string) { forced_encoding("I have a bad byté\x80", source_encoding) } it 'normally raises an EncodedString::InvalidByteSequenceError' do expect { string.encode(target_encoding) }.to raise_error(Encoding::InvalidByteSequenceError) end # See JRuby issue https://github.com/jruby/jruby/issues/2580 it 'replaces invalid byte sequences with the REPLACE string', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do resulting_string = build_encoded_string(string, target_encoding).to_s replacement = EncodedString::REPLACE * 3 expected_string = forced_encoding("I have a bad byt#{replacement}", target_encoding) expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end end context 'when no converter is known for an encoding' do # see https://github.com/rubyspec/rubyspec/blob/91ce9f6549/core/string/shared/encode.rb#L12 let(:source_encoding) { Encoding.find('ASCII-8BIT') } let(:no_converter_encoding) { Encoding::Emacs_Mule } let(:string) { forced_encoding("\x80", source_encoding) } it 'normally raises an Encoding::ConverterNotFoundError' do expect { string.encode(no_converter_encoding) }.to raise_error(Encoding::ConverterNotFoundError) end # See comment above ENCODE_UNCONVERTABLE_BYTES in encoded_string.rb # for why the behavior differs by (MRI) Ruby version. if RUBY_VERSION < '2.1' it 'does nothing' do resulting_string = build_encoded_string(string, no_converter_encoding).to_s expected_string = forced_encoding("\x80", no_converter_encoding) expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end else it 'forces the encoding and replaces invalid characters with the REPLACE string' do resulting_string = build_encoded_string(string, no_converter_encoding).to_s expected_string = forced_encoding(EncodedString::REPLACE, no_converter_encoding) expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end it 'does not mutate the input string' do expect { build_encoded_string(string, no_converter_encoding) }.not_to change { [string, string.encoding] } end end end # see https://github.com/ruby/ruby/blob/34fbf57aaa/transcode.c#L4289 # ISO-8859-1 -> UTF-8 -> EUC-JP # "\xa0" NO-BREAK SPACE, which is available in UTF-8 but not in EUC-JP context 'when there is an undefined conversion to the target encoding' do let(:source_encoding) { Encoding.find('ISO-8859-1') } let(:incompatible_encoding) { Encoding.find('EUC-JP') } let(:string) { forced_encoding("\xa0 hi I am not going to work", source_encoding) } it 'normally raises an Encoding::UndefinedConversionError' do expect { string.encode(incompatible_encoding) }.to raise_error(Encoding::UndefinedConversionError) end it 'replaces all undefines conversions with the REPLACE string' do resulting_string = build_encoded_string(string, incompatible_encoding).to_s replacement = EncodedString::REPLACE expected_string = forced_encoding("#{replacement} hi I am not going to work", 'EUC-JP') expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end end end let(:ascii_arrow_symbol) { "\xAE" } let(:utf_8_euro_symbol) { "\xE2\x82\xAC" } describe '#<<' do context 'with strings that can be converted to the target encoding' do let(:valid_ascii_string) { forced_encoding("abcde", "ASCII-8BIT") } let(:valid_unicode_string) { forced_encoding(utf_8_euro_symbol, 'UTF-8') } it 'encodes and appends the string' do resulting_string = build_encoded_string(valid_unicode_string, utf8_encoding) << valid_ascii_string expected_string = forced_encoding("#{utf_8_euro_symbol}abcde", 'UTF-8') expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end end context 'with a string that cannot be converted to the target encoding' do context 'when appending a string with an incompatible character encoding' do let(:ascii_string) { forced_encoding(ascii_arrow_symbol, "ASCII-8BIT") } let(:valid_unicode_string) { forced_encoding(utf_8_euro_symbol, 'UTF-8') } it "normally raises an Encoding::CompatibilityError" do expect { valid_unicode_string.encode(utf8_encoding) << ascii_string }.to raise_error(Encoding::CompatibilityError) end it 'replaces unconvertable characters with the REPLACE string' do resulting_string = build_encoded_string(valid_unicode_string, utf8_encoding) << ascii_string expected_string = "#{utf_8_euro_symbol}#{EncodedString::REPLACE}" expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end end end context 'with two ascii strings with a target encoding of UTF-8 ' do it 'has an encoding of UTF-8' do ascii_string = forced_encoding('abc', "ASCII-8BIT") other_ascii_string = forced_encoding('123', "ASCII-8BIT") resulting_string = build_encoded_string(ascii_string, utf8_encoding) << other_ascii_string expected_string = forced_encoding('abc123', utf8_encoding) expect(resulting_string).to be_identical_string(expected_string).with_same_encoding end end end describe '#split' do context 'when there is an undefined conversion to the target encoding' do let(:wrapped_string_template) { "abaaaaaaaaaa%saaaaa" } let(:wrapped_string) { sprintf(wrapped_string_template, ascii_arrow_symbol).force_encoding("ASCII-8BIT") } it 'normally raises an Encoding::UndefinedConversionError' do expect { wrapped_string.encode(utf8_encoding) }.to raise_error(Encoding::UndefinedConversionError) end it 'splits the string based on the delimiter accounting for encoding' do delimiter = forced_encoding("b", utf8_encoding) resulting_string = build_encoded_string(wrapped_string, utf8_encoding).split(delimiter) exp1, exp2 = sprintf(wrapped_string_template, EncodedString::REPLACE).force_encoding(utf8_encoding).split(delimiter) expect(resulting_string).to match [ a_string_identical_to(exp1).with_same_encoding, a_string_identical_to(exp2).with_same_encoding ] end it 'handles invalidly encoded strings' do source_string = forced_encoding("an\xAE\nother", 'US-ASCII') expect( build_encoded_string(source_string, utf8_encoding).split("\n") ).to eq([ 'an?', 'other' ]) end end # see https://github.com/rspec/rspec-expectations/blob/f8a1232/spec/rspec/expectations/fail_with_spec.rb#L50 # https://github.com/rspec/rspec-expectations/issues/201 # https://github.com/rspec/rspec-expectations/pull/220 context 'with a string that cannot be converted to the target encoding' do let(:binary_poop) {'💩' } # [128169] "\u{1F4A9}" let(:non_ascii_compatible_string) { "This is a pile of poo: #{binary_poop}, yuck".encode("UTF-16LE") } it 'normally raises an Encoding::CompatibilityError' do expect { non_ascii_compatible_string.split("\n") }.to raise_error(Encoding::CompatibilityError) end it 'makes no changes to the resulting string' do resulting_array = build_encoded_string(non_ascii_compatible_string).split("\n") expect(resulting_array).to match [ a_string_identical_to(non_ascii_compatible_string).with_same_encoding ] end end context 'when the string has an invalid byte sequence' do let(:message_with_invalid_byte_sequence) { forced_encoding("\xEF \255 \xAD I have bad bytes", utf8_encoding) } it 'normally raises an ArgumentError' do expect(message_with_invalid_byte_sequence).not_to be_valid_encoding expect { message_with_invalid_byte_sequence.split("\n") }.to raise_error(ArgumentError) end it 'replaces invalid bytes with the REPLACE string' do resulting_array = build_encoded_string(message_with_invalid_byte_sequence, utf8_encoding).split("\n") expected_string = "? ? ? I have bad bytes" expect(resulting_array).to match [ a_string_identical_to(expected_string).with_same_encoding ] end end end def build_encoded_string(string, target_encoding = string.encoding) EncodedString.new(string, target_encoding) end def forced_encoding(string, encoding) string.dup.force_encoding(encoding) end else describe '#source_encoding' do it 'defaults to US-ASCII' do str = EncodedString.new("abc", "UTF-8") expect(str.source_encoding).to eq('US-ASCII') end end end end end rspec-support-3.13.1/spec/rspec/support/fuzzy_matcher_spec.rb000066400000000000000000000153001456614207700244530ustar00rootroot00000000000000require 'spec_helper' require 'rspec/support/fuzzy_matcher' module RSpec module Support RSpec.describe FuzzyMatcher, ".values_match?" do matcher :match_against do |actual| match { |expected| FuzzyMatcher.values_match?(expected, actual) } end it 'returns true when given equal values' do expect(1).to match_against(1.0) end it 'returns false when given unequal values that do not provide match logic' do expect(1).not_to match_against(1.1) end it 'can match a regex against a string' do expect(/foo/).to match_against("foobar") expect(/foo/).not_to match_against("fobar") end it 'can match a regex against itself' do expect(/foo/).to match_against(/foo/) expect(/foo/).not_to match_against(/bar/) end it 'can match a class against an instance' do expect(String).to match_against("foo") expect(String).not_to match_against(123) end it 'can match a class against itself' do expect(String).to match_against(String) expect(String).not_to match_against(Regexp) end it 'can match against a matcher' do expect(be_within(0.1).of(2)).to match_against(2.05) expect(be_within(0.1).of(2)).not_to match_against(2.15) end it 'does not ask the second argument if it fuzzy matches (===)' do expect("foo").not_to match_against(String) end context "when given two 0-arg lambdas" do it 'returns true when given the same lambda' do k = lambda { 3 } expect(k).to match_against(k) end it 'returns false when given different lambdas' do expect(lambda { 3 }).not_to match_against(lambda { 4 }) end end context "when given an object whose implementation of `==` wrongly assumes it will only be called with objects of the same type" do Color = Struct.new(:r, :g, :b) do def ==(other) other.r == r && other.g == g && other.b == b end end before(:context) do expect { Color.new(0, 0, 0) == Object.new }.to raise_error(NoMethodError, /undefined method [`']r'/) end it 'can match against an expected value that matches anything' do anything = Object.new.tap do |o| def o.===(*); true; end end expect(anything).to match_against(Color.new(0, 0, 0)) end it 'surfaces the `NoMethodError` when used as the expected value' do expect { FuzzyMatcher.values_match?(Color.new(0, 0, 0), Object.new) }.to raise_error(NoMethodError, /undefined method [`']r'/) end it 'can match against objects of the same type' do expect(Color.new(0, 0, 0)).to match_against(Color.new(0, 0, 0)) expect(Color.new(0, 0, 0)).not_to match_against(Color.new(0, 1, 0)) end end context "when given an object whose implementation of `==` raises an ArgumentError" do it 'surfaces the error' do klass = Class.new do attr_accessor :foo def ==(other) other.foo == foo end end instance = klass.new other = Object.new def other.foo(arg); end expect { instance == other }.to raise_error(ArgumentError) expect { FuzzyMatcher.values_match?(instance, other) }.to raise_error(ArgumentError) end end it "does not match a struct against an array" do struct = Struct.new(:foo, :bar).new("first", 2) expect(["first", 2]).not_to match_against(struct) end context "when given two arrays" do it 'returns true if they have equal values' do expect([1, 2.0]).to match_against([1.0, 2]) end it 'returns false when given unequal values that do not provide match logic' do expect([1, 2.0]).not_to match_against([1.1, 2]) end it 'does the fuzzy matching on the individual elements' do expect([String, Integer]).to match_against(["a", 2]) expect([String, Integer]).not_to match_against([2, "a"]) end it 'returns false if they have a different number of elements' do expect([String, Integer]).not_to match_against(['a', 2, nil]) end it 'supports arbitrary nested arrays' do a1 = [ [String, Integer, [be_within(0.1).of(2)]], 3, [[[ /foo/ ]]] ] a2 = [ ["a", 1, [2.05]], 3, [[[ "foobar" ]]] ] expect(a1).to match_against(a2) a2[0][2][0] += 1 expect(a1).not_to match_against(a2) end end it 'can match an array an arbitrary enumerable' do my_enum = Class.new do include Enumerable def each yield 1; yield "foo" end end.new expect([Integer, String]).to match_against(my_enum) expect([String, Integer]).not_to match_against(my_enum) end it 'does not match an empty hash against an empty array or vice-versa' do expect({}).not_to match_against([]) expect([]).not_to match_against({}) end context 'when given two hashes' do it 'returns true when their keys and values are equal' do expect(:a => 5, :b => 2.0).to match_against(:a => 5.0, :b => 2) end it 'returns false when given unequal values that do not provide match logic' do expect(:a => 5).not_to match_against(:a => 5.1) end it 'does the fuzzy matching on the individual values' do expect(:a => String, :b => /bar/).to match_against(:a => "foo", :b => "barn") expect(:a => String, :b => /bar/).not_to match_against(:a => "foo", :b => "brn") end it 'returns false if the expected hash has nil values that are not in the actual hash' do expect(:a => 'b', :b => nil).not_to match_against(:a => "b") end it 'returns false if actual hash has extra entries' do expect(:a => 'b').not_to match_against(:a => "b", :b => nil) end it 'does not fuzzy match on keys' do expect(/foo/ => 1).not_to match_against("foo" => 1) end it 'supports arbitrary nested hashes' do h1 = { :a => { :b => [String, Integer], :c => { :d => be_within(0.1).of(2) } } } h2 = { :a => { :b => ["foo", 5], :c => { :d => 2.05 } } } expect(h1).to match_against(h2) h2[:a][:c][:d] += 1 expect(h1).not_to match_against(h2) end end end end end rspec-support-3.13.1/spec/rspec/support/matcher_definition_spec.rb000066400000000000000000000023041456614207700254140ustar00rootroot00000000000000require "spec_helper" module RSpec module Support RSpec.describe "matcher definitions" do RSpec::Matchers.define :fake_matcher do |expected| match { |actual| expected == actual } description { :fake_matcher } end RSpec::Matchers.define :matcher_with_no_description do match { true } undef description end describe ".rspec_description_for_object" do it "returns the object for a non matcher object" do o = Object.new expect(RSpec::Support.rspec_description_for_object(o)).to be o end it "returns the object's description for a matcher object that has a description" do expect(RSpec::Support.rspec_description_for_object(fake_matcher(nil))).to eq :fake_matcher end it "returns the object for a matcher that does not have a description" do matcher = matcher_with_no_description expect(matcher_with_no_description).not_to respond_to(:description) expect(RSpec::Support.is_a_matcher?(matcher_with_no_description)).to eq true expect(RSpec::Support.rspec_description_for_object(matcher)).to be matcher end end end end end rspec-support-3.13.1/spec/rspec/support/method_signature_verifier_spec.rb000066400000000000000000001264171456614207700270310ustar00rootroot00000000000000require 'rspec/support' require 'rspec/support/method_signature_verifier' module RSpec module Support RSpec.describe 'verifying methods' do let(:signature) { MethodSignature.new(test_method) } def valid_non_kw_args?(arity) described_class.new(signature, [nil] * arity).valid? end def valid?(*args) described_class.new(signature, args).valid? end def error_description described_class.new(signature).error_message[/Expected (.*),/, 1] end def error_for(*args) described_class.new(signature, args).error_message end def signature_description signature.description end def validate_expectation(*args) obj = MethodSignatureExpectation.new obj.min_count = Integer === args.first ? args.shift : nil obj.max_count = Integer === args.first ? args.shift : nil obj.expect_unlimited_arguments = !args.delete(:unlimited_args).nil? obj.expect_arbitrary_keywords = !args.delete(:arbitrary_kw_args).nil? obj.keywords = args described_class.new(signature).with_expectation(obj).valid? end shared_context 'a method verifier' do describe 'with a method with arguments' do def arity_two(x, y); end let(:test_method) { method(:arity_two) } it 'covers only the exact arity' do expect(valid_non_kw_args?(1)).to eq(false) expect(valid_non_kw_args?(2)).to eq(true) expect(valid_non_kw_args?(3)).to eq(false) end it "allows matchers to be passed as arguments" do expect(valid?(anything, anything)).to eq(true) end it 'does not treat a last-arg hash as kw args' do expect(valid?(1, {})).to eq(true) end it 'describes the arity precisely' do expect(error_description).to eq("2") end it 'mentions only the arity in the description' do expect(signature_description).to eq("arity of 2") end it 'indicates it has no optional kw args' do expect(signature.optional_kw_args).to eq([]) end it 'indicates it has no required kw args' do expect(signature.required_kw_args).to eq([]) end describe 'with an expectation object' do it 'matches the exact arity' do expect(validate_expectation 1).to eq(false) expect(validate_expectation 2).to eq(true) expect(validate_expectation 3).to eq(false) end it 'matches a range including the min and max counts' do expect(validate_expectation 1, 2).to eq(false) expect(validate_expectation 2, 2).to eq(true) expect(validate_expectation 2, 3).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) end if RubyFeatures.kw_args_supported? it 'does not match keywords' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) end else it 'ignores keyword expectations' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(true) end it 'ignores arbitrary keyword expectations' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation 2, :arbitrary_kw_args).to eq(true) end end end end describe 'a method with splat arguments' do def arity_splat(_, *); end let(:test_method) { method(:arity_splat) } it 'covers a range from the lower bound upwards' do expect(valid_non_kw_args?(0)).to eq(false) expect(valid_non_kw_args?(1)).to eq(true) expect(valid_non_kw_args?(2)).to eq(true) expect(valid_non_kw_args?(3)).to eq(true) end it 'describes the arity with no upper bound' do expect(error_description).to eq("1 or more") end it 'mentions only the arity in the description' do expect(signature_description).to eq("arity of 1 or more") end describe 'with an expectation object' do it 'matches a value from the lower bound upwards' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(true) expect(validate_expectation 2).to eq(true) expect(validate_expectation 3).to eq(true) end it 'matches a range from the lower bound upwards' do expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(true) expect(validate_expectation 1, 2).to eq(true) expect(validate_expectation 2, 3).to eq(true) expect(validate_expectation 1, 2 ** 31).to eq(true) end if RubyFeatures.optional_and_splat_args_supported? it 'matches unlimited arguments with the minimum arity' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation 1, :unlimited_args).to eq(true) end else it 'ignores unlimited arguments expectations' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation 1, :unlimited_args).to eq(true) end end if RubyFeatures.kw_args_supported? it 'does not match keywords' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation 2, :arbitrary_kw_args).to eq(false) end else it 'ignores keyword expectations' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(true) end it 'ignores arbitrary keyword expectations' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation 2, :arbitrary_kw_args).to eq(true) end end end end describe 'a method with optional arguments' do def arity_optional(x, y, z = 1); end let(:test_method) { method(:arity_optional) } it 'covers a range from min to max possible arguments' do expect(valid_non_kw_args?(1)).to eq(false) expect(valid_non_kw_args?(2)).to eq(true) expect(valid_non_kw_args?(3)).to eq(true) if RubyFeatures.optional_and_splat_args_supported? expect(valid_non_kw_args?(4)).to eq(false) else expect(valid_non_kw_args?(4)).to eq(true) end end if RubyFeatures.optional_and_splat_args_supported? it 'describes the arity as a range' do expect(error_description).to eq("2 to 3") end else it 'describes the arity with no upper bound' do expect(error_description).to eq("2 or more") end end describe 'with an expectation object' do it 'matches a value from min to max possible arguments' do expect(validate_expectation 1).to eq(false) expect(validate_expectation 2).to eq(true) expect(validate_expectation 3).to eq(true) if RubyFeatures.optional_and_splat_args_supported? expect(validate_expectation 4).to eq(false) else expect(validate_expectation 4).to eq(true) end end it 'matches a range from the lower bound upwards' do expect(validate_expectation 1, 2).to eq(false) expect(validate_expectation 2, 2).to eq(true) expect(validate_expectation 2, 3).to eq(true) if RubyFeatures.optional_and_splat_args_supported? expect(validate_expectation 2, 4).to eq(false) else expect(validate_expectation 2, 4).to eq(true) end end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) end if RubyFeatures.kw_args_supported? it 'does not match keywords' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) end else it 'ignores keyword expectations' do expect(validate_expectation :optional_keyword).to eq(false) expect(validate_expectation 2, :optional_keyword).to eq(true) end it 'ignores arbitrary keyword expectations' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation 2, :arbitrary_kw_args).to eq(true) end end end end if RubyFeatures.kw_args_supported? describe 'a method with optional keyword arguments' do eval <<-RUBY def arity_kw(x, y:1, z:2); end RUBY let(:test_method) { method(:arity_kw) } it 'does not require any of the arguments' do expect(valid?(nil)).to eq(true) expect(valid?(nil, nil)).to eq(false) end it 'does not allow an invalid keyword arguments' do expect(valid?(nil, :a => 1)).to eq(false) end it 'mentions the invalid keyword args in the error', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do expect(error_for(nil, :a => 0, :b => 1)).to \ eq("Invalid keyword arguments provided: a, b") end it 'describes invalid arity precisely' do expect(error_for()).to \ eq("Wrong number of arguments. Expected 1, got 0.") end it 'does not blow up when given a BasicObject as the last arg' do expect(valid?(BasicObject.new)).to eq(true) end it 'does not mutate the provided args array' do args = [nil, { :y => 1 }] described_class.new(signature, args).valid? expect(args).to eq([nil, { :y => 1 }]) end it 'mentions the arity and optional kw args in the description', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do expect(signature_description).to eq("arity of 1 and optional keyword args (:y, :z)") end it "indicates the optional keyword args" do expect(signature.optional_kw_args).to contain_exactly(:y, :z) end it "indicates it has no required keyword args" do expect(signature.required_kw_args).to eq([]) end describe 'with an expectation object' do it 'matches the exact arity' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(true) expect(validate_expectation 2).to eq(false) end it 'matches the exact range' do expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(true) expect(validate_expectation 1, 2).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) end it 'matches optional keywords with the correct arity' do expect(validate_expectation :y).to eq(false) expect(validate_expectation :z).to eq(false) expect(validate_expectation :y, :z).to eq(false) expect(validate_expectation 1, :y).to eq(true) expect(validate_expectation 1, :z).to eq(true) expect(validate_expectation 1, :y, :z).to eq(true) expect(validate_expectation 2, :y).to eq(false) expect(validate_expectation 2, :z).to eq(false) expect(validate_expectation 2, :y, :z).to eq(false) end it 'does not match invalid keywords' do expect(validate_expectation :w).to eq(false) expect(validate_expectation :w, :z).to eq(false) expect(validate_expectation 1, :w).to eq(false) expect(validate_expectation 1, :w, :z).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) end end end end if RubyFeatures.kw_args_supported? describe 'a method with optional argument and keyword arguments' do eval <<-RUBY def arity_kw(x, y = {}, z:2); end RUBY let(:test_method) { method(:arity_kw) } it 'does not require any of the arguments' do expect(valid?(nil)).to eq(true) expect(valid?(nil, nil)).to eq(true) end it 'does not allow an invalid keyword arguments' do expect(valid?(nil, nil, :a => 1)).to eq(false) expect(valid?(nil, :a => 1)).to eq(false) end if RubyFeatures.kw_arg_separation? context "when ruby has kw arg separation" do it 'treats symbols as keyword arguments' do expect(valid?(nil, nil, :z => 1)).to eq(true) expect(valid?(nil, :z => 1)).to eq(true) end it 'fails to match string keys as kw args' do expect(valid?(nil, nil, 'z' => 1)).to eq(false) expect(valid?(nil, 'z' => 1)).to eq(false) end it 'mentions the invalid keyword args in the error', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do expect(error_for(1, 2, :a => 0)).to eq("Invalid keyword arguments provided: a") expect(error_for(1, :a => 0)).to eq("Invalid keyword arguments provided: a") expect(error_for(1, 'a' => 0, :b => 0)).to eq("Invalid keyword arguments provided: a, b") end end else it 'treats symbols as keyword arguments and the rest as optional argument' do expect(valid?(nil, 'a' => 1)).to eq(true) expect(valid?(nil, 'a' => 1, :z => 3)).to eq(true) expect(valid?(nil, 'a' => 1, :b => 3)).to eq(false) expect(valid?(nil, 'a' => 1, :b => 2, :z => 3)).to eq(false) end it 'mentions the invalid keyword args in the error', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do expect(error_for(1, 2, :a => 0)).to eq("Invalid keyword arguments provided: a") expect(error_for(1, :a => 0)).to eq("Invalid keyword arguments provided: a") expect(error_for(1, 'a' => 0, :b => 0)).to eq("Invalid keyword arguments provided: b") end end it 'describes invalid arity precisely' do expect(error_for()).to \ eq("Wrong number of arguments. Expected 1 to 2, got 0.") end it 'does not blow up when given a BasicObject as the last arg' do expect(valid?(BasicObject.new)).to eq(true) end it 'does not mutate the provided args array' do args = [nil, nil, { :y => 1 }] described_class.new(signature, args).valid? expect(args).to eq([nil, nil, { :y => 1 }]) end it 'mentions the arity and optional kw args in the description', :pending => RSpec::Support::Ruby.jruby? && !RSpec::Support::Ruby.jruby_9000? do expect(signature_description).to eq("arity of 1 to 2 and optional keyword args (:z)") end it "indicates the optional keyword args" do expect(signature.optional_kw_args).to contain_exactly(:z) end it "indicates it has no required keyword args" do expect(signature.required_kw_args).to eq([]) end describe 'with an expectation object' do it 'matches the exact arity' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(true) expect(validate_expectation 2).to eq(true) end it 'matches the exact range' do expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(true) expect(validate_expectation 1, 2).to eq(true) expect(validate_expectation 1, 3).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) end it 'matches optional keywords with the correct arity' do expect(validate_expectation :z).to eq(false) expect(validate_expectation 1, :z).to eq(true) # Are we OK with that? expect(validate_expectation 1, 2, :z).to eq(true) expect(validate_expectation 1, 2, :y).to eq(false) end it 'does not match invalid keywords' do expect(validate_expectation :w).to eq(false) expect(validate_expectation 2, :w).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) end end end end if RubyFeatures.required_kw_args_supported? describe 'a method with required keyword arguments' do eval <<-RUBY def arity_required_kw(x, y:, z:, a: 'default'); end RUBY let(:test_method) { method(:arity_required_kw) } it 'returns false unless all required keywords args are present' do expect(valid?(nil, :a => 0, :y => 1, :z => 2)).to eq(true) expect(valid?(nil, :a => 0, :y => 1)).to eq(false) expect(valid?(nil, nil, :a => 0, :y => 1, :z => 2)).to eq(false) expect(valid?(nil, nil)).to eq(false) end it 'mentions the missing required keyword args in the error' do expect(error_for(nil, :a => 0)).to \ eq("Missing required keyword arguments: y, z") end it 'is described precisely when arity is wrong' do expect(error_for(nil, nil, :z => 0, :y => 1)).to \ eq("Wrong number of arguments. Expected 1, got 2.") end it 'mentions the arity, optional kw args and required kw args in the description' do expect(signature_description).to \ eq("arity of 1 and optional keyword args (:a) and required keyword args (:y, :z)") end it "indicates the optional keyword args" do expect(signature.optional_kw_args).to contain_exactly(:a) end it "indicates the required keyword args" do expect(signature.required_kw_args).to contain_exactly(:y, :z) end describe 'with an expectation object' do it 'does not match the exact arity without the required keywords' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(false) expect(validate_expectation 1, :y).to eq(false) expect(validate_expectation 1, :z).to eq(false) expect(validate_expectation 2).to eq(false) end it 'does not match the range without the required keywords' do expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(false) expect(validate_expectation 1, 1, :y).to eq(false) expect(validate_expectation 1, 1, :z).to eq(false) expect(validate_expectation 1, 2).to eq(false) end it 'matches the exact arity with the required keywords' do expect(validate_expectation 0, :y, :z).to eq(false) expect(validate_expectation 1, :y, :z).to eq(true) expect(validate_expectation 2, :y, :z).to eq(false) end it 'matches the range with the required keywords' do expect(validate_expectation 0, 1, :y, :z).to eq(false) expect(validate_expectation 1, 1, :y, :z).to eq(true) expect(validate_expectation 1, 2, :y, :z).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation :y, :z, :unlimited_args).to eq(false) end it 'matches optional keywords with the required keywords' do expect(validate_expectation 1, :a, :y, :z).to eq(true) end it 'does not match optional keywords without the required keywords' do expect(validate_expectation :a).to eq(false) expect(validate_expectation :a, :y).to eq(false) expect(validate_expectation :a, :z).to eq(false) expect(validate_expectation 1, :a).to eq(false) expect(validate_expectation 1, :a, :y).to eq(false) expect(validate_expectation 1, :a, :z).to eq(false) end it 'does not match invalid keywords' do expect(validate_expectation :w).to eq(false) expect(validate_expectation :w, :y, :z).to eq(false) expect(validate_expectation 1, :w).to eq(false) expect(validate_expectation 1, :w, :y, :z).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation :y, :z, :arbitrary_kw_args).to eq(false) end end end describe 'a method with required keyword arguments and a splat' do eval <<-RUBY def arity_required_kw_splat(w, *x, y:, z:, a: 'default'); end RUBY let(:test_method) { method(:arity_required_kw_splat) } it 'returns false unless all required keywords args are present' do expect(valid?(nil, :a => 0, :y => 1, :z => 2)).to eq(true) expect(valid?(nil, :a => 0, :y => 1)).to eq(false) expect(valid?(nil, nil, :a => 0, :y => 1, :z => 2)).to eq(true) expect(valid?(nil, nil, nil)).to eq(false) expect(valid?).to eq(false) end it 'mentions missing required keyword args in the error' do expect(error_for(nil, :y => 1)).to \ eq("Missing required keyword arguments: z") end it 'mentions the arity, optional kw args and required kw args in the description' do expect(signature_description).to \ eq("arity of 1 or more and optional keyword args (:a) and required keyword args (:y, :z)") end describe 'with an expectation object' do it 'does not match a value from the lower bound upwards' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(false) expect(validate_expectation 1, :y).to eq(false) expect(validate_expectation 1, :z).to eq(false) expect(validate_expectation 2).to eq(false) end it 'does not match a range from the lower bound upwards' do expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(false) expect(validate_expectation 1, 1, :y).to eq(false) expect(validate_expectation 1, 1, :z).to eq(false) expect(validate_expectation 1, 2).to eq(false) end it 'matches a value from the lower bound upwards with the required keywords' do expect(validate_expectation 0, :y, :z).to eq(false) expect(validate_expectation 1, :y, :z).to eq(true) expect(validate_expectation 2, :y, :z).to eq(true) expect(validate_expectation 3, :y, :z).to eq(true) end it 'matches a range from the lower bound upwards with the required keywords' do expect(validate_expectation 0, 1, :y, :z).to eq(false) expect(validate_expectation 1, 1, :y, :z).to eq(true) expect(validate_expectation 1, 2, :y, :z).to eq(true) expect(validate_expectation 3, 4, :y, :z).to eq(true) expect(validate_expectation 3, 2 ** 31, :y, :z).to eq(true) end it 'matches unlimited arguments with the minimum arity and the required keywords' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation 1, :unlimited_args).to eq(false) expect(validate_expectation :y, :z, :unlimited_args).to eq(false) expect(validate_expectation 1, :y, :z, :unlimited_args).to eq(true) end it 'matches optional keywords with the required keywords' do expect(validate_expectation 1, :a, :y, :z).to eq(true) end it 'does not match optional keywords without the required keywords' do expect(validate_expectation :a).to eq(false) expect(validate_expectation :a, :y).to eq(false) expect(validate_expectation :a, :z).to eq(false) expect(validate_expectation 1, :a).to eq(false) expect(validate_expectation 1, :a, :y).to eq(false) expect(validate_expectation 1, :a, :z).to eq(false) end it 'does not match invalid keywords' do expect(validate_expectation :w).to eq(false) expect(validate_expectation :w, :y, :z).to eq(false) expect(validate_expectation 1, :w).to eq(false) expect(validate_expectation 1, :w, :y, :z).to eq(false) end it 'does not match arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation :y, :z, :arbitrary_kw_args).to eq(false) end end end describe 'a method with only a keyword arg splat' do eval <<-RUBY def arity_kw_arg_splat(**rest); end RUBY let(:test_method) { method(:arity_kw_arg_splat) } if RubyFeatures.kw_arg_separation? it 'allows undeclared keyword args' do expect(valid?(:x => 1)).to eq(true) expect(valid?(:x => 1, 'y' => 2)).to eq(true) expect(valid?('y' => 2)).to eq(true) end else it 'allows undeclared symbol keyword args' do expect(valid?(:x => 1)).to eq(true) expect(valid?(:x => 1, 'y' => 2)).to eq(false) expect(valid?('y' => 2)).to eq(false) end end it 'mentions the required kw args and keyword splat in the description' do expect(signature_description).to \ eq("any additional keyword args") end describe 'with an expectation object' do it 'allows zero non-kw args' do expect(validate_expectation 0).to eq(true) expect(validate_expectation 1).to eq(false) expect(validate_expectation 0, 0).to eq(true) expect(validate_expectation 0, 1).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) end it 'matches arbitrary keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(true) end end end describe 'a method with required keyword arguments and a keyword arg splat' do eval <<-RUBY def arity_kw_arg_splat(x:, **rest); end RUBY let(:test_method) { method(:arity_kw_arg_splat) } it 'allows extra undeclared keyword args' do expect(valid?(:x => 1)).to eq(true) expect(valid?(:x => 1, :y => 2)).to eq(true) expect(valid?(:x => 1, :y => 2, 'z' => 3)).to eq(RubyFeatures.kw_arg_separation?) end it 'mentions missing required keyword args in the error' do expect(error_for(:y => 1)).to \ eq("Missing required keyword arguments: x") end it 'mentions the required kw args and keyword splat in the description' do expect(signature_description).to \ eq("required keyword args (:x) and any additional keyword args") end describe 'with an expectation object' do it 'does not match the exact arity without the required keywords' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(false) end it 'does not match the exact range without the required keywords' do expect(validate_expectation 0, 0).to eq(false) expect(validate_expectation 0, 1).to eq(false) end it 'matches the exact arity with the required keywords' do expect(validate_expectation 0, :x).to eq(true) end it 'does matches the exact range without the required keywords' do expect(validate_expectation 0, 0, :x).to eq(true) expect(validate_expectation 0, 1, :x).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation :x, :unlimited_args).to eq(false) end it 'matches arbitrary keywords with the required keywords' do expect(validate_expectation 0, :x, :u, :v).to eq(true) end it 'does not match arbitrary keywords without the required keywords' do expect(validate_expectation :a).to eq(false) expect(validate_expectation 0, :a).to eq(false) end it 'matches arbitrary keywords with the required keywords' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation :x, :arbitrary_kw_args).to eq(true) end end end describe 'a method with a required arg and a keyword arg splat' do eval <<-RUBY def arity_kw_arg_splat(x, **rest); end RUBY let(:test_method) { method(:arity_kw_arg_splat) } it 'allows a single arg and any number of keyword args' do expect(valid?(nil)).to eq(true) expect(valid?(nil, :x => 1)).to eq(true) expect(valid?(nil, 'x' => 1)).to eq(RubyFeatures.kw_arg_separation?) expect(valid?(nil, :x => 1, :y => 2)).to eq(true) expect(valid?(nil, :x => 1, :y => 2, 'z' => 3)).to eq(RubyFeatures.kw_arg_separation?) expect(valid?(:x => 1)).to eq(true) expect(valid?(nil, {})).to eq(true) expect(valid?).to eq(false) expect(valid?(nil, nil)).to eq(false) expect(valid?(nil, nil, :x => 1)).to eq(false) end it 'describes the arity precisely' do expect(error_for()).to \ eq("Wrong number of arguments. Expected 1, got 0.") end it 'mentions the required kw args and keyword splat in the description' do expect(signature_description).to \ eq("arity of 1 and any additional keyword args") end describe 'with an expectation object' do it 'matches the exact arity' do expect(validate_expectation 0).to eq(false) expect(validate_expectation 1).to eq(true) expect(validate_expectation 2).to eq(false) end it 'matches the exact range' do expect(validate_expectation 0, 0).to eq(false) expect(validate_expectation 0, 1).to eq(false) expect(validate_expectation 1, 1).to eq(true) expect(validate_expectation 1, 2).to eq(false) expect(validate_expectation 2, 2).to eq(false) end it 'does not match unlimited arguments' do expect(validate_expectation :unlimited_args).to eq(false) expect(validate_expectation 1, :unlimited_args).to eq(false) end it 'matches unlisted keywords with the required arity' do expect(validate_expectation 1, :u, :v).to eq(true) end it 'matches unlisted keywords with the exact range' do expect(validate_expectation 1, 1, :u, :v).to eq(true) end it 'matches arbitrary keywords with the required arity' do expect(validate_expectation :arbitrary_kw_args).to eq(false) expect(validate_expectation 1, :arbitrary_kw_args).to eq(true) end end end end describe 'a method with a block' do def arity_block(_, &block); end let(:test_method) { method(:arity_block) } it 'does not count the block as a parameter' do expect(valid_non_kw_args?(1)).to eq(true) expect(valid_non_kw_args?(2)).to eq(false) end it 'describes the arity precisely' do expect(error_description).to eq("1") end end describe 'an `attr_writer` method' do attr_writer :foo let(:test_method) { method(:foo=) } it 'validates against a single argument' do expect(valid_non_kw_args?(1)).to eq true end it 'fails validation against 0 arguments' do expect(valid_non_kw_args?(0)).to eq false end it 'fails validation against 2 arguments' do expect(valid_non_kw_args?(2)).to eq false end end if Ruby.jruby? describe 'a single-argument Java method' do let(:test_method) { Java::JavaLang::String.instance_method(:char_at) } it 'validates against a single argument' do expect(valid_non_kw_args?(1)).to eq true end it 'fails validation against 0 arguments' do expect(valid_non_kw_args?(0)).to eq false end it 'fails validation against 2 arguments' do expect(valid_non_kw_args?(2)).to eq false end end end end let(:fake_matcher) { Object.new } let(:fake_matcher_def) { lambda {|x| fake_matcher == x }} before do RSpec::Support.register_matcher_definition(&fake_matcher_def) end after do RSpec::Support.deregister_matcher_definition(&fake_matcher_def) end describe MethodSignatureExpectation do describe '#max_count' do it { expect(subject).to respond_to(:max_count).with(0).arguments } end describe '#max_count=' do it { expect(subject).to respond_to(:max_count=).with(1).argument } describe 'with nil' do before(:each) { subject.max_count = 5 } it { expect { subject.max_count = nil }.to change(subject, :max_count).to be(nil) } end describe 'with a positive integer' do let(:value) { 7 } it { expect { subject.max_count = value }.to change(subject, :max_count).to eq(value) } end describe 'with zero' do it { expect { subject.max_count = 0 }.to change(subject, :max_count).to eq(0) } end describe 'with a negative integer value' do it 'should raise an error' do expect { subject.max_count = -1 }.to raise_error ArgumentError end end describe 'with a non-integer value' do it 'should raise an error' do expect { subject.max_count = :many }.to raise_error ArgumentError end end end describe '#min_count' do it { expect(subject).to respond_to(:min_count).with(0).arguments } end describe '#min_count=' do it { expect(subject).to respond_to(:min_count=).with(1).argument } describe 'with nil' do before(:each) { subject.min_count = 5 } it { expect { subject.min_count = nil }.to change(subject, :min_count).to be(nil) } end describe 'with a positive integer' do let(:value) { 7 } it { expect { subject.min_count = value }.to change(subject, :min_count).to eq(value) } end describe 'with zero' do it { expect { subject.min_count = 0 }.to change(subject, :min_count).to eq(0) } end describe 'with a negative integer value' do it 'should raise an error' do expect { subject.min_count = -1 }.to raise_error ArgumentError end end describe 'with a non-integer value' do it 'should raise an error' do expect { subject.min_count = :many }.to raise_error ArgumentError end end end describe '#empty?' do it { expect(subject).to respond_to(:empty?).with(0).arguments } it { expect(subject.empty?).to eq(true) } describe 'with a count expectation' do before(:each) { subject.min_count = 5 } it { expect(subject.empty?).to eq(false) } end describe 'with a keywords expectation' do before(:each) { subject.keywords << :greetings << :programs } it { expect(subject.empty?).to eq(false) } end end describe '#expect_arbitrary_keywords' do it { expect(subject).to respond_to(:expect_arbitrary_keywords).with(0).arguments } it 'should default to false' do expect(described_class.new.expect_arbitrary_keywords).to eq(false) end end describe '#expect_arbitrary_keywords=' do it { expect(subject).to respond_to(:expect_arbitrary_keywords=).with(1).argument } describe 'with true' do it { expect { subject.expect_arbitrary_keywords = true }.to change(subject, :expect_arbitrary_keywords).to eq(true) } end end describe '#expect_unlimited_arguments' do it { expect(subject).to respond_to(:expect_unlimited_arguments).with(0).arguments } it 'should default to false' do expect(described_class.new.expect_unlimited_arguments).to eq(false) end end describe '#expect_unlimited_arguments=' do it { expect(subject).to respond_to(:expect_unlimited_arguments=).with(1).argument } describe 'with true' do it { expect { subject.expect_unlimited_arguments = true }.to change(subject, :expect_unlimited_arguments).to eq(true) } end end describe '#keywords' do it { expect(subject).to respond_to(:keywords).with(0).arguments } it { expect(subject.keywords).to eq(Array.new) } end describe '#keywords=' do it { expect(subject).to respond_to(:keywords=).with(1).argument } describe 'with nil' do before(:each) { subject.keywords = [:greetings, :programs] } it { expect { subject.keywords = nil }.to change(subject, :keywords).to eq(Array.new) } end describe 'with an array' do let(:keywords) { [:greetings, :programs] } it { expect { subject.keywords = keywords }.to change(subject, :keywords).to eq(keywords) } end end end describe StrictSignatureVerifier do it_behaves_like 'a method verifier' if RubyFeatures.kw_args_supported? describe 'providing a matcher for optional keyword arguments' do eval <<-RUBY def arity_kw(x, y:1); end RUBY let(:test_method) { method(:arity_kw) } it 'is not allowed' do expect(valid?(nil, fake_matcher)).to eq(false) end end end if RubyFeatures.required_kw_args_supported? describe 'providing a matcher for required keyword arguments' do eval <<-RUBY def arity_kw_required(x, y:); end RUBY let(:test_method) { method(:arity_kw_required) } it 'is not allowed' do expect(valid?(nil, fake_matcher)).to eq(false) end end end end describe LooseSignatureVerifier do it_behaves_like 'a method verifier' if RubyFeatures.kw_args_supported? describe 'for optional keyword arguments' do eval <<-RUBY def arity_kw(x, y:1, z:2); end RUBY let(:test_method) { method(:arity_kw) } it 'allows a matcher' do expect(valid?(nil, fake_matcher)).to eq(true) end it 'allows a matcher only for positional arguments' do expect(valid?(fake_matcher)).to eq(true) end end end if RubyFeatures.required_kw_args_supported? describe 'providing a matcher for required keyword arguments' do eval <<-RUBY def arity_kw_required(x, y:); end RUBY let(:test_method) { method(:arity_kw_required) } it 'is allowed' do expect(valid?(nil, fake_matcher)).to eq(true) end end end end end end end rspec-support-3.13.1/spec/rspec/support/mutex_spec.rb000066400000000000000000000003041456614207700227210ustar00rootroot00000000000000require 'rspec/support/mutex' RSpec.describe RSpec::Support::Mutex do it "allows ::Mutex to be mocked", :if => defined?(::Mutex) do expect(Mutex).to receive(:new) ::Mutex.new end end rspec-support-3.13.1/spec/rspec/support/object_formatter_spec.rb000066400000000000000000000306771456614207700251300ustar00rootroot00000000000000require 'rspec/support/object_formatter' require 'rspec/matchers/fail_matchers' module RSpec module Support RSpec.describe ObjectFormatter, ".format" do context 'with an array object containing other objects for which we have custom formatting' do let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } let(:input) { ["string", time, [3, time]] } it 'formats those objects within the array output, at any level of nesting' do formatted = ObjectFormatter.format(input) expect(formatted).to eq(%Q{["string", #{formatted_time}, [3, #{formatted_time}]]}) end end context "with a hash object containing other objects for which we have custom formatting" do let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } let(:input) { { "key" => time, time => "value", "nested" => { "key" => time } } } it 'formats those objects within the hash output, at any level of nesting' do formatted = ObjectFormatter.format(input) if RUBY_VERSION == '1.8.7' # We can't count on the ordering of the hash on 1.8.7... expect(formatted).to include(%Q{"key"=>#{formatted_time}}, %Q{#{formatted_time}=>"value"}, %Q{"nested"=>{"key"=>#{formatted_time}}}) else expect(formatted).to eq(%Q{{"key"=>#{formatted_time}, #{formatted_time}=>"value", "nested"=>{"key"=>#{formatted_time}}}}) end end end unless RUBY_VERSION == '1.8.7' # We can't count on the ordering of the hash on 1.8.7... context 'with a hash object' do let(:input) { { :c => "ccc", :a => "aaa", "b" => 'bbb' } } let(:expected) { '{:a=>"aaa", "b"=>"bbb", :c=>"ccc"}' } it 'sorts keys to ensure objects are always displayed the same way' do formatted = ObjectFormatter.format(input) expect(formatted).to eq expected end end end context 'with Time objects' do let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it 'produces an extended output' do expected_output = "1969-12-31 19:01:40.000101" expect(formatted_time).to include(expected_output) end end context 'with DateTime objects' do def with_date_loaded in_sub_process_if_possible do require 'date' yield end end let(:date_time) { DateTime.new(2000, 1, 1, 1, 1, Rational(1, 10)) } let(:formatted_date_time) { ObjectFormatter.format(date_time) } it 'formats the DateTime using inspect' do with_date_loaded do expect(formatted_date_time).to eq(date_time.inspect) end end it 'does not require DateTime to be defined since you need to require `date` to make it available' do hide_const('DateTime') expect(ObjectFormatter.format('Test String')).to eq('"Test String"') end context 'when ActiveSupport is loaded' do it "uses a custom format to ensure the output is different when DateTimes differ" do stub_const("ActiveSupport", Module.new) with_date_loaded do expected_date_time = 'Sat, 01 Jan 2000 01:01:00.100000000 +0000' expect(formatted_date_time).to eq(expected_date_time) end end end end context 'with BigDecimal objects' do let(:float) { 3.3 } let(:decimal) { BigDecimal("3.3") } let(:formatted_decimal) { ObjectFormatter.format(decimal) } if RUBY_VERSION >= '2.4' it "uses Ruby's BigDecimal formatting since it is improved in 2.4+" do in_sub_process_if_possible do require 'bigdecimal' expect(formatted_decimal).to eq('0.33e1') end end else it 'includes a conventional representation of the decimal' do in_sub_process_if_possible do require 'bigdecimal' # Suppress warning on JRuby 1.7: # file:/Users/me/.rbenv/versions/jruby-1.7.26/lib/jruby.jar!/jruby/bigdecimal.rb:1 # warning: loading in progress, circular require considered harmful - bigdecimal.jar $stderr.reset! expect(formatted_decimal).to include('3.3 (#" end end it 'includes the delegator class in the description even when protected' do with_delegate_loaded do protected_delegator = Class.new(SimpleDelegator) { protected :__getobj__ } expect( ObjectFormatter.format(protected_delegator.new(object)) ).to eq "#<#{protected_delegator.inspect}(#{object.inspect})>" end end it 'does not require Delegator to be defined' do hide_const("Delegator") expect(ObjectFormatter.format(object)).to eq object.inspect end context 'for a specially-formatted object' do let(:decimal) { BigDecimal("3.3") } let(:formatted_decimal) { ObjectFormatter.format(decimal) } let(:object) { decimal } it 'formats the underlying object normally' do with_delegate_loaded do require 'bigdecimal' # Suppress warning on JRuby 1.7: # file:/Users/me/.rbenv/versions/jruby-1.7.26/lib/jruby.jar!/jruby/bigdecimal.rb:1 # warning: loading in progress, circular require considered harmful - bigdecimal.jar $stderr.reset! expect(ObjectFormatter.format(delegator)).to eq "#" end end end end context 'with objects that implement description' do RSpec::Matchers.define :matcher_with_description do match { true } description { "description" } end RSpec::Matchers.define :matcher_without_a_description do match { true } undef description end it "produces a description when a matcher object has a description" do expect(ObjectFormatter.format(matcher_with_description)).to eq("description") end it "does not produce a description unless the object is a matcher" do double = double('non-matcher double', :description => true) expect(ObjectFormatter.format(double)).to eq(double.inspect) end it "produces an inspected object when a matcher is missing a description" do expect(ObjectFormatter.format(matcher_without_a_description)).to eq( matcher_without_a_description.inspect) end end context 'with an object that does not respond to #class and #inspect such as BasicObject' do subject(:output) do ObjectFormatter.format(input) end let(:input) do if defined?(BasicObject) BasicObject.new else fake_basic_object_class.new end end let(:fake_basic_object_class) do Class.new do def self.to_s 'BasicObject' end undef class, inspect, respond_to? end end if RUBY_VERSION == '1.9.2' it 'produces an #inspect-like output without object id' do expect(output).to eq('#') end else it "produces an output emulating MRI's #inspect-like output generated by C implementation" do expect(output).to match(/\A#\z/) end end end context 'with a recursive array' do subject(:output) do ObjectFormatter.format(input) end let(:input) do array = [time] array << array array end let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it 'formats the recursive element as [...] and other elements with custom formatting' do expect(output).to eq("[#{formatted_time}, [...]]") end end context 'with a recursive-key hash' do subject(:output) do ObjectFormatter.format(input) end let(:input) do hash = {} hash[hash] = time hash end let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it 'formats the recursive element as {...} and other elements with custom formatting' do expect(output).to eq("{{...}=>#{formatted_time}}") end end context 'with a recursive-value hash' do subject(:output) do ObjectFormatter.format(input) end let(:input) do hash = {} hash[time] = hash hash end let(:time) { Time.utc(1969, 12, 31, 19, 01, 40, 101) } let(:formatted_time) { ObjectFormatter.format(time) } it 'formats the recursive element as {...} and other elements with custom formatting' do expect(output).to eq("{#{formatted_time}=>{...}}") end end context 'with a non-immediate recursive array' do subject(:output) do ObjectFormatter.format(input) end let(:input) do array = [] array[0] = { :recursive_array => array } array end it 'formats the recursive element as [...]' do expect(output).to eq('[{:recursive_array=>[...]}]') end end context 'with a non-immediate recursive hash' do subject(:output) do ObjectFormatter.format(input) end let(:input) do hash = {} hash[:array] = [:next_is_recursive_hash, hash] hash end it 'formats the recursive element as {...}' do expect(output).to eq('{:array=>[:next_is_recursive_hash, {...}]}') end end context 'with an array including a same collection object multiple times' do subject(:output) do ObjectFormatter.format(input) end let(:input) do hash = { :key => 'value' } [hash, hash] end it 'does not omit them' do expect(output).to eq('[{:key=>"value"}, {:key=>"value"}]') end end context 'with truncation enabled' do it 'produces an output of limited length' do formatter = ObjectFormatter.new(10) expect(formatter.format('Test String Of A Longer Length')).to eq('"Test ...ngth"') end it 'does not truncate shorter strings' do formatter = ObjectFormatter.new(10) expect(formatter.format('Testing')).to eq('"Testing"') end context 'with ANSI escape codes that fall on the truncate split' do it 'removes that escape code so terminals do not get corrupted print a partial escape code' do formatter = ObjectFormatter.new(38) object = Class.new do def inspect "#<\e[33mClass\e[0m \e[36mname: \e[0m\"foobars\" \e[36mcount: \e[0m42>" end end.new expect(formatter.format(object)).to eq("#<\e[33mClass\e[0m ...\e[36mcount: \e[0m42>") end end end context 'with truncation disabled' do it 'does not limit the output length' do formatter = ObjectFormatter.new(nil) expect(formatter.format('Test String Of A Longer Length')).to eq('"Test String Of A Longer Length"') end end end end end rspec-support-3.13.1/spec/rspec/support/recursive_const_methods_spec.rb000066400000000000000000000031201456614207700265160ustar00rootroot00000000000000require 'rspec/support/recursive_const_methods' module RSpec module Support RSpec.describe RecursiveConstMethods do include described_class module Foo class Parent UNDETECTED = 'Not seen when looking up constants in Bar' end class Bar < Parent VAL = 10 end end describe '#recursive_const_defined?' do it 'finds constants' do const, _ = recursive_const_defined?('::RSpec::Support::Foo::Bar::VAL') expect(const).to eq(10) end it 'returns the fully qualified name of the constant' do _, name = recursive_const_defined?('::RSpec::Support::Foo::Bar::VAL') expect(name).to eq('RSpec::Support::Foo::Bar::VAL') end it 'does not find constants in ancestors' do expect(recursive_const_defined?('::RSpec::Support::Foo::Bar::UNDETECTED')).to be_falsy end it 'does not blow up on buggy classes that raise weird errors on `to_str`' do allow(Foo::Bar).to receive(:to_str).and_raise("boom!") const, _ = recursive_const_defined?('::RSpec::Support::Foo::Bar::VAL') expect(const).to eq(10) end end describe '#recursive_const_get' do it 'gets constants' do expect(recursive_const_get('::RSpec::Support::Foo::Bar::VAL')).to eq(10) end it 'does not get constants in ancestors' do expect do recursive_const_get('::RSpec::Support::Foo::Bar::UNDETECTED') end.to raise_error(NameError) end end end end end rspec-support-3.13.1/spec/rspec/support/reentrant_mutex_spec.rb000066400000000000000000000040421456614207700250060ustar00rootroot00000000000000require 'rspec/support/reentrant_mutex' require 'thread_order' # There are no assertions specifically # They are pass if they don't deadlock RSpec.describe RSpec::Support::ReentrantMutex do let!(:mutex) { described_class.new } let!(:order) { ThreadOrder.new } after { order.apocalypse! } it 'can repeatedly synchronize within the same thread' do mutex.synchronize { mutex.synchronize { } } end it 'locks other threads out while in the synchronize block' do order.declare(:before) { mutex.synchronize { } } order.declare(:within) { mutex.synchronize { } } order.declare(:after) { mutex.synchronize { } } order.pass_to :before, :resume_on => :exit mutex.synchronize { order.pass_to :within, :resume_on => :sleep } order.pass_to :after, :resume_on => :exit end it 'resumes the next thread once all its synchronize blocks have completed' do order.declare(:thread) { mutex.synchronize { } } mutex.synchronize { order.pass_to :thread, :resume_on => :sleep } order.join_all end # On Ruby 3.1.3+, 3.2.0 and RUBY_HEAD the raise in this spec can # bypass the `raise_error` capture and break this spec but # it is not sufficient to pend it as the raise can escape to the other # threads somehow therefore poisoning them so its skipped entirely. # This is a temporary work around to allow green cross project builds but # needs a fix. if RUBY_VERSION >= '3.0' && RUBY_VERSION < '3.1.3' && !ENV['RUBY_HEAD'] it 'waits when trying to lock from another Fiber' do mutex.synchronize do ready = false f = Fiber.new do expect { ready = true mutex.send(:enter) raise 'should reach here: mutex is already locked on different Fiber' }.to raise_error(Exception, 'waited correctly') end main_thread = Thread.current t = Thread.new do Thread.pass until ready && main_thread.stop? main_thread.raise Exception, 'waited correctly' end f.resume t.join end end end end rspec-support-3.13.1/spec/rspec/support/ruby_features_spec.rb000066400000000000000000000136251456614207700244500ustar00rootroot00000000000000require 'rspec/support/ruby_features' module RSpec module Support RSpec.describe OS do describe ".windows?" do %w[cygwin mswin mingw bccwin wince emx].each do |fragment| it "returns true when host os is #{fragment}" do stub_const("RbConfig::CONFIG", 'host_os' => fragment) expect(OS.windows?).to be true end end %w[darwin linux].each do |fragment| it "returns false when host os is #{fragment}" do stub_const("RbConfig::CONFIG", 'host_os' => fragment) expect(OS.windows?).to be false end end end describe ".windows_file_path?" do it "returns true when the file alt separator is a colon" do stub_const("File::ALT_SEPARATOR", "\\") unless OS.windows? expect(OS).to be_windows_file_path end it "returns false when file alt separator is not present" do stub_const("File::ALT_SEPARATOR", nil) if OS.windows? expect(OS).to_not be_windows_file_path end end end RSpec.describe Ruby do specify "jruby? reflects the state of RUBY_PLATFORM" do stub_const("RUBY_PLATFORM", "java") expect(Ruby).to be_jruby stub_const("RUBY_PLATFORM", "") expect(Ruby).to_not be_jruby end specify "rbx? reflects the state of RUBY_ENGINE" do stub_const("RUBY_ENGINE", "rbx") expect(Ruby).to be_rbx hide_const("RUBY_ENGINE") expect(Ruby).to_not be_rbx end specify "jruby_9000? reflects the state of RUBY_PLATFORM and JRUBY_VERSION" do stub_const("RUBY_PLATFORM", "java") stub_const("JRUBY_VERSION", "") expect(Ruby).to_not be_jruby_9000 stub_const("JRUBY_VERSION", "9.0.3.0") expect(Ruby).to be_jruby_9000 stub_const("RUBY_PLATFORM", "") expect(Ruby).to_not be_jruby_9000 end specify "rbx? reflects the state of RUBY_ENGINE" do hide_const("RUBY_ENGINE") expect(Ruby).to be_mri stub_const("RUBY_ENGINE", "ruby") expect(Ruby).to be_mri stub_const("RUBY_ENGINE", "rbx") expect(Ruby).to_not be_mri end end RSpec.describe RubyFeatures do specify "#module_refinement_supported? reflects refinement support" do if Ruby.mri? && RUBY_VERSION >= '2.1.0' expect(RubyFeatures.module_refinement_supported?).to eq true end end specify "#fork_supported? exists" do RubyFeatures.fork_supported? end specify "#supports_exception_cause? exists" do RubyFeatures.supports_exception_cause? end specify "#kw_args_supported? exists" do RubyFeatures.kw_args_supported? end specify "#required_kw_args_supported? exists" do RubyFeatures.required_kw_args_supported? end specify "distincts_kw_args_from_positional_hash?" do RubyFeatures.distincts_kw_args_from_positional_hash? end specify "#supports_rebinding_module_methods? exists" do RubyFeatures.supports_rebinding_module_methods? end specify "#supports_syntax_suggest?" do expect(RubyFeatures.supports_syntax_suggest?).to eq(RUBY_VERSION.to_f >= 3.2) end specify "#supports_taint?" do RubyFeatures.supports_taint? end specify "#caller_locations_supported? exists" do RubyFeatures.caller_locations_supported? if Ruby.mri? expect(RubyFeatures.caller_locations_supported?).to eq(RUBY_VERSION >= '2.0.0') end end describe "#ripper_supported?" do def ripper_is_implemented? in_sub_process_if_possible do begin require 'ripper' !!defined?(::Ripper) && Ripper.respond_to?(:lex) rescue LoadError false end end end def ripper_works_correctly? ripper_reports_correct_line_number? && ripper_can_parse_source_including_keywordish_symbol? && ripper_can_parse_source_referencing_keyword_arguments? end # https://github.com/jruby/jruby/issues/3386 def ripper_reports_correct_line_number? in_sub_process_if_possible do require 'ripper' tokens = ::Ripper.lex('foo') token = tokens.first location = token.first line_number = location.first line_number == 1 end end # https://github.com/jruby/jruby/issues/4562 def ripper_can_parse_source_including_keywordish_symbol? in_sub_process_if_possible do require 'ripper' sexp = ::Ripper.sexp(':if') !sexp.nil? end end # https://github.com/jruby/jruby/issues/5209 def ripper_can_parse_source_referencing_keyword_arguments? in_sub_process_if_possible do require 'ripper' # It doesn't matter if keyword arguments don't exist. if Ruby.mri? || Ruby.jruby? || Ruby.truffleruby? if RUBY_VERSION < '2.0' true else begin !::Ripper.sexp('def a(**kw_args); end').nil? rescue NoMethodError false end end end end end it 'returns whether Ripper is correctly implemented in the current environment' do if RSpec::Support::Ruby.jruby? && RSpec::Support::Ruby.jruby_version.between?('9.0.0.0', '9.2.1.0') pending "Ripper is not supported on JRuby 9.1.17.0 despite this tests claims" end expect(RubyFeatures.ripper_supported?).to eq(ripper_is_implemented? && ripper_works_correctly?) end it 'does not load Ripper' do expect { RubyFeatures.ripper_supported? }.not_to change { defined?(::Ripper) } end end end end end rspec-support-3.13.1/spec/rspec/support/source/000077500000000000000000000000001456614207700215235ustar00rootroot00000000000000rspec-support-3.13.1/spec/rspec/support/source/node_spec.rb000066400000000000000000000064671456614207700240240ustar00rootroot00000000000000require 'rspec/support/source/node' class RSpec::Support::Source RSpec.describe Node, :if => RSpec::Support::RubyFeatures.ripper_supported? do let(:root_node) do Node.new(sexp) end let(:sexp) do require 'ripper' Ripper.sexp(source) end let(:source) { <<-END } variable = do_something(1, 2) variable.do_anything do |arg| puts arg end END # [:program, # [[:assign, # [:var_field, [:@ident, "variable", [1, 6]]], # [:method_add_arg, # [:fcall, [:@ident, "do_something", [1, 17]]], # [:arg_paren, # [:args_add_block, # [[:@int, "1", [1, 30]], [:@int, "2", [1, 33]]], # false]]]], # [:method_add_block, # [:call, # [:var_ref, [:@ident, "variable", [2, 6]]], # :".", # [:@ident, "do_anything", [2, 15]]], # [:do_block, # [:block_var, # [:params, [[:@ident, "arg", [2, 31]]], nil, nil, nil, nil, nil, nil], # false], # [[:command, # [:@ident, "puts", [3, 8]], # [:args_add_block, [[:var_ref, [:@ident, "arg", [3, 13]]]], false]]]]]]] describe '#args' do context 'when the sexp args consist of direct child sexps' do let(:target_node) do root_node.find { |node| node.type == :method_add_arg } end it 'returns the child nodes' do expect(target_node.args).to match([ an_object_having_attributes(:type => :fcall), an_object_having_attributes(:type => :arg_paren) ]) end end context 'when the sexp args include an array of sexps' do let(:target_node) do root_node.find { |node| node.type == :args_add_block } end it 'returns pseudo expression sequence node for the array' do expect(target_node.args).to match([ an_object_having_attributes(:type => :_expression_sequence), false ]) end end end describe '#each_ancestor' do let(:target_node) do root_node.find { |node| node.type == :arg_paren } end it 'yields ancestor nodes from parent to root' do expect { |b| target_node.each_ancestor(&b) }.to yield_successive_args( an_object_having_attributes(:type => :method_add_arg), an_object_having_attributes(:type => :assign), an_object_having_attributes(:type => :_expression_sequence), an_object_having_attributes(:type => :program) ) end end describe '#location' do context 'with identifier type node' do let(:target_node) do root_node.find { |node| node.type == :@ident } end it 'returns a Location object with line and column numbers' do expect(target_node.location).to have_attributes(:line => 1, :column => 6) end end context 'with non-identifier type node' do let(:target_node) do root_node.find { |node| node.type == :assign } end it 'returns nil' do expect(target_node.location).to be_nil end end end describe '#inspect' do it 'returns a string including class name and node type' do expect(root_node.inspect).to eq('#') end end end end rspec-support-3.13.1/spec/rspec/support/source/token_spec.rb000066400000000000000000000043241456614207700242050ustar00rootroot00000000000000require 'rspec/support/source/token' class RSpec::Support::Source RSpec.describe Token, :if => RSpec::Support::RubyFeatures.ripper_supported? do let(:target_token) do tokens.first end let(:tokens) do Token.tokens_from_ripper_tokens(ripper_tokens) end let(:ripper_tokens) do require 'ripper' Ripper.lex(source) end let(:source) do 'puts :foo' end # [ # [[1, 0], :on_ident, "puts"], # [[1, 4], :on_sp, " "], # [[1, 5], :on_symbeg, ":"], # [[1, 6], :on_ident, "foo"] # ] describe "#closed_by" do context "with a normal ruby multi line method" do let(:source) { "def foo\n :bar\nend" } specify 'the first token is closed by the last' do expect(tokens.first).to be_closed_by(tokens.last) end end context "with a ruby one line method definition" do let(:source) { 'def self.foo = "bar"' } specify 'the first token is closed by the =' do expect(tokens.first).to be_closed_by(tokens[6]) end end end describe '#location' do it 'returns a Location object with line and column numbers' do expect(target_token.location).to have_attributes(:line => 1, :column => 0) end end describe '#type' do it 'returns a type of the token' do expect(target_token.type).to eq(:on_ident) end end describe '#string' do it 'returns a source string corresponding to the token' do expect(target_token.string).to eq('puts') end end describe '#==' do context 'when both tokens have same Ripper token' do it 'returns true' do expect(Token.new(ripper_tokens[0]) == Token.new(ripper_tokens[0])).to be true end end context 'when both tokens have different Ripper token' do it 'returns false' do expect(Token.new(ripper_tokens[0]) == Token.new(ripper_tokens[1])).to be false end end end describe '#inspect' do it 'returns a string including class name, token type and source string' do expect(target_token.inspect).to eq('#') end end end end rspec-support-3.13.1/spec/rspec/support/source_spec.rb000066400000000000000000000104161456614207700230640ustar00rootroot00000000000000require 'rspec/support/source' module RSpec::Support RSpec.describe Source, :if => RSpec::Support::RubyFeatures.ripper_supported? do subject(:source) do Source.new(source_string) end let(:source_string) { <<-END.gsub(/^ +\|/, '') } |2.times do | puts :foo |end END # [:program, # [[:method_add_block, # [:call, [:@int, "2", [1, 0]], :".", [:@ident, "times", [1, 2]]], # [:do_block, # nil, # [[:command, # [:@ident, "puts", [2, 2]], # [:args_add_block, # [[:symbol_literal, [:symbol, [:@ident, "foo", [2, 8]]]]], # false]]]]]]] describe '.from_file', :isolated_directory do subject(:source) do Source.from_file(path) end let(:path) do 'source.rb' end before do File.open(path, 'w') { |file| file.write(source_string) } end it 'returns a Source with the absolute path' do expect(source.lines.first).to eq('2.times do') expect(source.path).not_to eq(path) expect(source.path).to end_with(path) end it 'continues to work if File.read is stubbed' do allow(::File).to receive(:read).and_raise expect(source.lines.first).to eq('2.times do') end end describe '#lines' do it 'returns an array of lines without linefeed' do expect(source.lines).to eq([ '2.times do', ' puts :foo', 'end' ]) end it 'returns an array of lines no matter the encoding' do source_string << "\xAE" encoded_string = source_string.force_encoding('US-ASCII') expect(Source.new(encoded_string).lines).to eq([ '2.times do', ' puts :foo', 'end', '?', ]) end end describe '#ast' do it 'returns a root node' do expect(source.ast).to have_attributes(:type => :program) end end describe '#tokens' do it 'returns an array of tokens' do expect(source.tokens).to all be_a(Source::Token) end end describe '#nodes_by_line_number' do it 'returns a hash containing nodes for each line number' do expect(source.nodes_by_line_number).to match( 1 => if RUBY_VERSION >= '2.6.0' [ an_object_having_attributes(:type => :@int), an_object_having_attributes(:type => :@period), an_object_having_attributes(:type => :@ident) ] else [ an_object_having_attributes(:type => :@int), an_object_having_attributes(:type => :@ident) ] end, 2 => [ an_object_having_attributes(:type => :@ident), an_object_having_attributes(:type => :@ident) ] ) expect(source.nodes_by_line_number[0]).to be_empty end end describe '#tokens_by_line_number' do it 'returns a hash containing tokens for each line number' do expect(source.tokens_by_line_number).to match( 1 => [ an_object_having_attributes(:type => :on_int), an_object_having_attributes(:type => :on_period), an_object_having_attributes(:type => :on_ident), an_object_having_attributes(:type => :on_sp), an_object_having_attributes(:type => :on_kw), an_object_having_attributes(:type => :on_ignored_nl) ], 2 => [ an_object_having_attributes(:type => :on_sp), an_object_having_attributes(:type => :on_ident), an_object_having_attributes(:type => :on_sp), an_object_having_attributes(:type => :on_symbeg), an_object_having_attributes(:type => :on_ident), an_object_having_attributes(:type => :on_nl) ], 3 => [ an_object_having_attributes(:type => :on_kw), an_object_having_attributes(:type => :on_nl) ] ) expect(source.tokens_by_line_number[0]).to be_empty end end describe '#inspect' do it 'returns a string including class name and file path' do expect(source.inspect).to start_with('#') end end end end rspec-support-3.13.1/spec/rspec/support/spec/000077500000000000000000000000001456614207700211555ustar00rootroot00000000000000rspec-support-3.13.1/spec/rspec/support/spec/in_sub_process_spec.rb000066400000000000000000000027701456614207700255370ustar00rootroot00000000000000require 'tempfile' RSpec.describe 'isolating code to a sub process' do it 'isolates the block from the main process' do in_sub_process do module NotIsolated end expect(defined? NotIsolated).to eq "constant" end expect(defined? NotIsolated).to be_nil end if Process.respond_to?(:fork) && !(RUBY_PLATFORM == 'java' && RUBY_VERSION == '1.8.7') it 'returns the result of sub process' do expect(in_sub_process { :foo }).to eq(:foo) end it 'returns a UnmarshableObject if the result of sub process cannot be marshaled' do expect(in_sub_process { proc {} }).to be_a(RSpec::Support::InSubProcess::UnmarshableObject) end it 'captures and reraises errors to the main process' do expect { in_sub_process { raise "An Internal Error" } }.to raise_error "An Internal Error" end it 'captures and reraises test failures' do expect { in_sub_process { expect(true).to be false } }.to raise_error(/expected false/) end it 'fails if the sub process generates warnings' do expect { in_sub_process do # Redirect stderr so we don't get "boom" in our test suite output $stderr.reopen(Tempfile.new("stderr")) warn "boom" end }.to raise_error(RuntimeError, a_string_including("Warnings", "boom")) end else it 'pends the block' do expect { in_sub_process { true } }.to raise_error(/This spec requires forking to work properly/) end end end rspec-support-3.13.1/spec/rspec/support/spec/shell_out_spec.rb000066400000000000000000000034431456614207700245160ustar00rootroot00000000000000require 'rspec/support/spec/shell_out' RSpec.describe RSpec::Support::ShellOut, :slow do include described_class it 'shells out and returns stdout and stderr' do stdout, stderr, _ = shell_out("ruby", "-e", "$stdout.print 'yes'; $stderr.print 'no'") expect(stdout).to eq("yes") expect(stderr).to eq("no") end it 'returns the exit status as the third argument' do _, _, good_status = shell_out("ruby", "-e", '3 + 3') expect(good_status.exitstatus).to eq(0) unless RUBY_VERSION.to_f < 1.9 # except 1.8... _, _, bad_status = shell_out("ruby", "-e", 'boom') expect(bad_status.exitstatus).to eq(1) end end it 'can shell out to ruby with the current load path' do skip "Need to investigate why this is failing -- see " \ "https://travis-ci.org/rspec/rspec-core/jobs/60327106 and " \ "https://travis-ci.org/rspec/rspec-support/jobs/60296920 for examples" out, err, status = run_ruby_with_current_load_path('puts $LOAD_PATH.sort.join("\n")') expect(err).to eq("") expect(out).to include(*$LOAD_PATH.first(10)) expect(status.exitstatus).to eq(0) end it 'passes along the provided ruby flags' do out, err, status = run_ruby_with_current_load_path('puts "version"', '-v') expect(out).to include('version', RUBY_DESCRIPTION) expect(strip_known_warnings err).to eq('') expect(status.exitstatus).to eq(0) end it 'filters out the annoying output issued by `ruby -w` when the GC ENV vars are set' do with_env 'RUBY_GC_HEAP_FREE_SLOTS' => '10001', 'RUBY_GC_MALLOC_LIMIT' => '16777217', 'RUBY_FREE_MIN' => '10001' do out, err, status = run_ruby_with_current_load_path('', '-w') expect(out).to eq('') expect(strip_known_warnings err).to eq('') expect(status.exitstatus).to eq(0) end end end rspec-support-3.13.1/spec/rspec/support/spec/stderr_splitter_spec.rb000066400000000000000000000054001456614207700257440ustar00rootroot00000000000000require 'rspec/support/spec/stderr_splitter' require 'tempfile' require 'rspec/support/spec/in_sub_process' RSpec.describe 'RSpec::Support::StdErrSplitter' do include RSpec::Support::InSubProcess let(:splitter) { RSpec::Support::StdErrSplitter.new stderr } let(:stderr) { STDERR } before do allow(stderr).to receive(:write) end around do |example| original = $stderr $stderr = splitter example.run $stderr = original end it 'conforms to the stderr interface' do # There some methods that appear in the list of the #methods but actually not implemented: # # $stderr.pressed? # NotImplementedError: pressed?() function is unimplemented on this machine stderr_methods = stderr.methods.select { |method| stderr.respond_to?(method) } # On 2.2, there's a weird issue where stderr sometimes responds to `birthtime` and sometimes doesn't... stderr_methods -= [:birthtime] if RUBY_VERSION =~ /^2\.2/ # No idea why, but on our AppVeyor windows builds it doesn't respond to these... stderr_methods -= [:close_on_exec?, :close_on_exec=] if RSpec::Support::OS.windows? && ENV['CI'] expect(splitter).to respond_to(*stderr_methods) end it 'acknowledges its own interface' do expect(splitter).to respond_to :==, :write, :has_output?, :reset!, :verify_no_warnings!, :output end it 'supports methods that stderr supports but StringIO does not' do expect(StringIO.new).not_to respond_to(:stat) expect(splitter.stat).to be_a(File::Stat) end it 'supports #to_io' do expect(splitter.to_io).to be(stderr.to_io) end it 'behaves like stderr' do splitter.write 'a warning' expect(stderr).to have_received(:write) end it 'pretends to be stderr' do expect(splitter).to eq stderr end it 'resets when reopened' do in_sub_process(false) do warn 'a warning' allow(stderr).to receive(:write).and_call_original Tempfile.open('stderr') do |file| splitter.reopen(file) expect { splitter.verify_no_warnings! }.not_to raise_error end end end it 'tracks when output to' do splitter.write 'a warning' expect(splitter).to have_output end it 'will ignore examples without a warning' do splitter.verify_no_warnings! end it 'will ignore examples after a reset a warning' do warn 'a warning' splitter.reset! splitter.verify_no_warnings! end unless RSpec::Support::Ruby.rbx? || RSpec::Support::Ruby.truffleruby? # TruffleRuby doesn't support warnings for now # https://github.com/oracle/truffleruby/issues/2595 it 'will fail an example which generates a warning' do true unless $undefined expect { splitter.verify_no_warnings! }.to raise_error(/Warnings were generated:/) end end end rspec-support-3.13.1/spec/rspec/support/spec/with_isolated_std_err_spec.rb000066400000000000000000000007671456614207700271070ustar00rootroot00000000000000require 'rspec/support/spec' RSpec.describe 'isolating a spec from the stderr splitter' do include RSpec::Support::WithIsolatedStdErr it 'allows a spec to output a warning' do with_isolated_stderr do $stderr.puts "Imma gonna warn you" end end it 'resets $stderr to its original value even if an error is raised' do orig_stderr = $stderr expect { with_isolated_stderr { raise "boom" } }.to raise_error("boom") expect($stderr).to be(orig_stderr) end end rspec-support-3.13.1/spec/rspec/support/warnings_spec.rb000066400000000000000000000042131456614207700234120ustar00rootroot00000000000000require "spec_helper" require "rspec/support/warnings" require 'rspec/support/spec/shell_out' RSpec.describe "rspec warnings and deprecations" do include RSpec::Support::ShellOut let(:warning_object) do Object.new.tap { |o| o.extend(RSpec::Support::Warnings) } end it 'works when required in isolation' do out, err, status = run_ruby_with_current_load_path("RSpec.deprecate('foo')", "-rrspec/support/warnings") expect(out).to eq("") expect(err).to start_with("DEPRECATION: foo is deprecated") expect(status.exitstatus).to eq(0) end context "when rspec-core is not available" do shared_examples "falling back to Kernel.warn" do |args| let(:method_name) { args.fetch(:method_name) } it 'falls back to warning with a plain message' do expect(::Kernel).to receive(:warn).with(/message/) warning_object.send(method_name, 'message') end it "handles being passed options" do expect(::Kernel).to receive(:warn).with(/message/) warning_object.send(method_name, "this is the message", :type => :test) end end it_behaves_like 'falling back to Kernel.warn', :method_name => :deprecate it_behaves_like 'falling back to Kernel.warn', :method_name => :warn_deprecation end shared_examples "warning helper" do |helper| it 'warns with the message text' do expect(::Kernel).to receive(:warn).with(/Message/) warning_object.send(helper, 'Message') end it 'sets the calling line' do expect(::Kernel).to receive(:warn).with(/#{__FILE__}:#{__LINE__+1}/) warning_object.send(helper, 'Message') end it 'optionally sets the replacement' do expect(::Kernel).to receive(:warn).with(/Use Replacement instead./) warning_object.send(helper, 'Message', :replacement => 'Replacement') end end describe "#warning" do it 'prepends WARNING:' do expect(::Kernel).to receive(:warn).with(/WARNING: Message\./) warning_object.warning 'Message' end it_should_behave_like 'warning helper', :warning end describe "#warn_with message, options" do it_should_behave_like 'warning helper', :warn_with end end rspec-support-3.13.1/spec/rspec/support/with_keywords_when_needed_spec.rb000066400000000000000000000027301456614207700270130ustar00rootroot00000000000000require 'rspec/support/with_keywords_when_needed' module RSpec::Support RSpec.describe "WithKeywordsWhenNeeded" do describe ".class_exec" do extend RubyFeatures let(:klass) do Class.new do def self.check_argument(argument) raise ArgumentError unless argument == 42 end end end def run(klass, *args, &block) WithKeywordsWhenNeeded.class_exec(klass, *args, &block) end it "will run a block without keyword arguments" do run(klass, 42) { |arg| check_argument(arg) } end it "will run a block with a hash without keyword arguments" do run(klass, "value" => 42) { |arg| check_argument(arg["value"]) } end it "will run a block with optional keyword arguments when none are provided", :if => kw_args_supported? do binding.eval(<<-CODE, __FILE__, __LINE__) run(klass, 42) { |arg, val: nil| check_argument(arg) } CODE end it "will run a block with optional keyword arguments when they are provided", :if => required_kw_args_supported? do binding.eval(<<-CODE, __FILE__, __LINE__) run(klass, val: 42) { |val: nil| check_argument(val) } CODE end it "will run a block with required keyword arguments", :if => required_kw_args_supported? do binding.eval(<<-CODE, __FILE__, __LINE__) run(klass, val: 42) { |val:| check_argument(val) } CODE end end end end rspec-support-3.13.1/spec/rspec/support_spec.rb000066400000000000000000000231531456614207700215660ustar00rootroot00000000000000require 'rspec/support' require 'rspec/support/spec/library_wide_checks' module RSpec describe Support do extend Support::RubyFeatures it_behaves_like "library wide checks", "rspec-support", :consider_a_test_env_file => %r{rspec/support/spec}, :allowed_loaded_feature_regexps => [ /rbconfig/, # Used by RubyFeatures /prettyprint.rb/, /pp.rb/, /diff\/lcs/ # These are all loaded by the differ. ] describe '.method_handle_for(object, method_name)' do untampered_class = Class.new do def foo :bar end end http_request_class = Struct.new(:method, :uri) proxy_class = Struct.new(:original) do undef :=~ if respond_to?(:=~) undef :method if respond_to?(:method) def method_missing(name, *args, &block) original.__send__(name, *args, &block) end end it 'fetches method definitions for vanilla objects' do object = untampered_class.new expect(Support.method_handle_for(object, :foo).call).to eq :bar end it 'fetches method definitions for objects with method redefined' do request = http_request_class.new(:get, "http://foo.com/") expect(Support.method_handle_for(request, :uri).call).to eq "http://foo.com/" end it 'fetches method definitions for proxy objects' do object = proxy_class.new('abc') expect(Support.method_handle_for(object, :=~)).to be_a Method end it 'fetches method definitions for proxy objects' do object = proxy_class.new('abc') expect(Support.method_handle_for(object, :=~)).to be_a Method end it 'fails with `NameError` when an undefined method is fetched ' + 'from an object that has overridden `method` to raise an Exception' do object = double allow(object).to receive(:method).and_raise(Exception) expect { Support.method_handle_for(object, :some_undefined_method) }.to raise_error(NameError) end it 'fails with `NameError` when a method is fetched from an object ' + 'that has overridden `method` to not return a method' do object = proxy_class.new(double(:method => :baz)) expect { Support.method_handle_for(object, :=~) }.to raise_error(NameError) end context "for a BasicObject subclass", :if => RUBY_VERSION.to_f > 1.8 do let(:basic_class) do Class.new(BasicObject) do def foo :bar end end end let(:basic_class_with_method_override) do Class.new(basic_class) do def method :method end end end let(:basic_class_with_kernel) do Class.new(basic_class) do include ::Kernel end end let(:basic_class_with_proxying) do Class.new(BasicObject) do def method_missing(name, *args, &block) "foo".__send__(name, *args, &block) end end end it 'still works', :if => supports_rebinding_module_methods? do object = basic_class.new expect(Support.method_handle_for(object, :foo).call).to eq :bar end it 'works when `method` has been overridden', :if => supports_rebinding_module_methods? do object = basic_class_with_method_override.new expect(Support.method_handle_for(object, :foo).call).to eq :bar end it 'allows `method` to be proxied', :unless => supports_rebinding_module_methods? do object = basic_class_with_proxying.new expect(Support.method_handle_for(object, :reverse).call).to eq "oof" end it 'still works when Kernel has been mixed in' do object = basic_class_with_kernel.new expect(Support.method_handle_for(object, :foo).call).to eq :bar end end end describe '.class_of' do subject(:klass) do Support.class_of(object) end context 'with a String instance' do let(:object) do 'foo' end it { is_expected.to equal(String) } end context 'with a BasicObject instance' do let(: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 { is_expected.to equal(basic_object_class) } end context 'with nil' do let(:object) do nil end it { is_expected.to equal(NilClass) } end context 'with an object having a singleton class' do let(:object) do object = 'foo' def object.some_method end object end it 'returns its non-singleton ancestor class' do expect(klass).to equal(String) end end context 'with a Class instance' do let(:object) do String end it { is_expected.to equal(Class) } end end describe ".thread_local_data" do it "contains data local to the current thread" do RSpec::Support.thread_local_data[:__for_test] = :oh_hai Thread.new do expect(RSpec::Support.thread_local_data).to eq({}) end.join end if defined?(Fiber) && RUBY_VERSION.to_f >= 2.0 it "shares data across fibres" do RSpec::Support.thread_local_data[:__for_test] = :oh_hai Fiber.new do expect(RSpec::Support.thread_local_data[:__for_test]).to eq(:oh_hai) end.resume end end end describe "failure notification" do before { @failure_notifier = RSpec::Support.failure_notifier } after { RSpec::Support.failure_notifier = @failure_notifier } let(:error) { NotImplementedError.new("some message") } let(:failures) { [] } let(:append_to_failures_array_notifier) { lambda { |failure, _opts| failures << failure } } def notify(failure) RSpec::Support.notify_failure(failure) end def append_to_failures_array_instead_of_raising avoid_raising_errors.and change { failures }.from([]).to([error]) end def raise_instead_of_appending_to_failures_array raise_error(error).and avoid_changing { failures } end it "defaults to raising the provided exception" do expect { notify(error) }.to raise_error(error) end it "can be set to another callable" do RSpec::Support.failure_notifier = append_to_failures_array_notifier expect { notify(error) }.to append_to_failures_array_instead_of_raising end it "isolates notifier changes to the current thread" do RSpec::Support.failure_notifier = append_to_failures_array_notifier Thread.new do expect { notify(error) }.to raise_instead_of_appending_to_failures_array end.join end it "can be changed for the duration of a block" do yielded = false RSpec::Support.with_failure_notifier(append_to_failures_array_notifier) do yielded = true expect { notify(error) }.to append_to_failures_array_instead_of_raising end expect(yielded).to be true end it "resets the notifier back to what it originally was when the block completes, even if an error was raised" do expect { RSpec::Support.with_failure_notifier(append_to_failures_array_notifier) do raise "boom" end }.to raise_error("boom") expect { notify(error) }.to raise_instead_of_appending_to_failures_array end end describe "warning notification" do include RSpec::Support::Warnings before { @warning_notifier = RSpec::Support.warning_notifier } after { RSpec::Support.warning_notifier = @warning_notifier } let(:warnings) { [] } let(:append_to_warnings_array_notifier) { lambda { |warning| warnings << warning } } def append_to_array_instead_of_warning change { warnings }.from([]).to([a_string_including('some warning')]) end it "defaults to warning with the provided text" do expect { warning('some warning') }.to output(a_string_including 'some warning').to_stderr end it "can be set to another callable" do RSpec::Support.warning_notifier = append_to_warnings_array_notifier expect { warning('some warning') }.to append_to_array_instead_of_warning end end describe Support::AllExceptionsExceptOnesWeMustNotRescue do it "rescues a StandardError" do expect { begin raise StandardError rescue subject end }.not_to raise_error end it 'rescues an Exception' do expect { begin raise Exception rescue subject end }.not_to raise_error end Support::AllExceptionsExceptOnesWeMustNotRescue::AVOID_RESCUING.each do |klass| exception = if klass == SignalException SignalException.new("INT") else klass end it "does not rescue a #{klass}" do expect { begin raise exception rescue subject end }.to raise_error(klass) end end end end end rspec-support-3.13.1/spec/spec_helper.rb000066400000000000000000000003161456614207700202110ustar00rootroot00000000000000require 'rspec/support/spec' RSpec::Support::Spec.setup_simplecov RSpec::Matchers.define_negated_matcher :avoid_raising_errors, :raise_error RSpec::Matchers.define_negated_matcher :avoid_changing, :change