module Ameba::Spec::ExpectIssue

Overview

Mixin for #expect_issue and #expect_no_issues

This mixin makes it easier to specify strict issue expectations in a declarative and visual fashion. Just type out the code that should generate an issue, annotate code by writing '^'s underneath each character that should be highlighted, and follow the carets with a string (separated by a space) that is the message of the issue. You can include multiple issues in one code snippet.

Usage:

expect_issue subject, <<-CRYSTAL
  a do
    b
  end.c
  # ^^^ error: Avoid chaining a method call on a do...end block.
  CRYSTAL

Equivalent assertion without #expect_issue:

source = Source.new <<-CRYSTAL, "source.cr"
  a do
    b
  end.c
  CRYSTAL
subject.catch(source).should_not be_valid
source.issues.size.should be(1)

issue = source.issues.first
issue.location.to_s.should eq "source.cr:3:1"
issue.end_location.to_s.should eq "source.cr:3:5"
issue.message.should eq(
  "Avoid chaining a method call on a do...end block."
)

Autocorrection can be tested using #expect_correction after #expect_issue.

source = expect_issue subject, <<-CRYSTAL
  x % 2 == 0
  # ^^^^^^^^ error: Replace with `Int#even?`.
  CRYSTAL

expect_correction source, <<-CRYSTAL
  x.even?
  CRYSTAL

If you do not want to specify an issue then use the companion method #expect_no_issues. This method is a much simpler assertion since it just inspects the code and checks that there were no issues. The #expect_issue method has to do more work by parsing out lines that contain carets.

If the code produces an issue that could not be auto-corrected, you can use #expect_no_corrections after #expect_issue.

source = expect_issue subject, <<-CRYSTAL
  a do
    b
  end.c
  # ^^^ error: Avoid chaining a method call on a do...end block.
  CRYSTAL

expect_no_corrections source

If your code has variables of different lengths, you can use %{foo}, ^{foo}, and _{foo} to format your template; you can also abbreviate issue messages with [...]:

%w[raise fail].each do |keyword|
  expect_issue subject, <<-CRYSTAL, keyword: keyword
    %{keyword} Exception.new(msg)
    # ^{keyword}^^^^^^^^^^^^^^^^^ error: Redundant `Exception.new` [...]
    CRYSTAL

%w[has_one has_many].each do |type|
  expect_issue subject, <<-CRYSTAL, type: type
    class Book
      %{type} :chapter, foreign_key: "book_id"
      _{type}         # ^^^^^^^^^^^^^^^^^^^^^^ error: Specifying the default [...]
    end
    CRYSTAL
end

If you need to specify an issue on a blank line, use the empty ^{} marker:

expect_issue subject, <<-CRYSTAL

  # ^{} error: Missing frozen string literal comment.
  puts 1
  CRYSTAL

Included Modules

Defined in:

ameba/spec/expect_issue.cr

Instance Method Summary

Instance methods inherited from module Ameba::Spec::Util

normalize_code(code, separator = '\n') normalize_code

Instance Method Detail

def expect_correction(source, correction, *, file = __FILE__, line = __LINE__) #

[View source]
def expect_issue(rules : Rule::Base | Enumerable(Rule::Base), annotated_code : String, path = "", *, file = __FILE__, line = __LINE__, **replacements) #

[View source]
def expect_no_corrections(source, *, file = __FILE__, line = __LINE__) #

[View source]
def expect_no_issues(rules : Rule::Base | Enumerable(Rule::Base), code : String, path = "", *, file = __FILE__, line = __LINE__) #

[View source]