Skip to content

Commit

Permalink
More WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
icy-arctic-fox committed Jun 28, 2024
1 parent 9a3b0e0 commit 5a19f99
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 33 deletions.
21 changes: 7 additions & 14 deletions src/spectator/core/dsl.cr
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
module Spectator
EXAMPLE_ALIASES = [] of Nil

macro def_example_alias(name)
{% EXAMPLE_ALIASES << name %}
module Core::DSL
end

module Core
module DSL
macro finished
{% for example_alias in EXAMPLE_ALIASES %}
macro {{example_alias.id}}(description, &block)
{% verbatim do %}
specify({{description}}) do {% if !block.args.empty? %} |{{block.args.splat}}| {% end %}
{{yield}}
end
{% end %}
macro def_example_alias(name)
module ::Spectator::Core::DSL
macro {{name.id}}(description, &block)
{% verbatim do %}
specify({{description}}) do {% if !block.args.empty? %} |{{block.args.splat}}| {% end %}
{{yield}}
end
{% end %}
end
Expand Down
26 changes: 21 additions & 5 deletions src/spectator/core/example.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ module Spectator::Core
end

# Constructs a string representation of the example.
# The name will be used if it is set, otherwise the example will be anonymous.
# The description will be used if it is set, otherwise the example will be anonymous.
def to_s(io : IO) : Nil
if name = @name
io << name
if description = @description
io << description
else
io << "<Anonymous Example>"
end
end

def inspect(io : IO) : Nil
inspect(io) { }
end

protected def inspect(io : IO, & : IO ->) : Nil
io << "#<" << self.class << ' '
if description = @description
io << '"' << description << '"'
Expand All @@ -49,25 +53,37 @@ module Spectator::Core
end
io << " 0x"
object_id.to_s(io, 16)
yield io
io << '>'
end

def to_proc(&block : Example ->)
Procsy.new(self, &block)
end

def to_proc
Procsy.new(self)
end

struct Procsy
@proc : self ->

def initialize(@example : Example, &@proc : self ->)
end

def initialize(@example : Example)
@proc = ->run
@proc = ->@example.run
end

def run
@example.run
@proc.call(@example)
end

forward_missing_to @example
delegate to_s, to: @example

def inspect(io : IO) : Nil
@example.inspect(io, &.<< " Procsy")
end
end
end
Expand Down
18 changes: 10 additions & 8 deletions src/spectator/core/example_group.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "./context"
require "./example"
require "./item"
require "./location_range"

module Spectator::Core
# Information about a group of examples and functionality for running them.
Expand All @@ -14,15 +15,17 @@ module Spectator::Core
group
end

def context(description, &)
self.class.new(description).tap do |child|
def context(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &)
location = LocationRange.new(file, line, end_line)
self.class.new(description, location).tap do |child|
add_child(child)
with child yield
end
end

def specify(description, &block : Example ->) : Example
example = Example.new(description, &block)
def specify(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block : Example ->) : Example
location = LocationRange.new(file, line, end_line)
example = Example.new(description, location, &block)
add_child(example)
example
end
Expand All @@ -40,11 +43,10 @@ module Spectator::Core
end

def remove_child(child : Item) : Nil
# Don't remove the child if it's not ours.
return unless child.parent? == self

@children.delete(child)
child.parent = nil

# Disassociate the child only if it's ours.
child.parent = nil if child.parent? == self
end

# Constructs a string representation of the group.
Expand Down
28 changes: 22 additions & 6 deletions src/spectator/core/result.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "../assertion_failed"

module Spectator::Core
enum Status
Pass
Expand All @@ -11,20 +13,34 @@ module Spectator::Core
# The status of the example.
getter status : Status

# The time it took to run the example.
getter elapsed : Time::Span

# The exception that caused the example to fail.
# This will be nil if the example passed or was skipped.
getter! exception : Exception

def initialize(@status : Status, @exception = nil)
def initialize(@status : Status, @elapsed : Time::Span, @exception = nil)
end

def self.capture(&) : self
begin
yield
new(:pass)
rescue ex
new(:error, ex)
exception = nil.as(Exception?)
status = Status::Error # Safe default.

elapsed = Time.measure do
begin
yield
status = Status::Pass
rescue ex : AssertionFailed
status = Status::Fail
exception = ex
rescue ex
status = Status::Error
exception = ex
end
end

new(status, elapsed, exception)
end

def pass?
Expand Down

0 comments on commit 5a19f99

Please sign in to comment.