Skip to content

Commit

Permalink
Better error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldrapper committed Dec 17, 2024
1 parent 7c6e422 commit bcdfafc
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 32 deletions.
40 changes: 26 additions & 14 deletions lib/quickdraw/assertions.rb
Original file line number Diff line number Diff line change
@@ -1,50 +1,62 @@
# frozen_string_literal: true

module Quickdraw::Assertions
def assert_equal(expected, actual)
assert(expected == actual) do
def assert_equal(expected, actual, depth: 0)
depth += 1

assert(expected == actual, depth:) do
"expected #{expected.inspect} to == #{actual.inspect}"
end
end

def refute_equal(expected, actual)
def refute_equal(expected, actual, depth: 0)
depth += 1

refute(expected == actual) do
"expected #{expected.inspect} to not == #{actual.inspect}"
end
end

def assert_raises(expected)
def assert_raises(expected, depth: 0)
depth += 1
yield
failure! { "expected block to raise #{expected.inspect} but nothing was raised" }
failure!(depth:) { "expected block to raise #{expected.inspect} but nothing was raised" }
rescue Exception => error
assert(expected === error) do
assert(expected === error, depth:) do
"expected block to raise #{expected.inspect} but #{error.class.inspect} was raised instead"
end

error
end

def refute_raises
def refute_raises(depth: 0)
depth += 1
yield
success!
rescue Exception => error
failure! { "expected block not to raise, but #{error.class.inspect} was raised" }
failure!(depth:) { "expected block not to raise, but #{error.class.inspect} was raised" }
end

def assert_operator(object, operator, other)
assert object.public_send(operator, other) do
def assert_operator(object, operator, other, depth: 0)
depth += 1

assert object.public_send(operator, other), depth: do
"expected #{object.inspect} to #{operator} #{other.inspect}"
end
end

def assert_same(expected, actual)
assert expected.equal?(actual) do
def assert_same(expected, actual, depth: 0)
depth += 1

assert expected.equal?(actual), depth: do
"expected #{expected.inspect} to be the same object as #{actual.inspect}"
end
end

def refute_same(expected, actual)
refute expected.equal?(actual) do
def refute_same(expected, actual, depth: 0)
depth += 1

refute expected.equal?(actual), depth: do
"expected #{expected.inspect} not to be the same object as #{actual.inspect}"
end
end
Expand Down
38 changes: 34 additions & 4 deletions lib/quickdraw/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def initialize(processes:, threads:, files:, seed:)

@cluster = Quickdraw::Cluster.new
@batch = nil

@failures = Quickdraw::ConcurrentArray.new
@errors = Quickdraw::ConcurrentArray.new
@successes = Quickdraw::ConcurrentInteger.new
end

Expand All @@ -41,16 +43,38 @@ def call
end
end

puts

@errors.each do |error|
puts

[
"\e[4m#{error['location'][0]}:#{error['location'][1]}\e[0m",
"\e[1m#{(error['description'])}\e[0m",
"\e[3munexpected \e[1m#{error['name']}\e[0m",
error["message"],
*error["backtrace"].map { |it| it.gsub(":in `", " in `") },
].each_with_index do |line, i|
puts "#{' ' * i}#{line}"
end
end

@failures.each do |failure|
puts "#{failure['location'][0]}:#{failure['location'][1]}"
puts " #{failure['description']}"
puts " #{failure['message']}"
puts

[
"\e[4m#{failure['location'][0]}:#{failure['location'][1]}\e[0m",
"\e[1m#{(failure['description'])}\e[0m",
"\e[3m#{(failure['message'])}\e[0m",
failure["caller_locations"][failure["depth"]].gsub(":in `", " in `"),
].each_with_index do |line, i|
puts "#{' ' * i}#{line}"
end
end

puts

puts "Passed: #{@successes.value} | Failed: #{@failures.size}"
puts "Passed: #{@successes.value} | Failed: #{@failures.size} | Errors: #{@errors.size}"

exit(1) if @failures.any?
end
Expand Down Expand Up @@ -98,6 +122,10 @@ def failure!(failure)
@failures << failure
end

def error!(error)
@errors << error
end

private

def work(socket)
Expand Down Expand Up @@ -131,6 +159,7 @@ def work(socket)
threads.each(&:join)
socket.write Message::Stopping
socket.write JSON.generate({
errors: @errors.to_a,
failures: @failures.to_a,
successes: @successes.value,
})
Expand Down Expand Up @@ -189,6 +218,7 @@ def supervise(worker)
when Message::Stopping
results = JSON.parse(socket.read)
@failures.concat(results["failures"])
@errors.concat(results["errors"])
@successes.increment(results["successes"])
else
raise "Unhandled message: #{message}"
Expand Down
20 changes: 16 additions & 4 deletions lib/quickdraw/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ def run(runner)
setup
around_test { instance_exec(&@block) }
teardown
rescue Exception => error
@runner.error!({
location: @block.source_location,
description: @description,
message: error.message,
name: error.class.name,
detailed_message: error.detailed_message,
backtrace: error.backtrace,
})
end

def match
Expand All @@ -28,13 +37,15 @@ def match
failure! { e.message }
end

def assert(value)
def assert(value, depth: 0)
depth += 1

if value
success!
elsif block_given?
failure! { yield(value) }
failure!(depth:) { yield(value) }
else
failure! { "expected #{value.inspect} to be truthy" }
failure!(depth:) { "expected #{value.inspect} to be truthy" }
end

nil
Expand Down Expand Up @@ -64,7 +75,7 @@ def success!
end

# Indicate that an assertion failed.
def failure!(&)
def failure!(depth: 0, &)
if @skip
@runner.success!(@description)
else
Expand All @@ -73,6 +84,7 @@ def failure!(&)
description: @description,
message: yield,
caller_locations:,
depth:,
})
end

Expand Down
14 changes: 4 additions & 10 deletions test/assertions.test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def success!(description)
end
end

test "the truth" do
assert_equal "Hello", "Joel"
end

test "assert_equal" do
assert_equal 1, 1
end
Expand All @@ -40,16 +44,6 @@ def success!(description)
end
end

test "assert_respond_to" do
assert_test_passes do
assert_respond_to 1, :even?
end

assert_test_fails do
assert_respond_to 1, :not_a_valid_method
end
end

def assert_test_fails(description = nil, skip: false, &block)
runner = Runner.new

Expand Down

0 comments on commit bcdfafc

Please sign in to comment.