Initial work on assertions

This commit is contained in:
Michael Miller 2021-01-09 19:50:32 -07:00
parent 122395837f
commit 096c31d7f5
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
7 changed files with 263 additions and 226 deletions

View file

@ -0,0 +1,15 @@
require "./block"
require "./expression"
module Spectator
class Assertion
struct Target(T)
@expression : Expression(T) | Block(T)
@source : Source?
def initialize(@expression : Expression(T) | Block(T), @source)
puts "TARGET: #{@expression} @ #{@source}"
end
end
end
end

View file

@ -0,0 +1,15 @@
require "./source"
module Spectator
# Exception that indicates an assertion failed.
# When raised within a test, the test should abort.
class AssertionFailed < Exception
# Location where the assertion failed and the exception raised.
getter source : Source
# Creates the exception.
def initialize(@source : Source, message : String? = nil, cause : Exception? = nil)
super(message, cause)
end
end
end

View file

@ -1,4 +1,5 @@
# require "./dsl/*"
require "./dsl/assertions"
require "./dsl/builder"
require "./dsl/examples"
require "./dsl/groups"

View file

@ -1,10 +1,36 @@
require "../expectations/expectation_partial"
require "../assertion"
require "../assertion_failed"
require "../expression"
require "../source"
require "../test_block"
require "../test_value"
module Spectator
module DSL
module Spectator::DSL
# Methods and macros for asserting that conditions are met.
module Assertions
# Checks that the specified condition is true.
# Raises `AssertionFailed` if *condition* is false.
# The *message* is passed to the exception.
def assert(condition, message, *, _file = __FILE__, _line = __LINE__)
raise AssertionFailed.new(Source.new(_file, _line), message) unless condition
end
# Checks that the specified condition is true.
# Raises `AssertionFailed` if *condition* is false.
# The message of the exception is the *condition*.
macro assert(condition)
assert({{condition}}, {{condition.stringify}}, _file: {{condition.filename}}, _line: {{condition.line_number}})
end
macro expect(actual)
%actual = begin
{{actual}}
end
%expression = ::Spectator::Expression.new(%actual, {{actual.stringify}})
%source = ::Spectator::Source.new({{actual.filename}}, {{actual.line_number}})
::Spectator::Assertion::Target.new(%expression, %source)
end
end
# Starts an expectation.
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
# or `Spectator::Expectations::ExpectationPartial#to_not`.
@ -212,5 +238,4 @@ module Spectator
def fail
fail("Example failed")
end
end
end

View file

@ -1,5 +0,0 @@
module Spectator
# Exception that indicates an example failed and should abort.
class ExampleFailed < Exception
end
end

View file

@ -1,15 +0,0 @@
require "./example_failed"
module Spectator
# Exception that indicates a required expectation was not met in an example.
class ExpectationFailed < ExampleFailed
# Expectation that failed.
getter expectation : Expectations::Expectation
# Creates the exception.
# The exception string is generated from the expecation message.
def initialize(@expectation)
super(@expectation.failure_message)
end
end
end

View file

@ -6,6 +6,7 @@ require "./dsl"
# This type is intentionally outside the `Spectator` module.
# The reason for this is to prevent name collision when using the DSL to define a spec.
class SpectatorTestContext < SpectatorContext
include ::Spectator::DSL::Assertions
include ::Spectator::DSL::Examples
include ::Spectator::DSL::Groups
include ::Spectator::DSL::Hooks