File: matchers_with_side_effects.rb

package info (click to toggle)
ruby-test-prof 0.12.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 508 kB
  • sloc: ruby: 4,075; makefile: 4
file content (83 lines) | stat: -rw-r--r-- 3,074 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# frozen_string_literal: true

require_relative "../language"

module RuboCop
  module Cop
    module RSpec
      class AggregateExamples < ::RuboCop::Cop::Cop
        # When aggregated, the expectations will fail when not supposed to or
        # have a risk of not failing when expected to. One example is
        # `validate_presence_of :comment` as it leaves an empty comment after
        # itself on the subject making it invalid and the subsequent expectation
        # to fail.
        # Examples with those matchers are not supposed to be aggregated.
        #
        # @example MatchersWithSideEffects
        #
        #   # .rubocop.yml
        #   # RSpec/AggregateExamples:
        #   #   MatchersWithSideEffects:
        #   #   - allow_value
        #   #   - allow_values
        #   #   - validate_presence_of
        #
        #   # bad, but isn't automatically correctable
        #   describe do
        #     it { is_expected.to validate_presence_of(:comment) }
        #     it { is_expected.to be_valid }
        #   end
        #
        # @internal
        #   Support for taking special care of the matchers that have side
        #   effects, i.e. leave the subject in a modified state.
        module MatchersWithSideEffects
          extend RuboCop::NodePattern::Macros
          include RuboCop::Cop::RSpec::Language

          MSG_FOR_EXPECTATIONS_WITH_SIDE_EFFECTS =
            "Aggregate with the example at line %d. IMPORTANT! Pay attention " \
            "to the expectation order, some of the matchers have side effects."

          private

          def message_for(example, first_example)
            return super unless example_with_side_effects?(example)

            format(MSG_FOR_EXPECTATIONS_WITH_SIDE_EFFECTS, first_example.loc.line)
          end

          def matcher_with_side_effects_names
            cop_config.fetch("MatchersWithSideEffects", [])
              .map(&:to_sym)
          end

          def matcher_with_side_effects_name?(matcher_name)
            matcher_with_side_effects_names.include?(matcher_name)
          end

          # In addition to base definition, matches examples with:
          # - no matchers known to have side-effects
          def_node_matcher :example_for_autocorrect?, <<-PATTERN
            [ #super !#example_with_side_effects? ]
          PATTERN

          # Matches the example with matcher with side effects
          def_node_matcher :example_with_side_effects?, <<-PATTERN
            (block #{Examples::EXAMPLES.send_pattern} _ #expectation_with_side_effects?)
          PATTERN

          # Matches the expectation with matcher with side effects
          def_node_matcher :expectation_with_side_effects?, <<-PATTERN
            (send #expectation? #{Runners::ALL.node_pattern_union} #matcher_with_side_effects?)
          PATTERN

          # Matches the matcher with side effects
          def_node_search :matcher_with_side_effects?, <<-PATTERN
            (send nil? #matcher_with_side_effects_name? ...)
          PATTERN
        end
      end
    end
  end
end