Class: LintTrappings::Matchers::ReportLintMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/lint_trappings/spec/matchers/report_lint_matcher.rb

Overview

RSpec matcher that returns whether or not a linter reported lints matching the specified criteria.

Examples:


it { should report_lint line: 2 }

Constant Summary collapse

ALLOWED_KEYWORD_ARGUMENTS =
%i[line message]

Instance Method Summary collapse

Constructor Details

#initialize(*args, **kwargs) ⇒ ReportLintMatcher

Returns a new instance of ReportLintMatcher.


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
# File 'lib/lint_trappings/spec/matchers/report_lint_matcher.rb', line 13

def initialize(*args, **kwargs)
  @options = kwargs

  if args.any?
    raise ArgumentError,
          '`report_lint` was given more than one argument!' if args.length > 1

    if @options[:line]
      raise ArgumentError,
            '`line` keyword argument cannot be specified when Range is given'
    end

    @range = args.first
    if @range.is_a?(Array)
      if @range.length != 2 ||
         !@range.first.is_a?(Integer) ||
         !@range.last.is_a?(Integer)
        raise ArgumentError,
              'Location tuple must be an Array of two integers ' \
              "representing line and column, but was #{@range.inspect}"
      end

      # Convert to an actual range by assuming it spans nothing
      @range = @range..@range
    elsif !@range.is_a?(Range)
      raise ArgumentError, '`report_lint` must be given a Range e.g. [1, 2]..[3, 4]'
    elsif !(@range.begin.is_a?(Array) && @range.end.is_a?(Array))
      raise ArgumentError, 'Source range must have Array tuple endpoints'
    end
  else
    # Otherwise no explicit range was specified, so verify the options
    @options.keys.each do |key|
      raise ArgumentError,
            "Unknown keyword argument #{key}" unless ALLOWED_KEYWORD_ARGUMENTS.include?(key)
    end

    @line = @options[:line]
  end

  @message = @options[:message] if @options[:message]
end

Instance Method Details

#descriptionObject


114
115
116
117
118
119
120
121
122
123
124
# File 'lib/lint_trappings/spec/matchers/report_lint_matcher.rb', line 114

def description
  output = 'report a lint'
  output <<
    if @line
      " on line #{@line}"
    elsif @range
      " on #{range_to_str(@range)}"
    end.to_s

  output
end

#failure_messageObject


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/lint_trappings/spec/matchers/report_lint_matcher.rb', line 65

def failure_message
  output = 'expected that a lint would be reported'

  if !any_range_matches?
    output <<
      if @line
        " on line #{@line}"
      elsif @range
        " on #{range_to_str(@range)}"
      end.to_s

    output <<
      case @lints.count
      when 0
        ', but none were'
      when 1
        if @line
          ", but was reported on line #{@lints.first.source_range.begin.line}"
        elsif @range
          ", but was reported on #{range_to_str(@lints.first.source_range)}"
        end.to_s
      else
        if @line
          ", but lints were reported on the following lines instead:\n" +
            @lints.map { |lint| lint.source_range.line }.sort.join(', ')
        elsif @range
          ", but lints were reported on the following ranges instead:\n" +
            @lints.map { |lint| range_to_str(lint.source_range) }.join("\n")
        end.to_s
      end
  elsif @message
    matching_lints = lints_matching_range
    output <<
      if @message.is_a?(Regexp)
        " with message matching pattern #{@message.inspect} "
      else
        " with message #{@message.inspect} "
      end

    output << "but got:\n" << matching_lints.map(&:message).join("\n")
  end

  output
end

#failure_message_when_negatedObject


110
111
112
# File 'lib/lint_trappings/spec/matchers/report_lint_matcher.rb', line 110

def failure_message_when_negated
  'expected that a lint would NOT be reported'
end

#matches?(linter) ⇒ Boolean

Returns:

  • (Boolean)

55
56
57
58
59
60
61
62
63
# File 'lib/lint_trappings/spec/matchers/report_lint_matcher.rb', line 55

def matches?(linter)
  # We're cheating by accessing private values here, but it will allow us to
  # present more-helpful error messages since we get access to so much more
  # information by passing the linter instead of just a list of lints.
  @linter = linter
  @lints = linter.instance_variable_get(:@lints)

  any_lint_matches?
end