Skip to content

Commit

Permalink
Use proper source location for should calls without a block (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
segiddins committed Feb 20, 2024
1 parent 9c4a523 commit 098f0e3
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 21 deletions.
19 changes: 15 additions & 4 deletions lib/shoulda/context/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,20 @@ def teardown(&blk)
self.teardown_blocks << blk
end

def should(name_or_matcher, options = {}, &blk)
class LambdaWithLocation < Proc
attr_reader :source_location

def initialize(source_location, &blk)
@source_location = source_location
super(&blk)
end
end

def should(name_or_matcher, options = {}, source_location = (loc = caller_locations(1, 1)[0]
[loc.path, loc.lineno]), &blk)
if name_or_matcher.respond_to?(:description) && name_or_matcher.respond_to?(:matches?)
name = name_or_matcher.description
blk = lambda { assert_accepts name_or_matcher, subject }
blk = LambdaWithLocation.new(source_location, &lambda { assert_accepts name_or_matcher, subject })
else
name = name_or_matcher
end
Expand All @@ -71,9 +81,10 @@ def should(name_or_matcher, options = {}, &blk)
end
end

def should_not(matcher)
def should_not(matcher, source_location = (loc = caller_locations(1, 1)[0]
[loc.path, loc.lineno]))
name = matcher.description
blk = lambda { assert_rejects matcher, subject }
blk = LambdaWithLocation.new(source_location, &lambda { assert_rejects matcher, subject })
self.shoulds << { :name => "not #{name}", :block => blk }
end

Expand Down
14 changes: 8 additions & 6 deletions lib/shoulda/context/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ module ClassMethods
# should validate_presence_of(:first_name).with_message(/gotta be there/)
#

def should(name_or_matcher, options = {}, &blk)
def should(name_or_matcher, options = {}, source_location = (loc = caller_locations(1, 1)[0]
[loc.path, loc.lineno]), &blk)
if Shoulda::Context.current_context
Shoulda::Context.current_context.should(name_or_matcher, options, &blk)
Shoulda::Context.current_context.should(name_or_matcher, options, source_location, &blk)
else
context_name = self.name.gsub(/Test$/, "") if name
context = Shoulda::Context::Context.new(context_name, self) do
should(name_or_matcher, options, &blk)
should(name_or_matcher, options, source_location, &blk)
end
context.build
end
Expand All @@ -80,13 +81,14 @@ def should(name_or_matcher, options = {}, &blk)
# === Example:
#
# should_not set_the_flash
def should_not(matcher)
def should_not(matcher, source_location = (loc = caller_locations(1, 1)[0]
[loc.path, loc.lineno]))
if Shoulda::Context.current_context
Shoulda::Context.current_context.should_not(matcher)
Shoulda::Context.current_context.should_not(matcher, source_location)
else
context_name = self.name.gsub(/Test$/, "") if name
context = Shoulda::Context::Context.new(context_name, self) do
should_not(matcher)
should_not(matcher, source_location)
end
context.build
end
Expand Down
39 changes: 29 additions & 10 deletions test/shoulda/rerun_snippet_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,44 @@ class RerunSnippetTest < PARENT_TEST_CASE
require_relative "../../config/environment"
class FailingTest < #{PARENT_TEST_CASE}
class FakeMatcher
attr_reader :subject
attr_accessor :fail
def description
"be a fake matcher"
end
def matches?(subject)
@subject = subject
!@fail
end
def failure_message
"positive failure message"
end
def failure_message_when_negated
"negative failure message"
end
end
should "fail" do
assert false
end
should_not FakeMatcher.new.tap { |m| m.fail = false }
should FakeMatcher.new.tap { |m| m.fail = true }
end
RUBY

command_runner = app.run_n_unit_test_suite

expected_file_path_with_line_number =
if rails_version >= 6
"rails test test/models/failing_test.rb:5"
else
"bin/rails test test/models/failing_test.rb:5"
end
expected_executable = rails_version >= 6 ? "rails test" : "bin/rails test"

assert_includes(
command_runner.output,
expected_file_path_with_line_number
)
assert_includes(command_runner.output, "#{expected_executable} test/models/failing_test.rb:27")
assert_includes(command_runner.output, "#{expected_executable} test/models/failing_test.rb:31")
assert_includes(command_runner.output, "#{expected_executable} test/models/failing_test.rb:32")
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/shoulda/should_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def test_should_create_a_new_context_and_build_it_on_test_case_context

def test_should_create_a_one_off_context_and_build_it_on_test_case_should
s = mock("test")
Shoulda::Context::Context.any_instance.expects(:should).with("rock", {}).returns(s)
Shoulda::Context::Context.any_instance.expects(:should).with("rock", {}, [__FILE__, __LINE__ + 2]).returns(s)
Shoulda::Context::Context.any_instance.expects(:build)
self.class.should "rock" do; end
end
Expand Down

0 comments on commit 098f0e3

Please sign in to comment.