Merge branch 'specs'

This commit is contained in:
Michael Miller 2020-01-19 09:52:41 -07:00
commit 64f6456935
18 changed files with 248 additions and 152 deletions

View file

@ -11,10 +11,9 @@ Spectator.describe "`all` matcher" do
it { is_expected.to all(be < 10) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to all(be_even) }
xit { is_expected.to all(be_a(String)) }
xit { is_expected.to all(be > 2) }
it_fails { is_expected.to all(be_even) }
it_fails { is_expected.to all(be_a(String)) }
it_fails { is_expected.to all(be > 2) }
end
end
@ -29,7 +28,6 @@ Spectator.describe "`all` matcher" do
xit { is_expected.to all(start_with("s")) } # .or contain("y") ) }
# deliberate failures
# TODO: Add support for expected failures.
# TODO: Add support for compound matchers.
xit { is_expected.to all(contain("foo")) } # .and contain("bar") ) }
xit { is_expected.to all(be_a(String)) } # .and start_with("a") ) }

View file

@ -12,12 +12,11 @@ Spectator.describe "`be` matchers" do
specify { expect(false).not_to be_truthy }
# deliberate failures
# TODO: Add support for expected failures.
pending { expect(true).not_to be_truthy }
pending { expect(7).not_to be_truthy }
pending { expect("foo").not_to be_truthy }
pending { expect(nil).to be_truthy }
pending { expect(false).to be_truthy }
specify_fails { expect(true).not_to be_truthy }
specify_fails { expect(7).not_to be_truthy }
specify_fails { expect("foo").not_to be_truthy }
specify_fails { expect(nil).to be_truthy }
specify_fails { expect(false).to be_truthy }
end
context "be_falsey matcher" do
@ -28,12 +27,11 @@ Spectator.describe "`be` matchers" do
specify { expect("foo").not_to be_falsey }
# deliberate failures
# TODO: Add support for expected failures.
pending { expect(nil).not_to be_falsey }
pending { expect(false).not_to be_falsey }
pending { expect(true).to be_falsey }
pending { expect(7).to be_falsey }
pending { expect("foo").to be_falsey }
specify_fails { expect(nil).not_to be_falsey }
specify_fails { expect(false).not_to be_falsey }
specify_fails { expect(true).to be_falsey }
specify_fails { expect(7).to be_falsey }
specify_fails { expect("foo").to be_falsey }
end
context "be_nil matcher" do
@ -44,12 +42,11 @@ Spectator.describe "`be` matchers" do
specify { expect("foo").not_to be_nil }
# deliberate failures
# TODO: Add support for expected failures.
pending { expect(nil).not_to be_nil }
pending { expect(false).to be_nil }
pending { expect(true).to be_nil }
pending { expect(7).to be_nil }
pending { expect("foo").to be_nil }
specify_fails { expect(nil).not_to be_nil }
specify_fails { expect(false).to be_nil }
specify_fails { expect(true).to be_nil }
specify_fails { expect(7).to be_nil }
specify_fails { expect("foo").to be_nil }
end
context "be matcher" do
@ -60,11 +57,10 @@ Spectator.describe "`be` matchers" do
specify { expect(false).not_to be }
# deliberate failures
# TODO: Add support for expected failures.
pending { expect(true).not_to be }
pending { expect(7).not_to be }
pending { expect("foo").not_to be }
pending { expect(nil).to be }
pending { expect(false).to be }
specify_fails { expect(true).not_to be }
specify_fails { expect(7).not_to be }
specify_fails { expect("foo").not_to be }
specify_fails { expect(nil).to be }
specify_fails { expect(false).to be }
end
end

View file

@ -15,11 +15,10 @@ Spectator.describe "`be_within` matcher" do
it { is_expected.not_to be_within(0.5).of(26.9) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to be_within(0.5).of(28) }
xit { is_expected.not_to be_within(0.5).of(27) }
xit { is_expected.to be_within(0.5).of(28.1) }
xit { is_expected.to be_within(0.5).of(26.9) }
it_fails { is_expected.not_to be_within(0.5).of(28) }
it_fails { is_expected.not_to be_within(0.5).of(27) }
it_fails { is_expected.to be_within(0.5).of(28.1) }
it_fails { is_expected.to be_within(0.5).of(26.9) }
end
end
end

View file

@ -26,8 +26,7 @@ Spectator.describe "`change` matcher" do
end
# deliberate failure
# TODO: Add support for expected failures.
xit "should increment the count by 2" do
it_fails "should increment the count by 2" do
expect { Counter.increment }.to change { Counter.count }.by(2)
end
end
@ -36,12 +35,11 @@ Spectator.describe "`change` matcher" do
context "expect no change" do
describe "Counter#increment" do # TODO: Allow multiple arguments to context/describe.
# deliberate failures
# TODO: Add support for expected failures.
xit "should not increment the count by 1 (using not_to)" do
it_fails "should not increment the count by 1 (using not_to)" do
expect { Counter.increment }.not_to change { Counter.count }
end
xit "should not increment the count by 1 (using to_not)" do
it_fails "should not increment the count by 1 (using to_not)" do
expect { Counter.increment }.to_not change { Counter.count }
end
end

View file

@ -12,11 +12,10 @@ Spectator.describe "Comparison matchers" do
it { is_expected.to be >= 17 }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to be < 15 }
xit { is_expected.to be > 20 }
xit { is_expected.to be <= 17 }
xit { is_expected.to be >= 19 }
it_fails { is_expected.to be < 15 }
it_fails { is_expected.to be > 20 }
it_fails { is_expected.to be <= 17 }
it_fails { is_expected.to be >= 19 }
# it { is_expected.to be < 'a' } # Removed because Crystal doesn't support Int32#<(Char)
end
@ -24,7 +23,6 @@ Spectator.describe "Comparison matchers" do
it { is_expected.to be < 'b' }
# deliberate failures
# TODO: Add support for expected failures.
# it { is_expected.to be < 18 } # Removed because Crystal doesn't support Char#<(Int32)
end
end
@ -37,11 +35,10 @@ Spectator.describe "Comparison matchers" do
it { is_expected.to be >= "Banana" }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to be < "Cranberry" }
xit { is_expected.to be > "Zuchini" }
xit { is_expected.to be <= "Potato" }
xit { is_expected.to be >= "Tomato" }
it_fails { is_expected.to be < "Cranberry" }
it_fails { is_expected.to be > "Zuchini" }
it_fails { is_expected.to be <= "Potato" }
it_fails { is_expected.to be >= "Tomato" }
end
end
end

View file

@ -14,8 +14,7 @@ Spectator.describe "`contain_exactly` matcher" do
it { is_expected.to contain_exactly(3, 2, 1) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to contain_exactly(1, 2, 1) }
it_fails { is_expected.to contain_exactly(1, 2, 1) }
end
end
@ -25,8 +24,7 @@ Spectator.describe "`contain_exactly` matcher" do
it { is_expected.to_not contain_exactly(1, 2) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to_not contain_exactly(1, 3, 2) }
it_fails { is_expected.to_not contain_exactly(1, 3, 2) }
end
end
end

View file

@ -27,17 +27,16 @@ Spectator.describe "`contain` matcher" do
it { is_expected.not_to contain(43, 100) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to contain(4) }
xit { is_expected.to contain(be_even) }
xit { is_expected.not_to contain(1) }
xit { is_expected.not_to contain(3) }
xit { is_expected.not_to contain(7) }
xit { is_expected.not_to contain(1, 3, 7) }
it_fails { is_expected.to contain(4) }
it_fails { is_expected.to contain(be_even) }
it_fails { is_expected.not_to contain(1) }
it_fails { is_expected.not_to contain(3) }
it_fails { is_expected.not_to contain(7) }
it_fails { is_expected.not_to contain(1, 3, 7) }
# both of these should fail since it contains 1 but not 9
xit { is_expected.to contain(1, 9) }
xit { is_expected.not_to contain(1, 9) }
it_fails { is_expected.to contain(1, 9) }
it_fails { is_expected.not_to contain(1, 9) }
end
end
@ -49,11 +48,10 @@ Spectator.describe "`contain` matcher" do
it { is_expected.not_to contain("foo", "bar") }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to contain("foo") }
xit { is_expected.not_to contain("str") }
xit { is_expected.to contain("str", "foo") }
xit { is_expected.not_to contain("str", "foo") }
it_fails { is_expected.to contain("foo") }
it_fails { is_expected.not_to contain("str") }
it_fails { is_expected.to contain("str", "foo") }
it_fails { is_expected.not_to contain("str", "foo") }
end
end
@ -64,34 +62,33 @@ Spectator.describe "`contain` matcher" do
subject { {:a => 7, :b => 5} }
# Hash syntax is changed here from `:a => 7` to `a: 7`.
xit { is_expected.to contain(:a) }
xit { is_expected.to contain(:b, :a) }
# it { is_expected.to contain(:a) }
# it { is_expected.to contain(:b, :a) }
# TODO: This hash-like syntax isn't supported.
# it { is_expected.to contain(a: 7) }
# it { is_expected.to contain(b: 5, a: 7) }
xit { is_expected.not_to contain(:c) }
xit { is_expected.not_to contain(:c, :d) }
# it { is_expected.not_to contain(:c) }
# it { is_expected.not_to contain(:c, :d) }
# it { is_expected.not_to contain(d: 2) }
# it { is_expected.not_to contain(a: 5) }
# it { is_expected.not_to contain(b: 7, a: 5) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to contain(:a) }
xit { is_expected.not_to contain(:b, :a) }
# it { is_expected.not_to contain(:a) }
# it { is_expected.not_to contain(:b, :a) }
# it { is_expected.not_to contain(a: 7) }
# it { is_expected.not_to contain(a: 7, b: 5) }
xit { is_expected.to contain(:c) }
xit { is_expected.to contain(:c, :d) }
# it { is_expected.to contain(:c) }
# it { is_expected.to contain(:c, :d) }
# it { is_expected.to contain(d: 2) }
# it { is_expected.to contain(a: 5) }
# it { is_expected.to contain(a: 5, b: 7) }
# Mixed cases--the hash contains one but not the other.
# All 4 of these cases should fail.
xit { is_expected.to contain(:a, :d) }
xit { is_expected.not_to contain(:a, :d) }
# it { is_expected.to contain(:a, :d) }
# it { is_expected.not_to contain(:a, :d) }
# it { is_expected.to contain(a: 7, d: 3) }
# it { is_expected.not_to contain(a: 7, d: 3) }
end

View file

@ -15,16 +15,15 @@ Spectator.describe "`cover` matcher" do
it { is_expected.not_to cover(11, 12) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to cover(11) }
xit { is_expected.not_to cover(4) }
xit { is_expected.not_to cover(6) }
xit { is_expected.not_to cover(8) }
xit { is_expected.not_to cover(4, 6, 8) }
it_fails { is_expected.to cover(11) }
it_fails { is_expected.not_to cover(4) }
it_fails { is_expected.not_to cover(6) }
it_fails { is_expected.not_to cover(8) }
it_fails { is_expected.not_to cover(4, 6, 8) }
# both of these should fail since it covers 5 but not 11
xit { is_expected.to cover(5, 11) }
xit { is_expected.not_to cover(5, 11) }
it_fails { is_expected.to cover(5, 11) }
it_fails { is_expected.not_to cover(5, 11) }
end
end
end

View file

@ -10,9 +10,8 @@ Spectator.describe "`end_with` matcher" do
it { is_expected.not_to end_with "stringy" }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to end_with "string" }
xit { is_expected.to end_with "stringy" }
it_fails { is_expected.not_to end_with "string" }
it_fails { is_expected.to end_with "stringy" }
end
end
@ -25,9 +24,8 @@ Spectator.describe "`end_with` matcher" do
# it { is_expected.not_to end_with 0, 1, 2, 3, 4, 5 }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to end_with 4 }
xit { is_expected.to end_with 3 }
it_fails { is_expected.not_to end_with 4 }
it_fails { is_expected.to end_with 3 }
end
end
end

View file

@ -24,14 +24,13 @@ Spectator.describe "`have_attributes` matcher" do
# it { is_expected.not_to have_attributes(age: (a_value < 30) ) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.to have_attributes(name: "Bob") }
xit { is_expected.to have_attributes(name: 10) }
it_fails { is_expected.to have_attributes(name: "Bob") }
it_fails { is_expected.to have_attributes(name: 10) }
# fails if any of the attributes don't match
xit { is_expected.to have_attributes(name: "Bob", age: 32) }
xit { is_expected.to have_attributes(name: "Jim", age: 10) }
xit { is_expected.to have_attributes(name: "Bob", age: 10) }
it_fails { is_expected.to have_attributes(name: "Bob", age: 32) }
it_fails { is_expected.to have_attributes(name: "Jim", age: 10) }
it_fails { is_expected.to have_attributes(name: "Bob", age: 10) }
end
end
end

View file

@ -10,9 +10,8 @@ Spectator.describe "`match` matcher" do
it { is_expected.not_to match(/foo/) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to match(/str/) }
xit { is_expected.to match(/foo/) }
it_fails { is_expected.not_to match(/str/) }
it_fails { is_expected.to match(/foo/) }
end
end
@ -22,9 +21,8 @@ Spectator.describe "`match` matcher" do
it { is_expected.not_to match("drinks") }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to match("food") }
xit { is_expected.to match("drinks") }
it_fails { is_expected.not_to match("food") }
it_fails { is_expected.to match("drinks") }
end
end
end

View file

@ -11,8 +11,7 @@ Spectator.describe "Predicate matchers" do
describe 7 do
# deliberate failure
# TODO: Add support for expected failures.
xit { is_expected.to be_zero }
it_fails { is_expected.to be_zero }
end
end
@ -23,8 +22,7 @@ Spectator.describe "Predicate matchers" do
describe [] of Int32 do
# deliberate failure
# TODO: Add support for expected failures.
xit { is_expected.not_to be_empty }
it_fails { is_expected.not_to be_empty }
end
end
@ -35,8 +33,7 @@ Spectator.describe "Predicate matchers" do
it { is_expected.to have_key(:foo) }
# deliberate failure
# TODO: Add support for expected failures.
xit { is_expected.to have_key(:bar) }
it_fails { is_expected.to have_key(:bar) }
end
end
@ -58,8 +55,7 @@ Spectator.describe "Predicate matchers" do
subject { {"foo" => 7, "bar" => 5} }
# deliberate failure
# TODO: Add support for expected failures.
xit { is_expected.not_to have_all_string_keys }
it_fails { is_expected.not_to have_all_string_keys }
end
end
end
@ -76,9 +72,8 @@ Spectator.describe "Predicate matchers" do
it { is_expected.not_to be_multiple_of(7) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to be_multiple_of(4) }
xit { is_expected.to be_multiple_of(5) }
it_fails { is_expected.not_to be_multiple_of(4) }
it_fails { is_expected.to be_multiple_of(5) }
end
end

View file

@ -0,0 +1,94 @@
require "../../spec_helper"
# Examples taken from:
# https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/raise-error-matcher
# and modified to fit Spectator and Crystal.
Spectator.describe "`raise_error` matcher" do
context "expect any error" do
# This example originally calls a non-existent method.
# That isn't allowed in Crystal.
# The example has been changed to just raise a runtime error.
describe "dividing by zero" do
it "raises" do
expect { 42 // 0 }.to raise_error
end
end
end
context "expect specific error" do
# Again, can't even compile if a method doesn't exist.
# So using a different exception here.
describe "dividing by zero" do
it "raises" do
expect { 42 // 0 }.to raise_error(DivisionByZeroError)
end
end
end
# The following examples are changed slightly.
# `raise Type.new(message)` is the syntax in Crystal,
# whereas it is `raise Type, message` in Ruby.
# Additionally, `StandardError` doesn't exist in Crystal,
# so `Exception` is used instead.
context "match message with a string" do
describe "matching error message with string" do
it "matches the error message" do
expect { raise Exception.new("this message exactly") }
.to raise_error("this message exactly")
end
end
end
context "match message with a regexp" do
describe "matching error message with regex" do
it "matches the error message" do
expect { raise Exception.new("my message") }
.to raise_error(/my mess/)
end
end
end
context "matching message with `with_message`" do
describe "matching error message with regex" do
it "matches the error message" do
expect { raise Exception.new("my message") }
.to raise_error.with_message(/my mess/)
end
end
end
context "match class + message with string" do
describe "matching error message with string" do
it "matches the error message" do
expect { raise Exception.new("this message exactly") }
.to raise_error(Exception, "this message exactly")
end
end
end
context "match class + message with regexp" do
describe "matching error message with regex" do
it "matches the error message" do
expect { raise Exception.new("my message") }
.to raise_error(Exception, /my mess/)
end
end
end
# TODO: Support passing a block to `raise_error` matcher.
# context "set expectations on error object passed to block" do
# it "raises DivisionByZeroError" do
# expect { 42 // 0 }.to raise_error do |error|
# expect(error).to be_a(DivisionByZeroError)
# end
# end
# end
context "expect no error at all" do
describe "#to_s" do
it "does not raise" do
expect { 42.to_s }.not_to raise_error
end
end
end
end

View file

@ -0,0 +1,28 @@
require "../../spec_helper"
# Examples taken from:
# https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/respond-to-matcher
# and modified to fit Spectator and Crystal.
Spectator.describe "`respond_to` matcher" do
context "basic usage" do
describe "a string" do
it { is_expected.to respond_to(:size) } # It's size in Crystal, not length.
it { is_expected.to respond_to(:hash, :class, :to_s) }
it { is_expected.not_to respond_to(:to_model) }
it { is_expected.not_to respond_to(:compact, :flatten) }
# deliberate failures
it_fails { is_expected.to respond_to(:to_model) }
it_fails { is_expected.to respond_to(:compact, :flatten) }
it_fails { is_expected.not_to respond_to(:size) }
it_fails { is_expected.not_to respond_to(:hash, :class, :to_s) }
# mixed examples--String responds to :length but not :flatten
# both specs should fail
it_fails { is_expected.to respond_to(:size, :flatten) }
it_fails { is_expected.not_to respond_to(:size, :flatten) }
end
end
# Spectator doesn't support argument matching with respond_to.
end

View file

@ -10,9 +10,8 @@ Spectator.describe "`start_with` matcher" do
it { is_expected.not_to start_with "that" }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to start_with "this" }
xit { is_expected.to start_with "that" }
it_fails { is_expected.not_to start_with "this" }
it_fails { is_expected.to start_with "that" }
end
end
@ -25,9 +24,8 @@ Spectator.describe "`start_with` matcher" do
# it { is_expected.not_to start_with(0, 1, 2, 3, 4, 5) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to start_with 0 }
xit { is_expected.to start_with 3 }
it_fails { is_expected.not_to start_with 0 }
it_fails { is_expected.to start_with 3 }
end
end
end

View file

@ -40,19 +40,18 @@ Spectator.describe "Type matchers" do
it { is_expected.not_to be_a(String) }
# deliberate failures
# TODO: Add support for expected failures.
xit { is_expected.not_to be_kind_of(Derived) }
xit { is_expected.not_to be_a_kind_of(Derived) }
xit { is_expected.not_to be_a(Derived) }
xit { is_expected.not_to be_kind_of(Base) }
xit { is_expected.not_to be_a_kind_of(Base) }
xit { is_expected.not_to be_an(Base) }
xit { is_expected.not_to be_kind_of(MyModule) }
xit { is_expected.not_to be_a_kind_of(MyModule) }
xit { is_expected.not_to be_a(MyModule) }
xit { is_expected.to be_kind_of(String) }
xit { is_expected.to be_a_kind_of(String) }
xit { is_expected.to be_a(String) }
it_fails { is_expected.not_to be_kind_of(Derived) }
it_fails { is_expected.not_to be_a_kind_of(Derived) }
it_fails { is_expected.not_to be_a(Derived) }
it_fails { is_expected.not_to be_kind_of(Base) }
it_fails { is_expected.not_to be_a_kind_of(Base) }
it_fails { is_expected.not_to be_an(Base) }
it_fails { is_expected.not_to be_kind_of(MyModule) }
it_fails { is_expected.not_to be_a_kind_of(MyModule) }
it_fails { is_expected.not_to be_a(MyModule) }
it_fails { is_expected.to be_kind_of(String) }
it_fails { is_expected.to be_a_kind_of(String) }
it_fails { is_expected.to be_a(String) }
end
context "be_(an_)instance_of matcher" do
@ -87,14 +86,14 @@ Spectator.describe "Type matchers" do
it { is_expected.not_to be_an_instance_of(String) }
# deliberate failures
xit { is_expected.not_to be_instance_of(Derived) }
xit { is_expected.not_to be_an_instance_of(Derived) }
xit { is_expected.to be_instance_of(Base) }
xit { is_expected.to be_an_instance_of(Base) }
xit { is_expected.to be_instance_of(MyModule) }
xit { is_expected.to be_an_instance_of(MyModule) }
xit { is_expected.to be_instance_of(String) }
xit { is_expected.to be_an_instance_of(String) }
it_fails { is_expected.not_to be_instance_of(Derived) }
it_fails { is_expected.not_to be_an_instance_of(Derived) }
it_fails { is_expected.to be_instance_of(Base) }
it_fails { is_expected.to be_an_instance_of(Base) }
it_fails { is_expected.to be_instance_of(MyModule) }
it_fails { is_expected.to be_an_instance_of(MyModule) }
it_fails { is_expected.to be_instance_of(String) }
it_fails { is_expected.to be_an_instance_of(String) }
end
end
end

View file

@ -1 +1,13 @@
require "../src/spectator"
macro it_fails(description = nil, &block)
it {{description}} do
expect do
{{block.body}}
end.to raise_error(Spectator::ExampleFailed)
end
end
macro specify_fails(description = nil, &block)
it_fails {{description}} {{block}}
end

View file

@ -16,7 +16,7 @@ module Spectator::Matchers
# Actually performs the test against the expression.
def match(actual : TestExpression(T)) : MatchData forall T
snapshot = snapshot_values(actual.value)
if match?(snapshot)
if snapshot.values.all?
SuccessfulMatchData.new(description)
else
FailedMatchData.new(description, "#{actual.label} does not respond to #{label}", **values(snapshot))
@ -27,7 +27,7 @@ module Spectator::Matchers
# A successful match with `#match` should normally fail for this method, and vice-versa.
def negated_match(actual : TestExpression(T)) : MatchData forall T
snapshot = snapshot_values(actual.value)
if match?(snapshot)
if snapshot.values.any?
FailedMatchData.new(description, "#{actual.label} responds to #{label}", **values(snapshot))
else
SuccessfulMatchData.new(description)
@ -46,13 +46,6 @@ module Spectator::Matchers
{% end %}
end
# Checks if all results from the snapshot are satisified.
private def match?(snapshot)
# The snapshot did the hard work.
# Here just check if all values are true.
snapshot.values.all?
end
# Produces the tuple for the failed match data from a snapshot of the results.
private def values(snapshot)
{% begin %}