mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Merge remote-tracking branch 'origin/release/0.9' into mocks-and-doubles
This commit is contained in:
commit
8c180e818f
88 changed files with 838 additions and 9229 deletions
|
@ -1,33 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::CompositeExampleFilter do
|
|
||||||
describe "#includes?" do
|
|
||||||
context "with a matching filter" do
|
|
||||||
it "is true" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filters = [Spectator::NullExampleFilter.new.as(Spectator::ExampleFilter)]
|
|
||||||
filter = Spectator::CompositeExampleFilter.new(filters)
|
|
||||||
filter.includes?(example).should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a non-matching filter" do
|
|
||||||
it "is false" do
|
|
||||||
example = PassingExample.create
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
filters = [Spectator::SourceExampleFilter.new(source).as(Spectator::ExampleFilter)]
|
|
||||||
filter = Spectator::CompositeExampleFilter.new(filters)
|
|
||||||
filter.includes?(example).should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with no filters" do
|
|
||||||
it "is false" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filters = [] of Spectator::ExampleFilter
|
|
||||||
filter = Spectator::CompositeExampleFilter.new(filters)
|
|
||||||
filter.includes?(example).should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::DSL::ExampleFactory do
|
|
||||||
describe "#build" do
|
|
||||||
it "creates an example of the correct type" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
example = factory.build(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
example.should be_a(SpyExample)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the group" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
example = factory.build(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
example.group.should eq(group)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the sample values" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
values = Spectator::Internals::SampleValues.empty.add(:foo, "foo", 12345)
|
|
||||||
example = factory.build(group, values)
|
|
||||||
example.as(SpyExample).sample_values.should eq(values)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,234 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::DSL::NestedExampleGroupBuilder do
|
|
||||||
describe "#add_child" do
|
|
||||||
it "creates the correct number of children" do
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("bar")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.size.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleFactory" do
|
|
||||||
it "creates the example" do
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.first.should be_a(PassingExample)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleGroupBuilder" do
|
|
||||||
it "creates the group" do
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("bar")
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.first.should be_a(Spectator::NestedExampleGroup)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_around_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_around_each_hook(->(_proc : ->) {
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
proc = group.wrap_around_each_hooks { }
|
|
||||||
proc.call
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_around_each_hook(->(proc : ->) {
|
|
||||||
call_count += i + 1
|
|
||||||
proc.call
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
proc = group.wrap_around_each_hooks { }
|
|
||||||
proc.call
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#build" do
|
|
||||||
it "passes along the what value" do
|
|
||||||
what = "TEST"
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new(what)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.what.should eq(what)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the parent" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.parent.should be(root)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the sample values" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_child(factory)
|
|
||||||
values = Spectator::Internals::SampleValues.empty.add(:foo, "foo", 12345)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, values)
|
|
||||||
group.children.first.as(SpyExample).sample_values.should eq(values)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "specifies the parent of the children correctly" do
|
|
||||||
builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("bar")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.all? do |child|
|
|
||||||
case (child)
|
|
||||||
when Spectator::Example
|
|
||||||
child.group == group
|
|
||||||
when Spectator::NestedExampleGroup
|
|
||||||
child.parent == group
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,202 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::DSL::RootExampleGroupBuilder do
|
|
||||||
describe "#add_child" do
|
|
||||||
it "creates the correct number of children" do
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.size.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleFactory" do
|
|
||||||
it "creates the example" do
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
builder.add_child(factory)
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.first.should be_a(PassingExample)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleGroupBuilder" do
|
|
||||||
it "creates the group" do
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.first.should be_a(Spectator::NestedExampleGroup)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_around_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_around_each_hook(->(_proc : ->) {
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
proc = group.wrap_around_each_hooks { }
|
|
||||||
proc.call
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_around_each_hook(->(proc : ->) {
|
|
||||||
call_count += i + 1
|
|
||||||
proc.call
|
|
||||||
})
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
proc = group.wrap_around_each_hooks { }
|
|
||||||
proc.call
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#build" do
|
|
||||||
it "passes along the sample values" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
builder.add_child(factory)
|
|
||||||
values = Spectator::Internals::SampleValues.empty.add(:foo, "foo", 12345)
|
|
||||||
group = builder.build(values)
|
|
||||||
group.children.first.as(SpyExample).sample_values.should eq(values)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "specifies the parent of the children correctly" do
|
|
||||||
builder = Spectator::DSL::RootExampleGroupBuilder.new
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("foo")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
group = builder.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.all? do |child|
|
|
||||||
case (child)
|
|
||||||
when Spectator::Example
|
|
||||||
child.group == group
|
|
||||||
when Spectator::NestedExampleGroup
|
|
||||||
child.parent == group
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,350 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
SAMPLE_VALUES_COLLECTION = %i[foo bar baz]
|
|
||||||
|
|
||||||
struct SampleValueCollection
|
|
||||||
def initialize(sample_values : ::Spectator::Internals::SampleValues)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
SAMPLE_VALUES_COLLECTION
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::DSL::SampleExampleGroupBuilder do
|
|
||||||
describe "#add_child" do
|
|
||||||
it "creates the correct number of children" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
count = 4
|
|
||||||
count.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("bar")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.size.should eq(2 * count * SAMPLE_VALUES_COLLECTION.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleFactory" do
|
|
||||||
it "creates an example for each item in the collection" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.all? { |child| child.is_a?(PassingExample) }.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an ExampleGroupBuilder" do
|
|
||||||
it "creates a group for each item in the collection" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("bar")
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.all? { |child| child.is_a?(Spectator::NestedExampleGroup) }.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "attachs the hook to just the top-level group" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
call_count += 1
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.map(&.as(Spectator::ExampleGroup)).each(&.run_before_hooks)
|
|
||||||
call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_before_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "attachs the hook to just the top-level group" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
call_count += 1
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.map(&.as(Spectator::ExampleGroup)).each(&.run_before_hooks)
|
|
||||||
call_count.should eq(SAMPLE_VALUES_COLLECTION.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_before_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_all_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "attachs the hook to just the top-level group" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
call_count += 1
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.map(&.as(Spectator::ExampleGroup)).each(&.run_after_hooks)
|
|
||||||
call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_all_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#add_after_each_hook" do
|
|
||||||
it "adds a hook" do
|
|
||||||
hook_called = false
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
hook_called = true
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
hook_called.should eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "attachs the hook to just the top-level group" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
call_count += 1
|
|
||||||
})
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.map(&.as(Spectator::ExampleGroup)).each(&.run_after_hooks)
|
|
||||||
call_count.should eq(SAMPLE_VALUES_COLLECTION.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "supports multiple hooks" do
|
|
||||||
call_count = 0
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
5.times do |i|
|
|
||||||
builder.add_after_each_hook(->{
|
|
||||||
call_count += i + 1
|
|
||||||
})
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(15)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#build" do
|
|
||||||
it "passes along the what value" do
|
|
||||||
what = "TEST"
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new(what, SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.what.should eq(what)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the parent" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.parent.should be(root)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the sample values" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
builder.add_child(factory)
|
|
||||||
symbol = :test
|
|
||||||
values = Spectator::Internals::SampleValues.empty.add(symbol, "foo", 12345)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, values)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.map(&.as(SpyExample)).all? { |child| child.sample_values.get_wrapper(symbol) }.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes along the value name" do
|
|
||||||
symbol = :foo
|
|
||||||
name = "value"
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, name, symbol)
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.each do |child|
|
|
||||||
entries = child.as(SpyExample).sample_values.map(&.name)
|
|
||||||
entries.should contain(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "creates the correct number of sub-groups" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
builder.add_child(factory)
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.size.should eq(SAMPLE_VALUES_COLLECTION.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes the correct value to each sub-group" do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(SpyExample)
|
|
||||||
symbol = :test
|
|
||||||
count = 3
|
|
||||||
expected = Array.new(SAMPLE_VALUES_COLLECTION.size * count) { |i| SAMPLE_VALUES_COLLECTION[i // count] }
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", symbol)
|
|
||||||
count.times { builder.add_child(factory) }
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
all_children = group.map { |child| child.as(Spectator::ExampleGroup).to_a }.flatten
|
|
||||||
all_children.map { |child| child.as(SpyExample).sample_values.get_value(symbol, typeof(SAMPLE_VALUES_COLLECTION.first)) }.should eq(expected)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "specifies the parent of the children correctly" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("baz")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.all? do |child|
|
|
||||||
case (child)
|
|
||||||
when Spectator::Example
|
|
||||||
child.group == group
|
|
||||||
when Spectator::NestedExampleGroup
|
|
||||||
child.parent == group
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "specifies the container for the parent of the sub-groups" do
|
|
||||||
create_proc = ->(s : SampleValueCollection) { s.create }
|
|
||||||
builder = Spectator::DSL::SampleExampleGroupBuilder.new("foobar", SampleValueCollection, create_proc, "value", :foo)
|
|
||||||
3.times do
|
|
||||||
factory = Spectator::DSL::ExampleFactory.new(PassingExample)
|
|
||||||
group_builder = Spectator::DSL::NestedExampleGroupBuilder.new("baz")
|
|
||||||
builder.add_child(factory)
|
|
||||||
builder.add_child(group_builder)
|
|
||||||
end
|
|
||||||
root = Spectator::DSL::RootExampleGroupBuilder.new.build(Spectator::Internals::SampleValues.empty)
|
|
||||||
group = builder.build(root, Spectator::Internals::SampleValues.empty)
|
|
||||||
group.children.all? do |child|
|
|
||||||
case (child)
|
|
||||||
when Spectator::Example
|
|
||||||
child.group == group
|
|
||||||
when Spectator::NestedExampleGroup
|
|
||||||
child.parent == group
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,87 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_errored_result(
|
|
||||||
example : Spectator::Example? = nil,
|
|
||||||
elapsed : Time::Span? = nil,
|
|
||||||
expectations : Spectator::Expectations::ExampleExpectations? = nil,
|
|
||||||
error : Exception? = nil
|
|
||||||
)
|
|
||||||
Spectator::ErroredResult.new(
|
|
||||||
example || FailingExample.create,
|
|
||||||
elapsed || Time::Span.zero,
|
|
||||||
expectations || Spectator::Expectations::ExampleExpectations.new(generate_expectations(0, 1)[:expectations]),
|
|
||||||
error || Exception.new("foobar")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::ErroredResult do
|
|
||||||
describe "#call" do
|
|
||||||
context "without a block" do
|
|
||||||
it "invokes #error on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_errored_result.call(spy)
|
|
||||||
spy.error?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #failure" do
|
|
||||||
result = new_errored_result
|
|
||||||
returned = result.call(ResultCallSpy.new)
|
|
||||||
returned.should eq(:error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a block" do
|
|
||||||
it "invokes #error on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_errored_result.call(spy) { nil }
|
|
||||||
spy.error?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "yields itself" do
|
|
||||||
result = new_errored_result
|
|
||||||
value = nil.as(Spectator::Result?)
|
|
||||||
result.call(ResultCallSpy.new) { |r| value = r }
|
|
||||||
value.should eq(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #failure" do
|
|
||||||
result = new_errored_result
|
|
||||||
value = 42
|
|
||||||
returned = result.call(ResultCallSpy.new) { value }
|
|
||||||
returned.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example" do
|
|
||||||
it "is the expected value" do
|
|
||||||
example = FailingExample.create
|
|
||||||
result = new_errored_result(example: example)
|
|
||||||
result.example.should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#elapsed" do
|
|
||||||
it "is the expected value" do
|
|
||||||
elapsed = Time::Span.new(10, 10, 10)
|
|
||||||
result = new_errored_result(elapsed: elapsed)
|
|
||||||
result.elapsed.should eq(elapsed)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#expectations" do
|
|
||||||
it "is the expected value" do
|
|
||||||
expectations = Spectator::Expectations::ExampleExpectations.new(generate_expectations(5, 1)[:expectations])
|
|
||||||
result = new_errored_result(expectations: expectations)
|
|
||||||
result.expectations.should eq(expectations)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#error" do
|
|
||||||
it "is the expected value" do
|
|
||||||
error = IO::Error.new("oops")
|
|
||||||
result = new_errored_result(error: error)
|
|
||||||
result.error.should eq(error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,36 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::ExampleConditions do
|
|
||||||
{% for condition in %i[pre post] %}
|
|
||||||
describe "#run_{{condition.id}}_conditions" do
|
|
||||||
it "calls a proc" do
|
|
||||||
called = false
|
|
||||||
conditions = new_conditions({{condition.id}}: ->{ called = true; nil })
|
|
||||||
conditions.run_{{condition.id}}_conditions
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls multiple procs" do
|
|
||||||
call_count = 0
|
|
||||||
conditions = new_conditions({{condition.id}}: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
conditions.run_{{condition.id}}_conditions
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls procs in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
conditions = new_conditions({{condition.id}}: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
])
|
|
||||||
conditions.run_{{condition.id}}_conditions
|
|
||||||
calls.should eq(\%i[a b c])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
end
|
|
|
@ -1,79 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::ExampleHooks do
|
|
||||||
{% for hook in %i[before_all before_each after_all after_each] %}
|
|
||||||
describe "#run_{{hook.id}}" do
|
|
||||||
it "calls a proc" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks({{hook.id}}: ->{ called = true; nil })
|
|
||||||
hooks.run_{{hook.id}}
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls multiple procs" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks({{hook.id}}: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
hooks.run_{{hook.id}}
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls procs in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
hooks = new_hooks({{hook.id}}: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
])
|
|
||||||
hooks.run_{{hook.id}}
|
|
||||||
calls.should eq(\%i[a b c])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
describe "#wrap_around_each" do
|
|
||||||
it "wraps the block" do
|
|
||||||
called = false
|
|
||||||
wrapper = new_hooks.wrap_around_each do
|
|
||||||
called = true
|
|
||||||
end
|
|
||||||
wrapper.call
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps a proc" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(around_each: ->(proc : ->) { called = true; proc.call })
|
|
||||||
wrapper = hooks.wrap_around_each { }
|
|
||||||
wrapper.call
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps multiple procs" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(around_each: [
|
|
||||||
->(proc : ->) { call_count += 1; proc.call },
|
|
||||||
->(proc : ->) { call_count += 2; proc.call },
|
|
||||||
->(proc : ->) { call_count += 3; proc.call },
|
|
||||||
])
|
|
||||||
wrapper = hooks.wrap_around_each { }
|
|
||||||
wrapper.call
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps procs in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
hooks = new_hooks(around_each: [
|
|
||||||
->(proc : ->) { calls << :a; proc.call },
|
|
||||||
->(proc : ->) { calls << :b; proc.call },
|
|
||||||
->(proc : ->) { calls << :c; proc.call },
|
|
||||||
])
|
|
||||||
wrapper = hooks.wrap_around_each { }
|
|
||||||
wrapper.call
|
|
||||||
calls.should eq(%i[a b c])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,205 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::ExampleIterator do
|
|
||||||
describe "#next" do
|
|
||||||
context "with one example" do
|
|
||||||
it "returns the example" do
|
|
||||||
example = PassingExample.create
|
|
||||||
iterator = Spectator::ExampleIterator.new(example.group)
|
|
||||||
iterator.next.should eq(example)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 'stop' after the example" do
|
|
||||||
example = PassingExample.create
|
|
||||||
iterator = Spectator::ExampleIterator.new(example.group)
|
|
||||||
iterator.next # Should return example.
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when empty" do
|
|
||||||
it "returns 'stop'" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = [] of Spectator::ExampleComponent
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with one level of examples" do
|
|
||||||
it "iterates through all examples" do
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
5.times { examples << iterator.next.as(Spectator::Example) }
|
|
||||||
examples.should eq(group.children)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 'stop' at the end" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
5.times { iterator.next }
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with empty sub-groups" do
|
|
||||||
context "one level deep" do
|
|
||||||
it "returns 'stop'" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "multiple levels deep" do
|
|
||||||
it "returns 'stop'" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(5) do |j|
|
|
||||||
Spectator::NestedExampleGroup.new(j.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_sub_group|
|
|
||||||
sub_sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with multiple levels of examples" do
|
|
||||||
it "iterates through all examples" do
|
|
||||||
actual_examples = [] of Spectator::Example
|
|
||||||
expected_examples = [] of Spectator::Example
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
expected_examples << example
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
expected_examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
13.times { actual_examples << iterator.next.as(Spectator::Example) }
|
|
||||||
actual_examples.should eq(expected_examples)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 'stop' at the end" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
13.times { iterator.next }
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with deep nesting" do
|
|
||||||
# Sorry for this atrocity,
|
|
||||||
# but it was fun to write.
|
|
||||||
it "iterates through all examples" do
|
|
||||||
actual_examples = [] of Spectator::Example
|
|
||||||
expected_examples = [] of Spectator::Example
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group1|
|
|
||||||
sub_group1.children = Array(Spectator::ExampleComponent).new(5) do |j|
|
|
||||||
Spectator::NestedExampleGroup.new(j.to_s, sub_group1, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group2|
|
|
||||||
sub_group2.children = Array(Spectator::ExampleComponent).new(5) do |k|
|
|
||||||
Spectator::NestedExampleGroup.new(k.to_s, sub_group2, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group3|
|
|
||||||
sub_group3.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group3, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
expected_examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
(5 ** 4).times { actual_examples << iterator.next.as(Spectator::Example) }
|
|
||||||
actual_examples.should eq(expected_examples)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 'stop' at the end" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group1|
|
|
||||||
sub_group1.children = Array(Spectator::ExampleComponent).new(5) do |j|
|
|
||||||
Spectator::NestedExampleGroup.new(j.to_s, sub_group1, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group2|
|
|
||||||
sub_group2.children = Array(Spectator::ExampleComponent).new(5) do |k|
|
|
||||||
Spectator::NestedExampleGroup.new(k.to_s, sub_group2, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group3|
|
|
||||||
sub_group3.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group3, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
iterator = Spectator::ExampleIterator.new(group)
|
|
||||||
(5 ** 4).times { iterator.next }
|
|
||||||
iterator.next.should be_a(Iterator::Stop)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns 'stop' after the end has been reached" do
|
|
||||||
example = PassingExample.create
|
|
||||||
iterator = Spectator::ExampleIterator.new(example.group)
|
|
||||||
iterator.next # Should return example.
|
|
||||||
iterator.next # Should return "stop".
|
|
||||||
iterator.next.should be_a(Iterator::Stop) # Should still return "stop".
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#rewind" do
|
|
||||||
it "restarts the iterator" do
|
|
||||||
example = PassingExample.create
|
|
||||||
iterator = Spectator::ExampleIterator.new(example.group)
|
|
||||||
iterator.next
|
|
||||||
iterator.rewind
|
|
||||||
iterator.next.should eq(example)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can be called before #next" do
|
|
||||||
example = PassingExample.create
|
|
||||||
iterator = Spectator::ExampleIterator.new(example.group)
|
|
||||||
iterator.rewind
|
|
||||||
iterator.next.should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::ExpectationFailed do
|
|
||||||
describe "#expectation" do
|
|
||||||
it "contains the expected value" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
error = Spectator::ExpectationFailed.new(expectation)
|
|
||||||
error.expectation.should eq(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#message" do
|
|
||||||
it "is the same as the expectation's #actual_message" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
error = Spectator::ExpectationFailed.new(expectation)
|
|
||||||
error.message.should eq(expectation.failure_message)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,207 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Expectations::ExampleExpectations do
|
|
||||||
describe "#each" do
|
|
||||||
it "yields all expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each { |expectation| expectations << expectation }
|
|
||||||
# Expectations might not be in the same order.
|
|
||||||
# Just check if if the arrays contain the same items.
|
|
||||||
expectations.size.should eq(tuple[:expectations].size)
|
|
||||||
(expectations - tuple[:expectations]).empty?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#satisfied" do
|
|
||||||
it "returns only satisfied expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.satisfied.all?(&.satisfied?).should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the correct expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
satisfied = expectations.satisfied.to_a
|
|
||||||
satisfied.size.should eq(5)
|
|
||||||
(satisfied - tuple[:satisfied]).empty?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "returns all expectations" do
|
|
||||||
tuple = generate_expectations(5, 0)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.satisfied.size.should eq(tuple[:satisfied].size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "returns an empty collection" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.satisfied.size.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each_satisfied" do
|
|
||||||
it "yields only satisfied expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_satisfied { |expectation| expectations << expectation }
|
|
||||||
# Expectations might not be in the same order.
|
|
||||||
# Just check if if the arrays contain the same items.
|
|
||||||
expectations.size.should eq(tuple[:satisfied].size)
|
|
||||||
(expectations - tuple[:satisfied]).empty?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "yields all expectations" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_satisfied { |expectation| expectations << expectation }
|
|
||||||
expectations.size.should eq(tuple[:satisfied].size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "yields nothing" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_satisfied { |expectation| expectations << expectation }
|
|
||||||
expectations.empty?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#unsatisfied" do
|
|
||||||
it "returns only unsatisfied expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.unsatisfied.all?(&.satisfied?).should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the correct expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
unsatisfied = expectations.unsatisfied.to_a
|
|
||||||
unsatisfied.size.should eq(5)
|
|
||||||
(unsatisfied - tuple[:unsatisfied]).empty?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "returns an empty collection" do
|
|
||||||
tuple = generate_expectations(5, 0)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.unsatisfied.size.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "returns all expectations" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.unsatisfied.size.should eq(tuple[:unsatisfied].size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each_unsatisfied" do
|
|
||||||
it "yields only unsatisfied expectations" do
|
|
||||||
tuple = generate_expectations(5, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_unsatisfied { |expectation| expectations << expectation }
|
|
||||||
# Expectations might not be in the same order.
|
|
||||||
# Just check if if the arrays contain the same items.
|
|
||||||
expectations.size.should eq(tuple[:unsatisfied].size)
|
|
||||||
(expectations - tuple[:unsatisfied]).empty?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "yields nothing" do
|
|
||||||
tuple = generate_expectations(5, 0)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_unsatisfied { |expectation| expectations << expectation }
|
|
||||||
expectations.empty?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "yields all expectations" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = [] of Spectator::Expectations::Expectation
|
|
||||||
tuple[:reporter].expectations.each_unsatisfied { |expectation| expectations << expectation }
|
|
||||||
expectations.size.should eq(tuple[:unsatisfied].size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#successful?" do
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "is true" do
|
|
||||||
tuple = generate_expectations(5, 0)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.successful?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with one unsatisfied expectation" do
|
|
||||||
it "is false" do
|
|
||||||
tuple = generate_expectations(5, 1)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.successful?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with one satisfied expectation" do
|
|
||||||
it "is false" do
|
|
||||||
tuple = generate_expectations(1, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.successful?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "is false" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.successful?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#failed?" do
|
|
||||||
context "with all satisfied expectations" do
|
|
||||||
it "is false" do
|
|
||||||
tuple = generate_expectations(5, 0)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.failed?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with one unsatisfied expectation" do
|
|
||||||
it "is true" do
|
|
||||||
tuple = generate_expectations(5, 1)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with one satisfied expectation" do
|
|
||||||
it "is true" do
|
|
||||||
tuple = generate_expectations(1, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unsatisfied expectations" do
|
|
||||||
it "is true" do
|
|
||||||
tuple = generate_expectations(0, 5)
|
|
||||||
expectations = tuple[:reporter].expectations
|
|
||||||
expectations.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,80 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Expectations::ExpectationReporter do
|
|
||||||
describe "#report" do
|
|
||||||
context "with raise flag set" do
|
|
||||||
context "given a satisfied expectation" do
|
|
||||||
it "stores the result" do
|
|
||||||
expectation = new_satisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(true)
|
|
||||||
reporter.report(expectation)
|
|
||||||
reporter.expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given a unsatisfied expectation" do
|
|
||||||
it "raises and error" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(true)
|
|
||||||
expect_raises(Spectator::ExpectationFailed) { reporter.report(expectation) }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "stores the expectation" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(true)
|
|
||||||
begin
|
|
||||||
reporter.report(expectation)
|
|
||||||
rescue
|
|
||||||
# Ignore error, not testing that in this example.
|
|
||||||
end
|
|
||||||
reporter.expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with raise flag not set" do
|
|
||||||
context "given a satisfied expectation" do
|
|
||||||
it "stores the expectation" do
|
|
||||||
expectation = new_satisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(false)
|
|
||||||
reporter.report(expectation)
|
|
||||||
reporter.expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given a unsatisfied expectation" do
|
|
||||||
it "stores the expectation" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(false)
|
|
||||||
reporter.report(expectation)
|
|
||||||
reporter.expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#expectations" do
|
|
||||||
context "with no expectations" do
|
|
||||||
it "is empty" do
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new
|
|
||||||
reporter.expectations.size.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with multiple expectations" do
|
|
||||||
it "contains all expectations" do
|
|
||||||
expectation1 = new_satisfied_expectation
|
|
||||||
expectation2 = new_unsatisfied_expectation
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(false)
|
|
||||||
begin
|
|
||||||
reporter.report(expectation1)
|
|
||||||
reporter.report(expectation2)
|
|
||||||
rescue
|
|
||||||
# Ignore errors for this test.
|
|
||||||
end
|
|
||||||
reporter.expectations.should contain(expectation1)
|
|
||||||
reporter.expectations.should contain(expectation2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,51 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Expectations::Expectation do
|
|
||||||
describe "#satisifed?" do
|
|
||||||
context "with a successful match" do
|
|
||||||
it "is true" do
|
|
||||||
value = 42
|
|
||||||
matcher = new_matcher(value)
|
|
||||||
partial = new_partial(value)
|
|
||||||
match_data = matcher.match(partial.actual)
|
|
||||||
match_data.matched?.should be_true # Sanity check.
|
|
||||||
expectation = Spectator::Expectations::Expectation.new(match_data, partial.source)
|
|
||||||
expectation.satisfied?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when negated" do
|
|
||||||
it "is false" do
|
|
||||||
value = 42
|
|
||||||
matcher = new_matcher(value)
|
|
||||||
partial = new_partial(value)
|
|
||||||
match_data = matcher.negated_match(partial.actual)
|
|
||||||
match_data.matched?.should be_false # Sanity check.
|
|
||||||
expectation = Spectator::Expectations::Expectation.new(match_data, partial.source)
|
|
||||||
expectation.satisfied?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with an unsuccessful match" do
|
|
||||||
it "is false" do
|
|
||||||
matcher = new_matcher(42)
|
|
||||||
partial = new_partial(777)
|
|
||||||
match_data = matcher.match(partial.actual)
|
|
||||||
match_data.matched?.should be_false # Sanity check.
|
|
||||||
expectation = Spectator::Expectations::Expectation.new(match_data, partial.source)
|
|
||||||
expectation.satisfied?.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when negated" do
|
|
||||||
it "is true" do
|
|
||||||
matcher = new_matcher(42)
|
|
||||||
partial = new_partial(777)
|
|
||||||
match_data = matcher.negated_match(partial.actual)
|
|
||||||
match_data.matched?.should be_true # Sanity check.
|
|
||||||
expectation = Spectator::Expectations::Expectation.new(match_data, partial.source)
|
|
||||||
expectation.satisfied?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,87 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_failed_result(
|
|
||||||
example : Spectator::Example? = nil,
|
|
||||||
elapsed : Time::Span? = nil,
|
|
||||||
expectations : Spectator::Expectations::ExampleExpectations? = nil,
|
|
||||||
error : Exception? = nil
|
|
||||||
)
|
|
||||||
Spectator::FailedResult.new(
|
|
||||||
example || FailingExample.create,
|
|
||||||
elapsed || Time::Span.zero,
|
|
||||||
expectations || Spectator::Expectations::ExampleExpectations.new(generate_expectations(0, 1)[:expectations]),
|
|
||||||
error || Exception.new("foobar")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::FailedResult do
|
|
||||||
describe "#call" do
|
|
||||||
context "without a block" do
|
|
||||||
it "invokes #failure on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_failed_result.call(spy)
|
|
||||||
spy.failure?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #failure" do
|
|
||||||
result = new_failed_result
|
|
||||||
returned = result.call(ResultCallSpy.new)
|
|
||||||
returned.should eq(:failure)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a block" do
|
|
||||||
it "invokes #failure on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_failed_result.call(spy) { nil }
|
|
||||||
spy.failure?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "yields itself" do
|
|
||||||
result = new_failed_result
|
|
||||||
value = nil.as(Spectator::Result?)
|
|
||||||
result.call(ResultCallSpy.new) { |r| value = r }
|
|
||||||
value.should eq(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #failure" do
|
|
||||||
result = new_failed_result
|
|
||||||
value = 42
|
|
||||||
returned = result.call(ResultCallSpy.new) { value }
|
|
||||||
returned.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example" do
|
|
||||||
it "is the expected value" do
|
|
||||||
example = FailingExample.create
|
|
||||||
result = new_failed_result(example: example)
|
|
||||||
result.example.should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#elapsed" do
|
|
||||||
it "is the expected value" do
|
|
||||||
elapsed = Time::Span.new(10, 10, 10)
|
|
||||||
result = new_failed_result(elapsed: elapsed)
|
|
||||||
result.elapsed.should eq(elapsed)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#expectations" do
|
|
||||||
it "is the expected value" do
|
|
||||||
expectations = Spectator::Expectations::ExampleExpectations.new(generate_expectations(5, 1)[:expectations])
|
|
||||||
result = new_failed_result(expectations: expectations)
|
|
||||||
result.expectations.should eq(expectations)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#error" do
|
|
||||||
it "is the expected value" do
|
|
||||||
error = IO::Error.new("oops")
|
|
||||||
result = new_failed_result(error: error)
|
|
||||||
result.error.should eq(error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,93 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Formatting::Color do
|
|
||||||
describe "#success" do
|
|
||||||
it "includes the input text" do
|
|
||||||
text = "foobar"
|
|
||||||
output = Spectator::Formatting::Color.success(text)
|
|
||||||
output.to_s.should contain(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefixes with green markers" do
|
|
||||||
output = Spectator::Formatting::Color.success("foobar")
|
|
||||||
output.to_s.should start_with("\e[32m")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends color reset markers" do
|
|
||||||
output = Spectator::Formatting::Color.success("foobar")
|
|
||||||
output.to_s.should end_with("\e[0m")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#failure" do
|
|
||||||
it "includes the input text" do
|
|
||||||
text = "foobar"
|
|
||||||
output = Spectator::Formatting::Color.failure(text)
|
|
||||||
output.to_s.should contain(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefixes with green markers" do
|
|
||||||
output = Spectator::Formatting::Color.failure("foobar")
|
|
||||||
output.to_s.should start_with("\e[31m")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends color reset markers" do
|
|
||||||
output = Spectator::Formatting::Color.failure("foobar")
|
|
||||||
output.to_s.should end_with("\e[0m")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#error" do
|
|
||||||
it "includes the input text" do
|
|
||||||
text = "foobar"
|
|
||||||
output = Spectator::Formatting::Color.error(text)
|
|
||||||
output.to_s.should contain(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefixes with green markers" do
|
|
||||||
output = Spectator::Formatting::Color.error("foobar")
|
|
||||||
output.to_s.should start_with("\e[35m")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends color reset markers" do
|
|
||||||
output = Spectator::Formatting::Color.error("foobar")
|
|
||||||
output.to_s.should end_with("\e[0m")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#pending" do
|
|
||||||
it "includes the input text" do
|
|
||||||
text = "foobar"
|
|
||||||
output = Spectator::Formatting::Color.pending(text)
|
|
||||||
output.to_s.should contain(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefixes with green markers" do
|
|
||||||
output = Spectator::Formatting::Color.pending("foobar")
|
|
||||||
output.to_s.should start_with("\e[33m")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends color reset markers" do
|
|
||||||
output = Spectator::Formatting::Color.pending("foobar")
|
|
||||||
output.to_s.should end_with("\e[0m")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#comment" do
|
|
||||||
it "includes the input text" do
|
|
||||||
text = "foobar"
|
|
||||||
output = Spectator::Formatting::Color.comment(text)
|
|
||||||
output.to_s.should contain(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prefixes with green markers" do
|
|
||||||
output = Spectator::Formatting::Color.comment("foobar")
|
|
||||||
output.to_s.should start_with("\e[36m")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "appends color reset markers" do
|
|
||||||
output = Spectator::Formatting::Color.comment("foobar")
|
|
||||||
output.to_s.should end_with("\e[0m")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Example that always raises an exception.
|
|
||||||
class ErroredExample < Spectator::RunnableExample
|
|
||||||
# Dummy description.
|
|
||||||
def what : Symbol | String
|
|
||||||
"ERROR"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy source.
|
|
||||||
def source : ::Spectator::Source
|
|
||||||
::Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy symbolic flag.
|
|
||||||
def symbolic? : Bool
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy instance.
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the example that always produces an error.
|
|
||||||
private def run_instance
|
|
||||||
raise "Oops"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates an errored example.
|
|
||||||
def self.create
|
|
||||||
hooks = Spectator::ExampleHooks.empty
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
new(group, values).tap do |example|
|
|
||||||
group.children = [example.as(Spectator::ExampleComponent)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,59 +0,0 @@
|
||||||
# Creates a new `Spectator::ExampleHooks` instance.
|
|
||||||
# All arguments are optional,
|
|
||||||
# only specify the sets of hooks that are needed.
|
|
||||||
# The hooks that aren't specified will be left empty.
|
|
||||||
def new_hooks(
|
|
||||||
before_all = [] of ->,
|
|
||||||
before_each = [] of ->,
|
|
||||||
after_all = [] of ->,
|
|
||||||
after_each = [] of ->,
|
|
||||||
around_each = [] of Proc(Nil) ->
|
|
||||||
)
|
|
||||||
Spectator::ExampleHooks.new(before_all, before_each,
|
|
||||||
after_all, after_each, around_each)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a new `Spectator::ExampleHooks` instance.
|
|
||||||
# All arguments are optional,
|
|
||||||
# only specify a hook for the types that are needed.
|
|
||||||
# The hooks that aren't specified will be left empty.
|
|
||||||
def new_hooks(
|
|
||||||
before_all : Proc(Nil)? = nil,
|
|
||||||
before_each : Proc(Nil)? = nil,
|
|
||||||
after_all : Proc(Nil)? = nil,
|
|
||||||
after_each : Proc(Nil)? = nil,
|
|
||||||
around_each : Proc(Proc(Nil), Nil)? = nil
|
|
||||||
)
|
|
||||||
new_hooks(
|
|
||||||
before_all ? [before_all] : [] of ->,
|
|
||||||
before_each ? [before_each] : [] of ->,
|
|
||||||
after_all ? [after_all] : [] of ->,
|
|
||||||
after_each ? [after_each] : [] of ->,
|
|
||||||
around_each ? [around_each] : [] of Proc(Nil) ->
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a new `Spectator::ExampleConditions` instance.
|
|
||||||
# All arguments are optional,
|
|
||||||
# only specify the sets of conditions that are needed.
|
|
||||||
# The conditions that aren't specified will be left empty.
|
|
||||||
def new_conditions(
|
|
||||||
pre = [] of ->,
|
|
||||||
post = [] of ->
|
|
||||||
)
|
|
||||||
Spectator::ExampleConditions.new(pre, post)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a new `Spectator::ExampleConditions` instance.
|
|
||||||
# All arguments are optional,
|
|
||||||
# only specify a condition for the types that are needed.
|
|
||||||
# The conditions that aren't specified will be left empty.
|
|
||||||
def new_conditions(
|
|
||||||
pre : Proc(Nil)? = nil,
|
|
||||||
post : Proc(Nil)? = nil
|
|
||||||
)
|
|
||||||
new_conditions(
|
|
||||||
pre ? [pre] : [] of ->,
|
|
||||||
post ? [post] : [] of ->
|
|
||||||
)
|
|
||||||
end
|
|
|
@ -1,71 +0,0 @@
|
||||||
# Utility methods for creating expectations, partials, and matchers.
|
|
||||||
|
|
||||||
def new_partial(actual : T, label : String) forall T
|
|
||||||
test_value = Spectator::TestValue.new(actual, label)
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
Spectator::Expectations::ExpectationPartial.new(test_value, source)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_partial(actual : T = 123) forall T
|
|
||||||
test_value = Spectator::TestValue.new(actual)
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
Spectator::Expectations::ExpectationPartial.new(test_value, source)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_block_partial(label = "BLOCK", &block)
|
|
||||||
test_block = Spectator::TestBlock.new(block, label)
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
Spectator::Expectations::ExpectationPartial.new(test_block, source)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_matcher(expected : T, label : String) forall T
|
|
||||||
test_value = Spectator::TestValue.new(expected, label)
|
|
||||||
Spectator::Matchers::EqualityMatcher.new(test_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_matcher(expected : T = 123) forall T
|
|
||||||
test_value = Spectator::TestValue.new(expected)
|
|
||||||
Spectator::Matchers::EqualityMatcher.new(test_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_expectation(expected : ExpectedType = 123, actual : ActualType = 123) forall ExpectedType, ActualType
|
|
||||||
partial = new_partial(actual, "foo")
|
|
||||||
matcher = new_matcher(expected, "bar")
|
|
||||||
match_data = matcher.match(partial.actual)
|
|
||||||
Spectator::Expectations::Expectation.new(match_data, partial.source)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_satisfied_expectation(value : T = 123) forall T
|
|
||||||
new_expectation(value, value).tap do |expectation|
|
|
||||||
expectation.satisfied?.should be_true # Sanity check.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_unsatisfied_expectation(expected : ExpectedType = 123, actual : ActualType = 456) forall ExpectedType, ActualType
|
|
||||||
new_expectation(expected, actual).tap do |expectation|
|
|
||||||
expectation.satisfied?.should be_false # Sanity check.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_expectations(success_count = 1, failure_count = 0)
|
|
||||||
satisfied = Array.new(success_count) { new_satisfied_expectation }
|
|
||||||
unsatisfied = Array.new(failure_count) { new_unsatisfied_expectation }
|
|
||||||
(satisfied + unsatisfied).shuffle
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_expectations(success_count = 1, failure_count = 0)
|
|
||||||
satisfied = Array.new(success_count) { new_satisfied_expectation }
|
|
||||||
unsatisfied = Array.new(failure_count) { new_unsatisfied_expectation }
|
|
||||||
expectations = (satisfied + unsatisfied).shuffle
|
|
||||||
reporter = Spectator::Expectations::ExpectationReporter.new(false)
|
|
||||||
expectations.each do |expectation|
|
|
||||||
reporter.report(expectation)
|
|
||||||
end
|
|
||||||
{satisfied: satisfied, unsatisfied: unsatisfied, expectations: expectations, reporter: reporter}
|
|
||||||
end
|
|
||||||
|
|
||||||
def report_expectations(success_count = 1, failure_count = 0)
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
success_count.times { harness.report_expectation(new_satisfied_expectation) }
|
|
||||||
failure_count.times { harness.report_expectation(new_unsatisfied_expectation) }
|
|
||||||
end
|
|
|
@ -1,44 +0,0 @@
|
||||||
# Example that always fails.
|
|
||||||
class FailingExample < Spectator::RunnableExample
|
|
||||||
# Dummy description.
|
|
||||||
def what : Symbol | String
|
|
||||||
"FAIL"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy source.
|
|
||||||
def source : ::Spectator::Source
|
|
||||||
::Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy symbolic flag.
|
|
||||||
def symbolic? : Bool
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy instance.
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the example that always fails.
|
|
||||||
private def run_instance
|
|
||||||
report_expectations(0, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a failing example.
|
|
||||||
def self.create(hooks = Spectator::ExampleHooks.empty, conditions = Spectator::ExampleConditions.empty)
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, conditions)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
new(group, values).tap do |example|
|
|
||||||
group.children = [example.as(Spectator::ExampleComponent)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a group of failing examples.
|
|
||||||
def self.create_group(count = 5, hooks = Spectator::ExampleHooks.empty, conditions = Spectator::ExampleConditions.empty)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
Spectator::RootExampleGroup.new(hooks, conditions).tap do |group|
|
|
||||||
group.children = Array.new(count) { new(group, values).as(Spectator::ExampleComponent) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Retrieves a value from match data given its key/label.
|
|
||||||
def match_data_value_with_key(match_data_values, key)
|
|
||||||
labeled_value = match_data_values.find { |v| v.label == key }
|
|
||||||
raise "#{key} is missing" unless labeled_value
|
|
||||||
labeled_value.value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Retrieves the string representation and base value
|
|
||||||
# from a `Spectator::Matchers::PrefixedMatchDataValue` (or similar)
|
|
||||||
# in the values returned by `Spectator::Matchers::MatchData#values`.
|
|
||||||
def match_data_value_sans_prefix(match_data_values, key)
|
|
||||||
prefix = match_data_value_with_key(match_data_values, key)
|
|
||||||
{to_s: prefix.to_s, value: prefix.value}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check whether match data has a value with a specified key/label.
|
|
||||||
def match_data_has_key?(match_data_values, key)
|
|
||||||
found = match_data_values.find { |v| v.label == key }
|
|
||||||
!!found
|
|
||||||
end
|
|
|
@ -1,42 +0,0 @@
|
||||||
# Example that always succeeds.
|
|
||||||
class PassingExample < Spectator::RunnableExample
|
|
||||||
# Creates the example.
|
|
||||||
def initialize(group, values, @symbolic = false)
|
|
||||||
super(group, values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy description.
|
|
||||||
def what : Symbol | String
|
|
||||||
"PASS"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy source.
|
|
||||||
def source : ::Spectator::Source
|
|
||||||
::Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy symbolic flag.
|
|
||||||
def symbolic? : Bool
|
|
||||||
@symbolic
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy instance.
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run the example that always passes.
|
|
||||||
# If this doesn't something broke.
|
|
||||||
private def run_instance
|
|
||||||
report_expectations(1, 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a passing example.
|
|
||||||
def self.create(hooks = Spectator::ExampleHooks.empty, conditions = Spectator::ExampleConditions.empty)
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, conditions)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
new(group, values).tap do |example|
|
|
||||||
group.children = [example.as(Spectator::ExampleComponent)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,16 +0,0 @@
|
||||||
# Spy class for testing `Spectator::Result#call`.
|
|
||||||
class ResultCallSpy
|
|
||||||
{% for name in %i[success failure error pending] %}
|
|
||||||
getter? {{name.id}} = false
|
|
||||||
|
|
||||||
def {{name.id}}
|
|
||||||
@{{name.id}} = true
|
|
||||||
{{name}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def {{name.id}}(arg)
|
|
||||||
@{{name.id}} = true
|
|
||||||
arg
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
end
|
|
|
@ -1,69 +0,0 @@
|
||||||
# Example that invokes a closure when it is run.
|
|
||||||
# This is useful for capturing what's going on when an event is running.
|
|
||||||
class SpyExample < Spectator::RunnableExample
|
|
||||||
# Dummy description.
|
|
||||||
def what : Symbol | String
|
|
||||||
"SPY"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy source.
|
|
||||||
def source : ::Spectator::Source
|
|
||||||
::Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy symbolic flag.
|
|
||||||
def symbolic? : Bool
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy instance.
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Captures the sample values when the example is created.
|
|
||||||
def initialize(group, @sample_values)
|
|
||||||
super(group, @sample_values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Sample values given to the example.
|
|
||||||
getter sample_values : Spectator::Internals::SampleValues
|
|
||||||
|
|
||||||
# Harness that was used while running the example.
|
|
||||||
getter! harness : Spectator::Internals::Harness
|
|
||||||
|
|
||||||
setter block : Proc(Nil)? = nil
|
|
||||||
|
|
||||||
# Method called by the framework to run the example code.
|
|
||||||
private def run_instance
|
|
||||||
@harness = Spectator::Internals::Harness.current
|
|
||||||
if block = @block
|
|
||||||
block.call
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a spy example.
|
|
||||||
# The block passed to this method will be executed when the example runs.
|
|
||||||
def self.create(hooks = Spectator::ExampleHooks.empty, conditions = Spectator::ExampleConditions.empty, &block)
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, conditions)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
new(group, values).tap do |example|
|
|
||||||
group.children = [example.as(Spectator::ExampleComponent)]
|
|
||||||
example.block = block
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a group of spy examples.
|
|
||||||
# Specify the number of examplese to create and a block to invoke when the example is run.
|
|
||||||
# The block is given the index of the example in the group.
|
|
||||||
def self.create_group(count, &block : Int32 -> Nil)
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |group|
|
|
||||||
group.children = Array.new(count) do |index|
|
|
||||||
new(group, values).tap do |example|
|
|
||||||
example.block = block.partial(index)
|
|
||||||
end.as(Spectator::ExampleComponent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,47 +0,0 @@
|
||||||
# Formatter that doubles as a spy.
|
|
||||||
# This class tracks calls made to it.
|
|
||||||
class SpyFormatter < Spectator::Formatting::Formatter
|
|
||||||
{% for item in [
|
|
||||||
{"start_suite", "Spectator::TestSuite"},
|
|
||||||
{"start_example", "Spectator::Example"},
|
|
||||||
{"end_example", "Spectator::Result"},
|
|
||||||
] %}
|
|
||||||
{% method_name = item[0].id %}
|
|
||||||
{% argument_type = item[1].id %}
|
|
||||||
|
|
||||||
# Stores all invocations made to `#{{method_name}}`.
|
|
||||||
# Each element is an invocation and the value is the argument passed to the method.
|
|
||||||
getter {{method_name}}_calls = [] of {{argument_type}}
|
|
||||||
|
|
||||||
# Number of times the `#{{method_name}}` method was called.
|
|
||||||
def {{method_name}}_call_count
|
|
||||||
@{{method_name}}_calls.size
|
|
||||||
end
|
|
||||||
|
|
||||||
# Increments `#{{method_name}}_call_count` and stores the argument.
|
|
||||||
def {{method_name}}(arg : {{argument_type}})
|
|
||||||
@all_calls << {{method_name.symbolize}}
|
|
||||||
@{{method_name}}_calls << arg
|
|
||||||
end
|
|
||||||
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
# Stores all invocatiosn made to `#end_suite`.
|
|
||||||
# Each element is an invocation and the value is the arguments passed to the method.
|
|
||||||
getter end_suite_calls = [] of NamedTuple(report: Spectator::Report, profile: Spectator::Profile?)
|
|
||||||
|
|
||||||
# Number of times the `#end_suite` method was called.
|
|
||||||
def end_suite_call_count
|
|
||||||
@end_suite_calls.size
|
|
||||||
end
|
|
||||||
|
|
||||||
# Increments `#end_suite_call_count` and stores the arguments.
|
|
||||||
def end_suite(report, profile)
|
|
||||||
@all_calls << :end_suite
|
|
||||||
@end_suite_calls << {report: report, profile: profile}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Stores the methods that were called and in which order.
|
|
||||||
# The symbols will be the method name (i.e. `:start_suite`).
|
|
||||||
getter all_calls = [] of Symbol
|
|
||||||
end
|
|
|
@ -1,28 +0,0 @@
|
||||||
# Example system to test that doubles as a spy.
|
|
||||||
# This class tracks calls made to it.
|
|
||||||
class SpySUT
|
|
||||||
{% for item in [
|
|
||||||
{"==", "eq"},
|
|
||||||
{"!=", "ne"},
|
|
||||||
{"<", "lt"},
|
|
||||||
{"<=", "le"},
|
|
||||||
{">", "gt"},
|
|
||||||
{">=", "ge"},
|
|
||||||
{"===", "case_eq"},
|
|
||||||
{"=~", "match"},
|
|
||||||
{"includes?", "includes"},
|
|
||||||
] %}
|
|
||||||
{% operator = item[0].id %}
|
|
||||||
{% name = item[1].id %}
|
|
||||||
|
|
||||||
# Number of times the `#{{operator}}` method was called.
|
|
||||||
getter {{name}}_call_count = 0
|
|
||||||
|
|
||||||
# Returns true and increments `#{{name}}_call_count`.
|
|
||||||
def {{operator}}(other : T) forall T
|
|
||||||
@{{name}}_call_count += 1
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
{% end %}
|
|
||||||
end
|
|
|
@ -1,109 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Internals::Harness do
|
|
||||||
describe "#run" do
|
|
||||||
it "runs an example" do
|
|
||||||
run_count = 0
|
|
||||||
spy = SpyExample.create do
|
|
||||||
run_count += 1
|
|
||||||
end
|
|
||||||
Spectator::Internals::Harness.run(spy)
|
|
||||||
run_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a passing exmaple" do
|
|
||||||
it "returns a passing result" do
|
|
||||||
example = PassingExample.create
|
|
||||||
result = Spectator::Internals::Harness.run(example)
|
|
||||||
result.should be_a(Spectator::SuccessfulResult)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a failing example" do
|
|
||||||
it "returns a failing result" do
|
|
||||||
example = FailingExample.create
|
|
||||||
result = Spectator::Internals::Harness.run(example)
|
|
||||||
result.should be_a(Spectator::FailedResult)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#current" do
|
|
||||||
it "references the current harness" do
|
|
||||||
harness = nil.as(Spectator::Internals::Harness?)
|
|
||||||
spy = SpyExample.create do
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
end
|
|
||||||
Spectator::Internals::Harness.run(spy)
|
|
||||||
harness.should be_a(Spectator::Internals::Harness)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example" do
|
|
||||||
it "references the current example" do
|
|
||||||
example = nil.as(Spectator::Example?)
|
|
||||||
spy = SpyExample.create do
|
|
||||||
example = Spectator::Internals::Harness.current.example
|
|
||||||
end
|
|
||||||
Spectator::Internals::Harness.run(spy)
|
|
||||||
example.should be(spy)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#report_expectation" do
|
|
||||||
context "with a successful result" do
|
|
||||||
it "stores the result" do
|
|
||||||
expectation = new_satisfied_expectation
|
|
||||||
spy = SpyExample.create do
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
harness.report_expectation(expectation)
|
|
||||||
end
|
|
||||||
result = Spectator::Internals::Harness.run(spy)
|
|
||||||
result.should be_a(Spectator::SuccessfulResult)
|
|
||||||
result.as(Spectator::SuccessfulResult).expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a failed result" do
|
|
||||||
it "raises an error" do
|
|
||||||
error = nil.as(Exception?)
|
|
||||||
spy = SpyExample.create do
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
begin
|
|
||||||
harness.report_expectation(new_unsatisfied_expectation)
|
|
||||||
rescue ex
|
|
||||||
error = ex
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Spectator::Internals::Harness.run(spy)
|
|
||||||
error.should be_a(Spectator::ExampleFailed)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "stores the result" do
|
|
||||||
expectation = new_unsatisfied_expectation
|
|
||||||
spy = SpyExample.create do
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
harness.report_expectation(expectation)
|
|
||||||
end
|
|
||||||
result = Spectator::Internals::Harness.run(spy)
|
|
||||||
result.should be_a(Spectator::FailedResult)
|
|
||||||
result.as(Spectator::FailedResult).expectations.should contain(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#expectation_results" do
|
|
||||||
it "contains the reported results" do
|
|
||||||
expectations = [new_satisfied_expectation, new_unsatisfied_expectation]
|
|
||||||
spy = SpyExample.create do
|
|
||||||
harness = Spectator::Internals::Harness.current
|
|
||||||
expectations.each do |expectation|
|
|
||||||
harness.report_expectation(expectation)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
result = Spectator::Internals::Harness.run(spy)
|
|
||||||
reported_results = result.as(Spectator::FailedResult).expectations.to_a
|
|
||||||
(expectations - reported_results).size.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,117 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
private def add_sample_value(values : Spectator::Internals::SampleValues,
|
|
||||||
symbol : Symbol, name : String, value : T) forall T
|
|
||||||
values.add(symbol, name, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def add_sample_value(symbol, name, value : T) forall T
|
|
||||||
add_sample_value(Spectator::Internals::SampleValues.empty, symbol, name, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def add_sample_value(symbol, value : T) forall T
|
|
||||||
add_sample_value(symbol, symbol.to_s, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::Internals::SampleValues do
|
|
||||||
describe "#add" do
|
|
||||||
it "creates a new set" do
|
|
||||||
original = Spectator::Internals::SampleValues.empty
|
|
||||||
new_set = original.add(:new, "new", 123)
|
|
||||||
new_set.should_not eq(original)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "adds a new value" do
|
|
||||||
symbol = :new
|
|
||||||
value = 123
|
|
||||||
values = add_sample_value(symbol, value)
|
|
||||||
values.get_value(symbol, typeof(value)).should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#get_wrapper" do
|
|
||||||
it "returns a wrapper for a value" do
|
|
||||||
symbol = :new
|
|
||||||
value = 123
|
|
||||||
values = add_sample_value(symbol, value)
|
|
||||||
wrapper = values.get_wrapper(symbol)
|
|
||||||
wrapper.should be_a(Spectator::Internals::ValueWrapper)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the correct wrapper" do
|
|
||||||
symbol = :new
|
|
||||||
value = 123
|
|
||||||
values = add_sample_value(symbol, value)
|
|
||||||
wrapper = values.get_wrapper(symbol)
|
|
||||||
wrapper.should be_a(Spectator::Internals::TypedValueWrapper(typeof(value)))
|
|
||||||
wrapper.as(Spectator::Internals::TypedValueWrapper(typeof(value))).value.should eq(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with multiple values" do
|
|
||||||
it "returns the expected value" do
|
|
||||||
symbols = {
|
|
||||||
one: 123,
|
|
||||||
two: 456,
|
|
||||||
three: 789,
|
|
||||||
}
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
symbols.each do |symbol, number|
|
|
||||||
values = add_sample_value(values, symbol, symbol.to_s, number)
|
|
||||||
end
|
|
||||||
selected_symbol = :one
|
|
||||||
selected_number = symbols[selected_symbol]
|
|
||||||
wrapper = values.get_wrapper(selected_symbol)
|
|
||||||
wrapper.should be_a(Spectator::Internals::TypedValueWrapper(typeof(selected_number)))
|
|
||||||
wrapper.as(Spectator::Internals::TypedValueWrapper(typeof(selected_number))).value.should eq(selected_number)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#get_value" do
|
|
||||||
it "returns a value" do
|
|
||||||
symbol = :new
|
|
||||||
value = 123
|
|
||||||
values = add_sample_value(symbol, value)
|
|
||||||
values.get_value(symbol, typeof(value)).should eq(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with multiple values" do
|
|
||||||
it "returns the expected value" do
|
|
||||||
symbols = {
|
|
||||||
one: 123,
|
|
||||||
two: 456,
|
|
||||||
three: 789,
|
|
||||||
}
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
symbols.each do |symbol, number|
|
|
||||||
values = add_sample_value(values, symbol, symbol.to_s, number)
|
|
||||||
end
|
|
||||||
selected_symbol = :one
|
|
||||||
selected_number = symbols[selected_symbol]
|
|
||||||
value = values.get_value(selected_symbol, typeof(selected_number))
|
|
||||||
value.should eq(selected_number)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each" do
|
|
||||||
it "yields each entry" do
|
|
||||||
symbols = {
|
|
||||||
one: 123,
|
|
||||||
two: 456,
|
|
||||||
three: 789,
|
|
||||||
}
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
symbols.each do |symbol, number|
|
|
||||||
values = add_sample_value(values, symbol, symbol.to_s, number)
|
|
||||||
end
|
|
||||||
|
|
||||||
size = 0
|
|
||||||
values.each do |entry|
|
|
||||||
size += 1
|
|
||||||
symbols.keys.map(&.to_s).should contain(entry.name)
|
|
||||||
end
|
|
||||||
size.should eq(symbols.size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
require "../spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Internals::TypedValueWrapper do
|
|
||||||
describe "#value" do
|
|
||||||
it "returns the expected value" do
|
|
||||||
value = 12345
|
|
||||||
wrapper = Spectator::Internals::TypedValueWrapper.new(value)
|
|
||||||
wrapper.value.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can be cast for storage" do
|
|
||||||
value = 12345
|
|
||||||
wrapper = Spectator::Internals::TypedValueWrapper.new(value).as(Spectator::Internals::ValueWrapper)
|
|
||||||
typed = wrapper.as(Spectator::Internals::TypedValueWrapper(typeof(value)))
|
|
||||||
typed.value.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::LineExampleFilter do
|
|
||||||
describe "#includes?" do
|
|
||||||
context "with a matching example" do
|
|
||||||
it "is true" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::LineExampleFilter.new(example.source.line)
|
|
||||||
filter.includes?(example).should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a non-matching example" do
|
|
||||||
it "is false" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::LineExampleFilter.new(example.source.line + 5)
|
|
||||||
filter.includes?(example).should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::NameExampleFilter do
|
|
||||||
describe "#includes?" do
|
|
||||||
context "with a matching example" do
|
|
||||||
it "is true" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::NameExampleFilter.new(example.to_s)
|
|
||||||
filter.includes?(example).should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a non-matching example" do
|
|
||||||
it "is false" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::NameExampleFilter.new("BOGUS")
|
|
||||||
filter.includes?(example).should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::NullExampleFilter do
|
|
||||||
describe "#includes?" do
|
|
||||||
it "returns true" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::NullExampleFilter.new
|
|
||||||
filter.includes?(example).should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,122 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
class ConcretePendingExample < Spectator::PendingExample
|
|
||||||
def what : Symbol | String
|
|
||||||
"PENDING_TEST_EXAMPLE"
|
|
||||||
end
|
|
||||||
|
|
||||||
def source : ::Spectator::Source
|
|
||||||
::Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
def symbolic? : Bool
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_pending_example(group : Spectator::ExampleGroup? = nil)
|
|
||||||
ConcretePendingExample.new(group || new_root_group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_pending_example_with_hooks(hooks)
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
new_pending_example(group)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::PendingExample do
|
|
||||||
describe "#run" do
|
|
||||||
it "returns a pending result" do
|
|
||||||
new_pending_example.run.should be_a(Spectator::PendingResult)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't run before_all hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(before_all: ->{ called = true; nil })
|
|
||||||
example = new_pending_example_with_hooks(hooks)
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't run before_each hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(before_each: ->{ called = true; nil })
|
|
||||||
example = new_pending_example_with_hooks(hooks)
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't run after_all hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_all: ->{ called = true; nil })
|
|
||||||
example = new_pending_example_with_hooks(hooks)
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't run after_each hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_each: ->{ called = true; nil })
|
|
||||||
example = new_pending_example_with_hooks(hooks)
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't run around_each hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(around_each: ->(proc : ->) { called = true; proc.call })
|
|
||||||
example = new_pending_example_with_hooks(hooks)
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#finished?" do
|
|
||||||
it "is initially false" do
|
|
||||||
new_pending_example.finished?.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is true after #run is called" do
|
|
||||||
example = new_pending_example
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
example.finished?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#group" do
|
|
||||||
it "is the expected value" do
|
|
||||||
group = new_root_group
|
|
||||||
example = new_pending_example(group)
|
|
||||||
example.group.should eq(group)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example_count" do
|
|
||||||
it "is one" do
|
|
||||||
new_pending_example.example_count.should eq(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#[]" do
|
|
||||||
it "returns self" do
|
|
||||||
example = new_pending_example
|
|
||||||
example[0].should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#to_s" do
|
|
||||||
it "contains #what" do
|
|
||||||
example = new_pending_example
|
|
||||||
example.to_s.should contain(example.what)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "contains the group's #what" do
|
|
||||||
group = new_nested_group
|
|
||||||
example = new_pending_example(group)
|
|
||||||
example.to_s.should contain(group.what.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,53 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_pending_result(example : Spectator::Example? = nil)
|
|
||||||
Spectator::PendingResult.new(example || FailingExample.create)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::PendingResult do
|
|
||||||
describe "#call" do
|
|
||||||
context "without a block" do
|
|
||||||
it "invokes #pending on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_pending_result.call(spy)
|
|
||||||
spy.pending?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #pending" do
|
|
||||||
result = new_pending_result
|
|
||||||
returned = result.call(ResultCallSpy.new)
|
|
||||||
returned.should eq(:pending)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a block" do
|
|
||||||
it "invokes #pending on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_pending_result.call(spy) { nil }
|
|
||||||
spy.pending?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "yields itself" do
|
|
||||||
result = new_pending_result
|
|
||||||
value = nil.as(Spectator::Result?)
|
|
||||||
result.call(ResultCallSpy.new) { |r| value = r }
|
|
||||||
value.should eq(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #pending" do
|
|
||||||
result = new_pending_result
|
|
||||||
value = 42
|
|
||||||
returned = result.call(ResultCallSpy.new) { value }
|
|
||||||
returned.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example" do
|
|
||||||
it "is the expected value" do
|
|
||||||
example = PassingExample.create
|
|
||||||
result = new_pending_result(example: example)
|
|
||||||
result.example.should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,237 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_passing_result
|
|
||||||
example = PassingExample.create
|
|
||||||
elapsed = Time::Span.new(nanoseconds: 1_000_000)
|
|
||||||
expectations = Spectator::Expectations::ExampleExpectations.new([] of Spectator::Expectations::Expectation)
|
|
||||||
Spectator::SuccessfulResult.new(example, elapsed, expectations)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_failure_result(result_type : Spectator::Result.class = Spectator::FailedResult)
|
|
||||||
example = FailingExample.create # Doesn't matter what type of example is used here.
|
|
||||||
elapsed = Time::Span.new(nanoseconds: 1_000_000)
|
|
||||||
expectations = Spectator::Expectations::ExampleExpectations.new([] of Spectator::Expectations::Expectation)
|
|
||||||
error = Exception.new("foobar")
|
|
||||||
result_type.new(example, elapsed, expectations, error)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_results(successful_count = 5, failed_count = 5, error_count = 5, pending_count = 5)
|
|
||||||
total = successful_count + failed_count + error_count + pending_count
|
|
||||||
results = Array(Spectator::Result).new(total)
|
|
||||||
successful_count.times { results << new_passing_result }
|
|
||||||
failed_count.times { results << new_failure_result }
|
|
||||||
error_count.times { results << new_failure_result(Spectator::ErroredResult) }
|
|
||||||
pending_count.times { results << new_pending_result }
|
|
||||||
results
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_report(successful_count = 5, failed_count = 5, error_count = 5, pending_count = 5, overhead_time = 1_000_000i64, fail_blank = false)
|
|
||||||
results = new_results(successful_count, failed_count, error_count, pending_count)
|
|
||||||
example_runtime = results.compact_map(&.as?(Spectator::FinishedResult)).sum(&.elapsed)
|
|
||||||
total_runtime = example_runtime + Time::Span.new(nanoseconds: overhead_time)
|
|
||||||
Spectator::Report.new(results, total_runtime, fail_blank: fail_blank)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::Report do
|
|
||||||
describe "#initialize(results)" do
|
|
||||||
describe "#runtime" do
|
|
||||||
it "is the sum of all results' runtimes" do
|
|
||||||
results = new_results
|
|
||||||
runtime = results.compact_map(&.as?(Spectator::FinishedResult)).sum(&.elapsed)
|
|
||||||
report = Spectator::Report.new(results)
|
|
||||||
report.runtime.should eq(runtime)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each" do
|
|
||||||
it "yields all results" do
|
|
||||||
results = new_results
|
|
||||||
report = Spectator::Report.new(results)
|
|
||||||
# The `#each` method is tested through `Enumerable#to_a`.
|
|
||||||
report.to_a.should eq(results)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#runtime" do
|
|
||||||
it "is the expected value" do
|
|
||||||
span = Time::Span.new(10, 10, 10)
|
|
||||||
report = Spectator::Report.new([] of Spectator::Result, span)
|
|
||||||
report.runtime.should eq(span)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.example_count.should eq(14)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#examples_ran" do
|
|
||||||
it "is the number of non-skipped examples" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.examples_ran.should eq(12)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#successful_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.successful_count.should eq(5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#failed_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.failed_count.should eq(7)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#error_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.error_count.should eq(3)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#pending_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.pending_count.should eq(2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#remaining_count" do
|
|
||||||
it "is the expected value" do
|
|
||||||
results = [] of Spectator::Result
|
|
||||||
remaining = 5
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero, remaining)
|
|
||||||
report.remaining_count.should eq(remaining)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#failed?" do
|
|
||||||
context "with a failed test suite" do
|
|
||||||
it "is true" do
|
|
||||||
report = new_report(5, 4, 3, 2)
|
|
||||||
report.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a passing test suite" do
|
|
||||||
it "is false" do
|
|
||||||
report = new_report(5, 0, 0, 0)
|
|
||||||
report.failed?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with fail-blank enabled" do
|
|
||||||
context "when no tests run" do
|
|
||||||
it "is true" do
|
|
||||||
report = new_report(0, 0, 0, 5, fail_blank: true)
|
|
||||||
report.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when tests run" do
|
|
||||||
context "and there are failures" do
|
|
||||||
it "is true" do
|
|
||||||
report = new_report(5, 4, 3, 2, fail_blank: true)
|
|
||||||
report.failed?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "and there are no failures" do
|
|
||||||
it "is false" do
|
|
||||||
report = new_report(5, 0, 0, 2, fail_blank: true)
|
|
||||||
report.failed?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#remaining?" do
|
|
||||||
context "with remaining tests" do
|
|
||||||
it "is true" do
|
|
||||||
results = [] of Spectator::Result
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero, 5)
|
|
||||||
report.remaining?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "without remaining tests" do
|
|
||||||
it "is false" do
|
|
||||||
results = [] of Spectator::Result
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero, 0)
|
|
||||||
report.remaining?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#failures" do
|
|
||||||
it "returns the expected results" do
|
|
||||||
results = Array.new(5) { new_failure_result.as(Spectator::Result) }
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero)
|
|
||||||
report.failures.to_a.should eq(results)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "includes errors" do
|
|
||||||
results = Array(Spectator::Result).new(5) do |index|
|
|
||||||
if index.odd?
|
|
||||||
new_failure_result
|
|
||||||
else
|
|
||||||
new_failure_result(Spectator::ErroredResult)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero)
|
|
||||||
report.failures.to_a.should eq(results)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#errors" do
|
|
||||||
it "returns the expected results" do
|
|
||||||
results = Array.new(5) { new_failure_result(Spectator::ErroredResult).as(Spectator::Result) }
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero)
|
|
||||||
report.errors.to_a.should eq(results)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "does not include failures" do
|
|
||||||
results = Array(Spectator::Result).new(5) do |index|
|
|
||||||
if index.odd?
|
|
||||||
new_failure_result
|
|
||||||
else
|
|
||||||
new_failure_result(Spectator::ErroredResult)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
report = Spectator::Report.new(results, Time::Span.zero)
|
|
||||||
errors_only = results.select(&.is_a?(Spectator::ErroredResult))
|
|
||||||
report.errors.to_a.should eq(errors_only)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example_runtime" do
|
|
||||||
it "is the sum of all example run-times" do
|
|
||||||
passing_results = Array.new(5) { new_passing_result }
|
|
||||||
runtime = passing_results.sum(&.elapsed)
|
|
||||||
results = passing_results.map(&.as(Spectator::Result))
|
|
||||||
total_runtime = runtime + Time::Span.new(nanoseconds: 1_234_567)
|
|
||||||
report = Spectator::Report.new(results, total_runtime)
|
|
||||||
report.example_runtime.should eq(runtime)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#overhead_time" do
|
|
||||||
it "is the difference between total runtime and the sum of all example run-times" do
|
|
||||||
passing_results = Array.new(5) { new_passing_result }
|
|
||||||
runtime = passing_results.sum(&.elapsed)
|
|
||||||
results = passing_results.map(&.as(Spectator::Result))
|
|
||||||
overhead = Time::Span.new(nanoseconds: 1_234_567)
|
|
||||||
total_runtime = runtime + overhead
|
|
||||||
report = Spectator::Report.new(results, total_runtime)
|
|
||||||
report.overhead_time.should eq(overhead)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,810 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_root_group(hooks = Spectator::ExampleHooks.empty, conditions = Spectator::ExampleConditions.empty)
|
|
||||||
Spectator::RootExampleGroup.new(hooks, conditions).tap do |group|
|
|
||||||
group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def root_group_with_examples(example_count = 5)
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(example_count) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{group, examples}
|
|
||||||
end
|
|
||||||
|
|
||||||
def root_group_with_sub_groups(sub_group_count = 5, example_count = 5)
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(sub_group_count) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(example_count) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{group, examples}
|
|
||||||
end
|
|
||||||
|
|
||||||
def complex_root_group
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(10) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group1|
|
|
||||||
sub_group1.children = Array(Spectator::ExampleComponent).new(10) do |j|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(sub_group1, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(j.to_s, sub_group1, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group2|
|
|
||||||
sub_group2.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group2, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
{group, examples}
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::RootExampleGroup do
|
|
||||||
describe "#run_before_hooks" do
|
|
||||||
it "runs a before_all hook" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(before_all: ->{ called = true; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_before_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs a before_each hook" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(before_each: ->{ called = true; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_before_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple before_all hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(before_all: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple before_each hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(before_each: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_before_hooks
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs hooks in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
hooks = new_hooks(before_all: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
],
|
|
||||||
before_each: [
|
|
||||||
->{ calls << :d; nil },
|
|
||||||
->{ calls << :e; nil },
|
|
||||||
->{ calls << :f; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_before_hooks
|
|
||||||
calls.should eq(%i[a b c d e f])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the before_all hooks once" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(before_all: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
2.times { group.run_before_hooks }
|
|
||||||
call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the before_each hooks multiple times" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(before_each: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
2.times { group.run_before_hooks }
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#run_after_hooks" do
|
|
||||||
# No children are used for most of these examples.
|
|
||||||
# That's because `[].all?` is always true.
|
|
||||||
# Which means that all examples are considered finished, since there are none.
|
|
||||||
it "runs a single after_all hook" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_all: ->{ called = true; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs a single after_each hook" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_each: ->{ called = true; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple after_all hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_all: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple after_each hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_all: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_after_hooks
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs hooks in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
hooks = new_hooks(after_each: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
],
|
|
||||||
after_all: [
|
|
||||||
->{ calls << :d; nil },
|
|
||||||
->{ calls << :e; nil },
|
|
||||||
->{ calls << :f; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
group.run_after_hooks
|
|
||||||
calls.should eq(%i[a b c d e f])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the after_all hooks once" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_all: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
2.times { group.run_after_hooks }
|
|
||||||
call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the after_each hooks multiple times" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_each: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(hooks)
|
|
||||||
2.times { group.run_after_hooks }
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with no examples finished" do
|
|
||||||
it "doesn't run the after_all hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_all: ->{ called = true; nil })
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the after_each hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_each: ->{ called = true; nil })
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with some examples finished" do
|
|
||||||
it "doesn't run the after_all hooks" do
|
|
||||||
called = false
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
hooks = new_hooks(after_all: ->{ called = true; nil })
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
examples.each_with_index do |example, index|
|
|
||||||
Spectator::Internals::Harness.run(example) if index % 2 == 0
|
|
||||||
end
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the after_each hooks" do
|
|
||||||
called = false
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
hooks = new_hooks(after_each: ->{ called = true; nil })
|
|
||||||
group = Spectator::RootExampleGroup.new(hooks, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).tap do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
end
|
|
||||||
examples.each_with_index do |example, index|
|
|
||||||
Spectator::Internals::Harness.run(example) if index % 2 == 0
|
|
||||||
end
|
|
||||||
group.run_after_hooks
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#wrap_around_each_hooks" do
|
|
||||||
it "wraps the block" do
|
|
||||||
called = false
|
|
||||||
wrapper = new_root_group.wrap_around_each_hooks do
|
|
||||||
called = true
|
|
||||||
end
|
|
||||||
wrapper.call
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps a proc" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(around_each: ->(proc : ->) { called = true; proc.call })
|
|
||||||
wrapper = new_root_group(hooks).wrap_around_each_hooks { }
|
|
||||||
wrapper.call
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps multiple procs" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(around_each: [
|
|
||||||
->(proc : ->) { call_count += 1; proc.call },
|
|
||||||
->(proc : ->) { call_count += 2; proc.call },
|
|
||||||
->(proc : ->) { call_count += 3; proc.call },
|
|
||||||
])
|
|
||||||
wrapper = new_root_group(hooks).wrap_around_each_hooks { }
|
|
||||||
wrapper.call
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "wraps procs in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
hooks = new_hooks(around_each: [
|
|
||||||
->(proc : ->) { calls << :a; proc.call },
|
|
||||||
->(proc : ->) { calls << :b; proc.call },
|
|
||||||
->(proc : ->) { calls << :c; proc.call },
|
|
||||||
])
|
|
||||||
wrapper = new_root_group(hooks).wrap_around_each_hooks { }
|
|
||||||
wrapper.call
|
|
||||||
calls.should eq(%i[a b c])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#run_pre_conditions" do
|
|
||||||
it "runs a condition" do
|
|
||||||
called = false
|
|
||||||
conditions = new_conditions(pre: ->{ called = true; nil })
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_pre_conditions
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple conditions" do
|
|
||||||
call_count = 0
|
|
||||||
conditions = new_conditions(pre: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_pre_conditions
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs conditions in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
conditions = new_conditions(pre: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_pre_conditions
|
|
||||||
calls.should eq(%i[a b c])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the conditions multiple times" do
|
|
||||||
call_count = 0
|
|
||||||
conditions = new_conditions(pre: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
2.times { group.run_pre_conditions }
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#run_post_conditions" do
|
|
||||||
it "runs a single condition" do
|
|
||||||
called = false
|
|
||||||
conditions = new_conditions(post: ->{ called = true; nil })
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_post_conditions
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs multiple conditions" do
|
|
||||||
call_count = 0
|
|
||||||
conditions = new_conditions(post: [
|
|
||||||
->{ call_count += 1; nil },
|
|
||||||
->{ call_count += 2; nil },
|
|
||||||
->{ call_count += 3; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_post_conditions
|
|
||||||
call_count.should eq(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs conditions in the correct order" do
|
|
||||||
calls = [] of Symbol
|
|
||||||
conditions = new_conditions(post: [
|
|
||||||
->{ calls << :a; nil },
|
|
||||||
->{ calls << :b; nil },
|
|
||||||
->{ calls << :c; nil },
|
|
||||||
])
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
group.run_post_conditions
|
|
||||||
calls.should eq(%i[a b c])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the conditions multiple times" do
|
|
||||||
call_count = 0
|
|
||||||
conditions = new_conditions(post: ->{ call_count += 1; nil })
|
|
||||||
group = new_root_group(conditions: conditions)
|
|
||||||
2.times { group.run_post_conditions }
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#to_s" do
|
|
||||||
it "is empty" do
|
|
||||||
new_root_group.to_s.should be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#children" do
|
|
||||||
it "raises an error when not set" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
expect_raises(Exception) { group.children }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the expected set" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
group.children = children
|
|
||||||
group.children.should eq(children)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#children=" do
|
|
||||||
it "raises an error trying to reset" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
group.children = children
|
|
||||||
expect_raises(Exception) { group.children = children }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each" do
|
|
||||||
it "yields each child" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.to_a.should eq(group.children)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't yield children of children" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.to_a.should eq(group.children)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#each : Iterator" do
|
|
||||||
it "iterates over each child" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.each.to_a.should eq(group.children)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't iterate over children of children" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
if i % 2 == 0
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = Array(Spectator::ExampleComponent).new(5) do
|
|
||||||
PassingExample.new(sub_group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.each.to_a.should eq(group.children)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example_count" do
|
|
||||||
context "with no examples" do
|
|
||||||
it "is zero" do
|
|
||||||
new_root_group.example_count.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with empty sub-groups" do
|
|
||||||
it "is zero" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
end
|
|
||||||
group.example_count.should eq(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with direct descendant examples" do
|
|
||||||
it "equals the number of examples" do
|
|
||||||
example_count = 10
|
|
||||||
group, _ = root_group_with_examples(example_count)
|
|
||||||
group.example_count.should eq(example_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with examples sub-groups" do
|
|
||||||
it "equals the total number of examples" do
|
|
||||||
sub_group_count = 3
|
|
||||||
example_count = 10
|
|
||||||
group, _ = root_group_with_sub_groups(sub_group_count, example_count)
|
|
||||||
group.example_count.should eq(sub_group_count * example_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with examples at all levels" do
|
|
||||||
it "equals the total number of examples" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
group.example_count.should eq(examples.size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#[]" do
|
|
||||||
context "when empty" do
|
|
||||||
it "raises an error" do
|
|
||||||
group = new_root_group
|
|
||||||
expect_raises(IndexError) { group[0] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with direct descendant examples" do
|
|
||||||
context "given 0" do
|
|
||||||
it "returns the first example" do
|
|
||||||
group, examples = root_group_with_examples
|
|
||||||
group[0].should eq(examples.first)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given -1" do
|
|
||||||
it "returns the last example" do
|
|
||||||
group, examples = root_group_with_examples
|
|
||||||
group[-1].should eq(examples.last)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds positive index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = root_group_with_examples(10)
|
|
||||||
group[3].should eq(examples[3])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds negative index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = root_group_with_examples(10)
|
|
||||||
group[-3].should eq(examples[-3])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds positive index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, _ = root_group_with_examples(10)
|
|
||||||
expect_raises(IndexError) { group[15] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, _ = root_group_with_examples(10)
|
|
||||||
expect_raises(IndexError) { group[10] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds negative index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, _ = root_group_with_examples(10)
|
|
||||||
expect_raises(IndexError) { group[-15] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, _ = root_group_with_examples(10)
|
|
||||||
expect_raises(IndexError) { group[-11] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with examples only in sub-groups" do
|
|
||||||
context "given 0" do
|
|
||||||
it "returns the first example" do
|
|
||||||
group, examples = root_group_with_sub_groups
|
|
||||||
group[0].should eq(examples.first)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given -1" do
|
|
||||||
it "returns the last example" do
|
|
||||||
group, examples = root_group_with_sub_groups
|
|
||||||
group[-1].should eq(examples.last)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds positive index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = root_group_with_sub_groups(10, 2)
|
|
||||||
group[6].should eq(examples[6])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds negative index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = root_group_with_sub_groups(10, 2)
|
|
||||||
group[-6].should eq(examples[-6])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds positive index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, _ = root_group_with_sub_groups(10, 2)
|
|
||||||
expect_raises(IndexError) { group[25] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, _ = root_group_with_sub_groups(10, 2)
|
|
||||||
expect_raises(IndexError) { group[20] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds negative index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, _ = root_group_with_sub_groups(10, 2)
|
|
||||||
expect_raises(IndexError) { group[-25] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, _ = root_group_with_sub_groups(10, 2)
|
|
||||||
expect_raises(IndexError) { group[-21] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with examples at all levels" do
|
|
||||||
context "given 0" do
|
|
||||||
it "returns the first example" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
group[0].should eq(examples.first)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given -1" do
|
|
||||||
it "returns the last example" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
group[-1].should eq(examples.last)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds positive index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
group[42].should eq(examples[42])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "given an in-bounds negative index" do
|
|
||||||
it "returns the expected example" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
group[-42].should eq(examples[-42])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds positive index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
expect_raises(IndexError) { group[examples.size + 5] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
expect_raises(IndexError) { group[examples.size] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "an out-of-bounds negative index" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
expect_raises(IndexError) { group[-examples.size - 5] }
|
|
||||||
end
|
|
||||||
|
|
||||||
it "handles off-by-one" do
|
|
||||||
group, examples = complex_root_group
|
|
||||||
expect_raises(IndexError) { group[-examples.size - 1] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with only sub-groups and no examples" do
|
|
||||||
it "raises an index error" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
expect_raises(IndexError) { group[0] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#finished?" do
|
|
||||||
context "with no children" do
|
|
||||||
it "is true" do
|
|
||||||
new_root_group.finished?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unfinished children" do
|
|
||||||
it "is false" do
|
|
||||||
group, _ = root_group_with_examples
|
|
||||||
group.finished?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with some finished children" do
|
|
||||||
it "is false" do
|
|
||||||
group, examples = root_group_with_examples
|
|
||||||
examples.each_with_index do |example, index|
|
|
||||||
Spectator::Internals::Harness.run(example) if index % 2 == 0
|
|
||||||
end
|
|
||||||
group.finished?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all finished children" do
|
|
||||||
it "is true" do
|
|
||||||
group, examples = root_group_with_examples
|
|
||||||
examples.each do |example|
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
end
|
|
||||||
group.finished?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a sub-group" do
|
|
||||||
context "with no children" do
|
|
||||||
it "is true" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) do |i|
|
|
||||||
Spectator::NestedExampleGroup.new(i.to_s, group, Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty).tap do |sub_group|
|
|
||||||
sub_group.children = [] of Spectator::ExampleComponent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
group.finished?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all unfinished children" do
|
|
||||||
it "is false" do
|
|
||||||
group, _ = root_group_with_sub_groups
|
|
||||||
group.finished?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with some finished children" do
|
|
||||||
it "is false" do
|
|
||||||
group, examples = root_group_with_sub_groups
|
|
||||||
examples.each_with_index do |example, index|
|
|
||||||
Spectator::Internals::Harness.run(example) if index % 2 == 0
|
|
||||||
end
|
|
||||||
group.finished?.should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with all finished children" do
|
|
||||||
it "is true" do
|
|
||||||
group, examples = root_group_with_sub_groups
|
|
||||||
examples.each do |example|
|
|
||||||
Spectator::Internals::Harness.run(example)
|
|
||||||
end
|
|
||||||
group.finished?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#symbolic?" do
|
|
||||||
it "is true" do
|
|
||||||
new_root_group.symbolic?.should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,270 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
# Creates a `Config` for Spectator that is suited for testing it.
|
|
||||||
def spectator_test_config(formatter : Spectator::Formatting::Formatter? = nil, fail_fast = false)
|
|
||||||
builder = Spectator::ConfigBuilder.new
|
|
||||||
builder.formatter = formatter || Spectator::Formatting::SilentFormatter.new
|
|
||||||
builder.fail_fast = fail_fast
|
|
||||||
builder.build
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_test_suite(group : Spectator::ExampleGroup? = nil)
|
|
||||||
filter = Spectator::NullExampleFilter.new
|
|
||||||
Spectator::TestSuite.new(group || PassingExample.create.group, filter)
|
|
||||||
end
|
|
||||||
|
|
||||||
def suite_with_nested_failures(hooks)
|
|
||||||
conditions = Spectator::ExampleConditions.empty
|
|
||||||
values = Spectator::Internals::SampleValues.empty
|
|
||||||
root = Spectator::RootExampleGroup.new(hooks, conditions)
|
|
||||||
root.children = Array(Spectator::ExampleComponent).new(5) do |index|
|
|
||||||
Spectator::NestedExampleGroup.new(index.to_s, root, hooks, conditions).tap do |group|
|
|
||||||
group.children = Array(Spectator::ExampleComponent).new(5) { FailingExample.new(group, values) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
new_test_suite(root)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::Runner do
|
|
||||||
describe "#run" do
|
|
||||||
it "runs all examples in the suite" do
|
|
||||||
called = [] of Int32
|
|
||||||
group = SpyExample.create_group(5) do |index|
|
|
||||||
called << index
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config)
|
|
||||||
runner.run
|
|
||||||
called.should eq([0, 1, 2, 3, 4])
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with fail-fast enabled" do
|
|
||||||
it "stops on the first failure" do
|
|
||||||
called = [] of Int32
|
|
||||||
group = SpyExample.create_group(10) do |index|
|
|
||||||
called << index
|
|
||||||
raise "Failure" if index > 5
|
|
||||||
end
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
called.should eq([0, 1, 2, 3, 4, 5, 6])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs after_each hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_each: ->{ called = true; nil })
|
|
||||||
group = FailingExample.create_group(hooks: hooks)
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs after_all hooks" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(after_all: ->{ called = true; nil })
|
|
||||||
group = FailingExample.create_group(hooks: hooks)
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the remaining around_each hook code" do
|
|
||||||
called = false
|
|
||||||
hooks = new_hooks(around_each: ->(proc : ->) {
|
|
||||||
proc.call
|
|
||||||
called = true
|
|
||||||
nil
|
|
||||||
})
|
|
||||||
group = FailingExample.create_group(hooks: hooks)
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
called.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with nested groups" do
|
|
||||||
it "runs after_each hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_each: ->{ call_count += 1; nil })
|
|
||||||
suite = suite_with_nested_failures(hooks)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs after_all hooks" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(after_all: ->{ call_count += 1; nil })
|
|
||||||
suite = suite_with_nested_failures(hooks)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "runs the remaining around_each hook code" do
|
|
||||||
call_count = 0
|
|
||||||
hooks = new_hooks(around_each: ->(proc : ->) {
|
|
||||||
proc.call
|
|
||||||
call_count += 1
|
|
||||||
nil
|
|
||||||
})
|
|
||||||
suite = suite_with_nested_failures(hooks)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(fail_fast: true))
|
|
||||||
runner.run
|
|
||||||
call_count.should eq(2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "the report" do
|
|
||||||
it "has the remaining tests" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
group = SpyExample.create_group(10) do |index|
|
|
||||||
raise "Failure" if index > 5
|
|
||||||
end
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy, true))
|
|
||||||
runner.run
|
|
||||||
args = spy.end_suite_calls.first
|
|
||||||
args[:report].remaining_count.should eq(3)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "the formatter" do
|
|
||||||
it "#start_suite is called once" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.start_suite_call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#start_suite is called at the beginning" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.all_calls.first.should eq(:start_suite)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes the test suite to #start_suite" do
|
|
||||||
test_suite = new_test_suite
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.start_suite_calls.first.should eq(test_suite)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#end_suite is called once" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.end_suite_call_count.should eq(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#end_suite is called at the end" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.all_calls.last.should eq(:end_suite)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#start_example is called" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.start_example_call_count.should be > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
it "#start_example is called for each example" do
|
|
||||||
group = SpyExample.create_group(5) { nil }
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.start_example_call_count.should eq(5)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes the correct example to #start_example" do
|
|
||||||
group = SpyExample.create_group(5) { nil }
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.start_example_calls.should eq(group.children)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls #end_example" do
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(new_test_suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.end_example_call_count.should be > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
it "calls #end_example for each example" do
|
|
||||||
group = SpyExample.create_group(5) { nil }
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.end_example_call_count.should eq(5)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "passes the correct result to #end_example" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array.new(5) do |index|
|
|
||||||
if index.odd?
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
FailingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end.as(Spectator::ExampleComponent)
|
|
||||||
end
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
spy.end_example_calls.map(&.example).should eq(group.children)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "the report" do
|
|
||||||
it "contains the expected results" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array.new(5) do |index|
|
|
||||||
if index.odd?
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
else
|
|
||||||
FailingExample.new(group, Spectator::Internals::SampleValues.empty)
|
|
||||||
end.as(Spectator::ExampleComponent)
|
|
||||||
end
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
runner.run
|
|
||||||
args = spy.end_suite_calls.first
|
|
||||||
args[:report].each_with_index do |result, index|
|
|
||||||
if index.odd?
|
|
||||||
result.should be_a(Spectator::SuccessfulResult)
|
|
||||||
else
|
|
||||||
result.should be_a(Spectator::FailedResult)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "contains the expected time span" do
|
|
||||||
group = SpyExample.create_group(5) { nil }
|
|
||||||
suite = new_test_suite(group)
|
|
||||||
spy = SpyFormatter.new
|
|
||||||
runner = Spectator::Runner.new(suite, spectator_test_config(spy))
|
|
||||||
max_time = Time.measure { runner.run }
|
|
||||||
min_time = spy.end_example_calls.each.map(&.as(Spectator::FinishedResult)).sum(&.elapsed)
|
|
||||||
args = spy.end_suite_calls.first
|
|
||||||
report = args[:report]
|
|
||||||
report.runtime.should be <= max_time
|
|
||||||
report.runtime.should be >= min_time
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::SourceExampleFilter do
|
|
||||||
describe "#includes?" do
|
|
||||||
context "with a matching example" do
|
|
||||||
it "is true" do
|
|
||||||
example = PassingExample.create
|
|
||||||
filter = Spectator::SourceExampleFilter.new(example.source)
|
|
||||||
filter.includes?(example).should be_true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a non-matching example" do
|
|
||||||
it "is false" do
|
|
||||||
example = PassingExample.create
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
filter = Spectator::SourceExampleFilter.new(source)
|
|
||||||
filter.includes?(example).should be_false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,76 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::Source do
|
|
||||||
describe "#file" do
|
|
||||||
it "is the expected value" do
|
|
||||||
file = __FILE__
|
|
||||||
source = Spectator::Source.new(file, __LINE__)
|
|
||||||
source.file.should eq(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#line" do
|
|
||||||
it "is the expected value" do
|
|
||||||
line = __LINE__
|
|
||||||
source = Spectator::Source.new(__FILE__, line)
|
|
||||||
source.line.should eq(line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#path" do
|
|
||||||
context "with a relative file" do
|
|
||||||
it "is shortened" do
|
|
||||||
file = "test.cr"
|
|
||||||
absolute = File.join(Dir.current, file)
|
|
||||||
source = Spectator::Source.new(absolute, __LINE__)
|
|
||||||
source.path.should eq(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a different directory" do
|
|
||||||
it "is the absolute path" do
|
|
||||||
file = "/foo/bar/baz.cr"
|
|
||||||
source = Spectator::Source.new(file, __LINE__)
|
|
||||||
source.path.should eq(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#to_s" do
|
|
||||||
it "contains #path" do
|
|
||||||
file = __FILE__
|
|
||||||
source = Spectator::Source.new(file, __LINE__)
|
|
||||||
source.to_s.should contain(source.path)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "contains #line" do
|
|
||||||
line = __LINE__
|
|
||||||
source = Spectator::Source.new(__FILE__, line)
|
|
||||||
source.to_s.should contain(line.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is formatted correctly" do
|
|
||||||
source = Spectator::Source.new(__FILE__, __LINE__)
|
|
||||||
source.to_s.should match(/^(.+?)\:(\d+)$/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse" do
|
|
||||||
it "gets the absolute path" do
|
|
||||||
file = "foo.cr"
|
|
||||||
path = File.expand_path(file)
|
|
||||||
source = Spectator::Source.parse("#{file}:42")
|
|
||||||
source.file.should eq(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "gets the relative path" do
|
|
||||||
source = Spectator::Source.parse("foo.cr:42")
|
|
||||||
source.path.should eq("foo.cr")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "gets the line number" do
|
|
||||||
source = Spectator::Source.parse("foo.cr:42")
|
|
||||||
source.line.should eq(42)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,6 +1,4 @@
|
||||||
require "spec"
|
|
||||||
require "../src/spectator"
|
require "../src/spectator"
|
||||||
require "./helpers/*"
|
|
||||||
|
|
||||||
# Prevent Spectator from trying to run tests.
|
# Prevent Spectator from trying to run tests on its own.
|
||||||
Spectator.autorun = false
|
Spectator.autorun = false
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
def new_successful_result(
|
|
||||||
example : Spectator::Example? = nil,
|
|
||||||
elapsed : Time::Span? = nil,
|
|
||||||
expectations : Spectator::Expectations::ExampleExpectations? = nil
|
|
||||||
)
|
|
||||||
Spectator::SuccessfulResult.new(
|
|
||||||
example || PassingExample.create,
|
|
||||||
elapsed || Time::Span.zero,
|
|
||||||
expectations || Spectator::Expectations::ExampleExpectations.new([new_satisfied_expectation])
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe Spectator::SuccessfulResult do
|
|
||||||
describe "#call" do
|
|
||||||
context "without a block" do
|
|
||||||
it "invokes #success on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_successful_result.call(spy)
|
|
||||||
spy.success?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #success" do
|
|
||||||
result = new_successful_result
|
|
||||||
returned = result.call(ResultCallSpy.new)
|
|
||||||
returned.should eq(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with a block" do
|
|
||||||
it "invokes #success on an instance" do
|
|
||||||
spy = ResultCallSpy.new
|
|
||||||
new_successful_result.call(spy) { nil }
|
|
||||||
spy.success?.should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "yields itself" do
|
|
||||||
result = new_successful_result
|
|
||||||
value = nil.as(Spectator::Result?)
|
|
||||||
result.call(ResultCallSpy.new) { |r| value = r }
|
|
||||||
value.should eq(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns the value of #success" do
|
|
||||||
result = new_successful_result
|
|
||||||
value = 42
|
|
||||||
returned = result.call(ResultCallSpy.new) { value }
|
|
||||||
returned.should eq(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#example" do
|
|
||||||
it "is the expected value" do
|
|
||||||
example = PassingExample.create
|
|
||||||
result = new_successful_result(example: example)
|
|
||||||
result.example.should eq(example)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#elapsed" do
|
|
||||||
it "is the expected value" do
|
|
||||||
elapsed = Time::Span.new(10, 10, 10)
|
|
||||||
result = new_successful_result(elapsed: elapsed)
|
|
||||||
result.elapsed.should eq(elapsed)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#expectations" do
|
|
||||||
it "is the expected value" do
|
|
||||||
expectations = Spectator::Expectations::ExampleExpectations.new(create_expectations(5, 0))
|
|
||||||
result = new_successful_result(expectations: expectations)
|
|
||||||
result.expectations.should eq(expectations)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,31 +0,0 @@
|
||||||
require "./spec_helper"
|
|
||||||
|
|
||||||
describe Spectator::TestSuite do
|
|
||||||
describe "#each" do
|
|
||||||
it "yields each example" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array.new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).as(Spectator::ExampleComponent)
|
|
||||||
end
|
|
||||||
test_suite = Spectator::TestSuite.new(group, Spectator::NullExampleFilter.new)
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
test_suite.each do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
examples.should eq(group.children)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "skips examples not in the filter" do
|
|
||||||
group = Spectator::RootExampleGroup.new(Spectator::ExampleHooks.empty, Spectator::ExampleConditions.empty)
|
|
||||||
group.children = Array.new(5) do
|
|
||||||
PassingExample.new(group, Spectator::Internals::SampleValues.empty).as(Spectator::ExampleComponent)
|
|
||||||
end
|
|
||||||
test_suite = Spectator::TestSuite.new(group, Spectator::CompositeExampleFilter.new([] of Spectator::ExampleFilter))
|
|
||||||
examples = [] of Spectator::Example
|
|
||||||
test_suite.each do |example|
|
|
||||||
examples << example
|
|
||||||
end
|
|
||||||
examples.should be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +1,12 @@
|
||||||
require "./spectator/includes"
|
require "./spectator/includes"
|
||||||
|
require "./spectator_test"
|
||||||
|
|
||||||
# Module that contains all functionality related to Spectator.
|
# Module that contains all functionality related to Spectator.
|
||||||
module Spectator
|
module Spectator
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
# Current version of the Spectator library.
|
# Current version of the Spectator library.
|
||||||
VERSION = "0.8.2"
|
VERSION = "0.9.0"
|
||||||
|
|
||||||
# Top-level describe method.
|
# Top-level describe method.
|
||||||
# All specs in a file must be wrapped in this call.
|
# All specs in a file must be wrapped in this call.
|
||||||
|
@ -23,7 +24,7 @@ module Spectator
|
||||||
# NOTE: Inside the block, the `Spectator` prefix is no longer needed.
|
# NOTE: Inside the block, the `Spectator` prefix is no longer needed.
|
||||||
# Actually, prefixing methods and macros with `Spectator`
|
# Actually, prefixing methods and macros with `Spectator`
|
||||||
# most likely won't work and can cause compiler errors.
|
# most likely won't work and can cause compiler errors.
|
||||||
macro describe(what, &block)
|
macro describe(description, &block)
|
||||||
# This macro creates the foundation for all specs.
|
# This macro creates the foundation for all specs.
|
||||||
# Every group of examples is defined a separate module - `SpectatorExamples`.
|
# Every group of examples is defined a separate module - `SpectatorExamples`.
|
||||||
# There's multiple reasons for this.
|
# There's multiple reasons for this.
|
||||||
|
@ -32,30 +33,21 @@ module Spectator
|
||||||
# We don't want the spec code to accidentally pickup types and values from the `Spectator` module.
|
# We don't want the spec code to accidentally pickup types and values from the `Spectator` module.
|
||||||
# Another reason is that we need a root module to put all examples and groups in.
|
# Another reason is that we need a root module to put all examples and groups in.
|
||||||
# And lastly, the spec DSL needs to be given to the block of code somehow.
|
# And lastly, the spec DSL needs to be given to the block of code somehow.
|
||||||
# The DSL is included in the `SpectatorExamples` module.
|
# The DSL is included in the `SpectatorTest` class.
|
||||||
#
|
#
|
||||||
# For more information on how the DSL works, see the `DSL` module.
|
# For more information on how the DSL works, see the `DSL` module.
|
||||||
|
|
||||||
# Root-level module that contains all examples and example groups.
|
# Root-level class that contains all examples and example groups.
|
||||||
module SpectatorExamples
|
class SpectatorTest
|
||||||
# Include the DSL for creating groups, example, and more.
|
# Pass off the description argument and block to `DSL::StructureDSL.describe`.
|
||||||
include ::Spectator::DSL::StructureDSL
|
|
||||||
|
|
||||||
# Placeholder initializer.
|
|
||||||
# This is needed because examples and groups call super in their initializer.
|
|
||||||
# Those initializers pass the sample values upward through their hierarchy.
|
|
||||||
def initialize(_sample_values : ::Spectator::Internals::SampleValues)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Pass off the "what" argument and block to `DSL::StructureDSL.describe`.
|
|
||||||
# That method will handle creating a new group for this spec.
|
# That method will handle creating a new group for this spec.
|
||||||
describe({{what}}) {{block}}
|
describe({{description}}) {{block}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# ditto
|
# ditto
|
||||||
macro context(what, &block)
|
macro context(description, &block)
|
||||||
describe({{what}}) {{block}}
|
describe({{description}}) {{block}}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Flag indicating whether Spectator should automatically run tests.
|
# Flag indicating whether Spectator should automatically run tests.
|
||||||
|
@ -109,7 +101,7 @@ module Spectator
|
||||||
# Builds the tests and runs the framework.
|
# Builds the tests and runs the framework.
|
||||||
private def run
|
private def run
|
||||||
# Build the test suite and run it.
|
# Build the test suite and run it.
|
||||||
suite = ::Spectator::DSL::Builder.build(config.example_filter)
|
suite = ::Spectator::SpecBuilder.build(config.example_filter)
|
||||||
Runner.new(suite, config).run
|
Runner.new(suite, config).run
|
||||||
rescue ex
|
rescue ex
|
||||||
# Catch all unhandled exceptions here.
|
# Catch all unhandled exceptions here.
|
||||||
|
|
|
@ -2,7 +2,6 @@ require "./dsl/*"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Namespace containing methods representing the spec domain specific language.
|
# Namespace containing methods representing the spec domain specific language.
|
||||||
# Also contains builders to generate classes and instances to later run the spec.
|
|
||||||
module DSL
|
module DSL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,14 +2,9 @@ require "../expectations/expectation_partial"
|
||||||
require "../source"
|
require "../source"
|
||||||
require "../test_block"
|
require "../test_block"
|
||||||
require "../test_value"
|
require "../test_value"
|
||||||
require "./matcher_dsl"
|
|
||||||
|
|
||||||
module Spectator::DSL
|
|
||||||
# Methods that are available inside test code.
|
|
||||||
# Basically, inside an `StructureDSL#it` block.
|
|
||||||
module ExampleDSL
|
|
||||||
include MatcherDSL
|
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
module DSL
|
||||||
# Starts an expectation.
|
# Starts an expectation.
|
||||||
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
# This should be followed up with `Spectator::Expectations::ExpectationPartial#to`
|
||||||
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
# or `Spectator::Expectations::ExpectationPartial#to_not`.
|
||||||
|
@ -23,9 +18,9 @@ module Spectator::DSL
|
||||||
# Where the actual value is returned by the system-under-test,
|
# Where the actual value is returned by the system-under-test,
|
||||||
# and the expected value is what the actual value should be to satisfy the condition.
|
# and the expected value is what the actual value should be to satisfy the condition.
|
||||||
macro expect(actual, _source_file = __FILE__, _source_line = __LINE__)
|
macro expect(actual, _source_file = __FILE__, _source_line = __LINE__)
|
||||||
test_value = ::Spectator::TestValue.new({{actual}}, {{actual.stringify}})
|
%test_value = ::Spectator::TestValue.new({{actual}}, {{actual.stringify}})
|
||||||
source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
::Spectator::Expectations::ExpectationPartial.new(test_value, source)
|
::Spectator::Expectations::ExpectationPartial.new(%test_value, %source)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Starts an expectation on a block of code.
|
# Starts an expectation on a block of code.
|
|
@ -1,15 +0,0 @@
|
||||||
module Spectator::DSL
|
|
||||||
# Creates instances of examples from a specified class.
|
|
||||||
class ExampleFactory
|
|
||||||
# Creates the factory.
|
|
||||||
# The type passed to this constructor must be a sub-type of `Example`.
|
|
||||||
def initialize(@example_type : Example.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Constructs a new example instance and returns it.
|
|
||||||
# The *group* and *sample_values* are passed to `Example#initialize`.
|
|
||||||
def build(group : ExampleGroup, sample_values : Internals::SampleValues) : Example
|
|
||||||
@example_type.new(group, sample_values)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,93 +0,0 @@
|
||||||
module Spectator::DSL
|
|
||||||
# Base class for building all example groups.
|
|
||||||
abstract class ExampleGroupBuilder
|
|
||||||
# Type alias for valid children of example groups.
|
|
||||||
# NOTE: `NestedExampleGroupBuilder` is used instead of `ExampleGroupBuilder`.
|
|
||||||
# That is because `RootExampleGroupBuilder` also inherits from this class,
|
|
||||||
# and the root example group can't be a child.
|
|
||||||
alias Child = ExampleFactory | NestedExampleGroupBuilder
|
|
||||||
|
|
||||||
private getter doubles = {} of Symbol => DoubleFactory
|
|
||||||
|
|
||||||
# Factories and builders for all examples and groups.
|
|
||||||
@children = [] of Child
|
|
||||||
|
|
||||||
# Hooks added to the group so far.
|
|
||||||
@before_all_hooks = [] of ->
|
|
||||||
@before_each_hooks = [] of ->
|
|
||||||
@after_all_hooks = [] of ->
|
|
||||||
@after_each_hooks = [] of ->
|
|
||||||
@around_each_hooks = [] of Proc(Nil) ->
|
|
||||||
|
|
||||||
# Pre and post conditions so far.
|
|
||||||
@pre_conditions = [] of ->
|
|
||||||
@post_conditions = [] of ->
|
|
||||||
|
|
||||||
# Adds a new example factory or group builder to this group.
|
|
||||||
def add_child(child : Child)
|
|
||||||
@children << child
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a hook to run before all examples (and nested examples) in this group.
|
|
||||||
def add_before_all_hook(block : ->) : Nil
|
|
||||||
@before_all_hooks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a hook to run before each example (and nested example) in this group.
|
|
||||||
def add_before_each_hook(block : ->) : Nil
|
|
||||||
@before_each_hooks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a hook to run after all examples (and nested examples) in this group.
|
|
||||||
def add_after_all_hook(block : ->) : Nil
|
|
||||||
@after_all_hooks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a hook to run after each example (and nested example) in this group.
|
|
||||||
def add_after_each_hook(block : ->) : Nil
|
|
||||||
@after_each_hooks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a hook to run around each example (and nested example) in this group.
|
|
||||||
# The block of code will be given another proc as an argument.
|
|
||||||
# It is expected that the block will call the proc.
|
|
||||||
def add_around_each_hook(block : Proc(Nil) ->) : Nil
|
|
||||||
@around_each_hooks << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a pre-condition to run at the start of every example in this group.
|
|
||||||
def add_pre_condition(block : ->) : Nil
|
|
||||||
@pre_conditions << block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a post-condition to run at the end of every example in this group.
|
|
||||||
def add_post_condition(block : ->) : Nil
|
|
||||||
@post_conditions << block
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_double(id : Symbol, double_factory : DoubleFactory) : Nil
|
|
||||||
@doubles[id] = double_factory
|
|
||||||
end
|
|
||||||
|
|
||||||
# Constructs an `ExampleHooks` instance with all the hooks defined for this group.
|
|
||||||
# This method should be called only when the group is being built,
|
|
||||||
# otherwise some hooks may be missing.
|
|
||||||
private def hooks
|
|
||||||
ExampleHooks.new(
|
|
||||||
@before_all_hooks,
|
|
||||||
@before_each_hooks,
|
|
||||||
@after_all_hooks,
|
|
||||||
@after_each_hooks,
|
|
||||||
@around_each_hooks
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Constructs an `ExampleConditions` instance
|
|
||||||
# with all the pre- and post-conditions defined for this group.
|
|
||||||
# This method should be called only when the group is being built,
|
|
||||||
# otherwise some conditions may be missing.
|
|
||||||
private def conditions
|
|
||||||
ExampleConditions.new(@pre_conditions, @post_conditions)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
64
src/spectator/dsl/examples.cr
Normal file
64
src/spectator/dsl/examples.cr
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
require "../source"
|
||||||
|
require "../spec_builder"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
module DSL
|
||||||
|
macro it(description, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
{% if block.is_a?(Nop) %}
|
||||||
|
{% if description.is_a?(Call) %}
|
||||||
|
def %run
|
||||||
|
{{description}}
|
||||||
|
end
|
||||||
|
{% else %}
|
||||||
|
{% raise "Unrecognized syntax: `it #{description}` at #{_source_file}:#{_source_line}" %}
|
||||||
|
{% end %}
|
||||||
|
{% else %}
|
||||||
|
def %run
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
|
::Spectator::SpecBuilder.add_example(
|
||||||
|
{{description.is_a?(StringLiteral) ? description : description.stringify}},
|
||||||
|
%source,
|
||||||
|
{{@type.name}}
|
||||||
|
) { |test| test.as({{@type.name}}).%run }
|
||||||
|
end
|
||||||
|
|
||||||
|
macro specify(description, &block)
|
||||||
|
it({{description}}) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro pending(description, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
{% if block.is_a?(Nop) %}
|
||||||
|
{% if description.is_a?(Call) %}
|
||||||
|
def %run
|
||||||
|
{{description}}
|
||||||
|
end
|
||||||
|
{% else %}
|
||||||
|
{% raise "Unrecognized syntax: `pending #{description}` at #{_source_file}:#{_source_line}" %}
|
||||||
|
{% end %}
|
||||||
|
{% else %}
|
||||||
|
def %run
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
|
::Spectator::SpecBuilder.add_pending_example(
|
||||||
|
{{description.is_a?(StringLiteral) ? description : description.stringify}},
|
||||||
|
%source,
|
||||||
|
{{@type.name}}
|
||||||
|
) { |test| test.as({{@type.name}}).%run }
|
||||||
|
end
|
||||||
|
|
||||||
|
macro skip(description, &block)
|
||||||
|
pending({{description}}) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro xit(description, &block)
|
||||||
|
pending({{description}}) {{block}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
144
src/spectator/dsl/groups.cr
Normal file
144
src/spectator/dsl/groups.cr
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
require "../spec_builder"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
module DSL
|
||||||
|
macro context(what, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
class Context%context < {{@type.id}}
|
||||||
|
{%
|
||||||
|
description = if what.is_a?(StringLiteral)
|
||||||
|
if what.starts_with?("#") || what.starts_with?(".")
|
||||||
|
what.id.symbolize
|
||||||
|
else
|
||||||
|
what
|
||||||
|
end
|
||||||
|
else
|
||||||
|
what.symbolize
|
||||||
|
end
|
||||||
|
%}
|
||||||
|
|
||||||
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
|
::Spectator::SpecBuilder.start_group({{description}}, %source)
|
||||||
|
|
||||||
|
{% if what.is_a?(Path) || what.is_a?(Generic) %}
|
||||||
|
macro described_class
|
||||||
|
{{what}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def subject(*args)
|
||||||
|
described_class.new(*args)
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{{block.body}}
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.end_group
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro describe(what, &block)
|
||||||
|
context({{what}}) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
||||||
|
|
||||||
|
def %collection
|
||||||
|
{{collection}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def %to_a
|
||||||
|
{% if count %}
|
||||||
|
%collection.first({{count}})
|
||||||
|
{% else %}
|
||||||
|
%collection.to_a
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
|
||||||
|
class Context%sample < {{@type.id}}
|
||||||
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
|
::Spectator::SpecBuilder.start_sample_group({{collection.stringify}}, %source, :%sample, {{name.stringify}}) do |values|
|
||||||
|
sample = {{@type.id}}.new(values)
|
||||||
|
sample.%to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def {{name}}
|
||||||
|
@spectator_test_values.get_value(:%sample, typeof(%to_a.first))
|
||||||
|
end
|
||||||
|
|
||||||
|
{{block.body}}
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.end_group
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro random_sample(collection, count = nil, _source_file = __FILE__, _source_line = __LINE__, &block)
|
||||||
|
{% name = block.args.empty? ? :value.id : block.args.first.id %}
|
||||||
|
|
||||||
|
def %collection
|
||||||
|
{{collection}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def %to_a
|
||||||
|
{% if count %}
|
||||||
|
%collection.first({{count}})
|
||||||
|
{% else %}
|
||||||
|
%collection.to_a
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
|
||||||
|
class Context%sample < {{@type.id}}
|
||||||
|
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
|
||||||
|
::Spectator::SpecBuilder.start_sample_group({{collection.stringify}}, %source, :%sample, {{name.stringify}}) do |values|
|
||||||
|
sample = {{@type.id}}.new(values)
|
||||||
|
collection = sample.%to_a
|
||||||
|
{% if count %}
|
||||||
|
collection.sample({{count}}, ::Spectator.random)
|
||||||
|
{% else %}
|
||||||
|
collection.shuffle(::Spectator.random)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
|
||||||
|
def {{name}}
|
||||||
|
@spectator_test_values.get_value(:%sample, typeof(%to_a.first))
|
||||||
|
end
|
||||||
|
|
||||||
|
{{block.body}}
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.end_group
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro given(*assignments, &block)
|
||||||
|
context({{assignments.splat.stringify}}) do
|
||||||
|
{% for assignment in assignments %}
|
||||||
|
let({{assignment.target}}) { {{assignment.value}} }
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
{% # Trick to get the contents of the block as an array of nodes.
|
||||||
|
# If there are multiple expressions/statements in the block,
|
||||||
|
# then the body will be a `Expressions` type.
|
||||||
|
# If there's only one expression, then the body is just that.
|
||||||
|
body = if block.is_a?(Nop)
|
||||||
|
raise "Missing block for 'given'"
|
||||||
|
elsif block.body.is_a?(Expressions)
|
||||||
|
# Get the expressions, which is already an array.
|
||||||
|
block.body.expressions
|
||||||
|
else
|
||||||
|
# Wrap the expression in an array.
|
||||||
|
[block.body]
|
||||||
|
end %}
|
||||||
|
|
||||||
|
{% for item in body %}
|
||||||
|
# If the item starts with "it", then leave it as-is.
|
||||||
|
# Otherwise, prefix it with "it"
|
||||||
|
# and treat it as the one-liner "it" syntax.
|
||||||
|
{% if item.is_a?(Call) && item.name == :it.id %}
|
||||||
|
{{item}}
|
||||||
|
{% else %}
|
||||||
|
it {{item}}
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
79
src/spectator/dsl/hooks.cr
Normal file
79
src/spectator/dsl/hooks.cr
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
module Spectator
|
||||||
|
module DSL
|
||||||
|
macro before_each(&block)
|
||||||
|
def %hook({{block.args.splat}}) : Nil
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.add_before_each_hook do |test, example|
|
||||||
|
cast_test = test.as({{@type.id}})
|
||||||
|
{% if block.args.empty? %}
|
||||||
|
cast_test.%hook
|
||||||
|
{% else %}
|
||||||
|
cast_test.%hook(example)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro after_each(&block)
|
||||||
|
def %hook({{block.args.splat}}) : Nil
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.add_after_each_hook do |test, example|
|
||||||
|
cast_test = test.as({{@type.id}})
|
||||||
|
{% if block.args.empty? %}
|
||||||
|
cast_test.%hook
|
||||||
|
{% else %}
|
||||||
|
cast_test.%hook(example)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro before_all(&block)
|
||||||
|
::Spectator::SpecBuilder.add_before_all_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro after_all(&block)
|
||||||
|
::Spectator::SpecBuilder.add_after_all_hook {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro around_each(&block)
|
||||||
|
def %hook({{block.args.splat}}) : Nil
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.add_around_each_hook { |test, proc| test.as({{@type.id}}).%hook(proc) }
|
||||||
|
end
|
||||||
|
|
||||||
|
macro pre_condition(&block)
|
||||||
|
def %hook({{block.args.splat}}) : Nil
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.add_pre_condition do |test, example|
|
||||||
|
cast_test = test.as({{@type.id}})
|
||||||
|
{% if block.args.empty? %}
|
||||||
|
cast_test.%hook
|
||||||
|
{% else %}
|
||||||
|
cast_test.%hook(example)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro post_condition(&block)
|
||||||
|
def %hook({{block.args.splat}}) : Nil
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
::Spectator::SpecBuilder.add_post_condition do |test, example|
|
||||||
|
cast_test = test.as({{@type.id}})
|
||||||
|
{% if block.args.empty? %}
|
||||||
|
cast_test.%hook
|
||||||
|
{% else %}
|
||||||
|
cast_test.%hook(example)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,9 +2,8 @@ require "../matchers"
|
||||||
require "../test_block"
|
require "../test_block"
|
||||||
require "../test_value"
|
require "../test_value"
|
||||||
|
|
||||||
module Spectator::DSL
|
module Spectator
|
||||||
# Methods for defining matchers for expectations.
|
module DSL
|
||||||
module MatcherDSL
|
|
||||||
# Indicates that some value should equal another.
|
# Indicates that some value should equal another.
|
||||||
# The == operator is used for this check.
|
# The == operator is used for this check.
|
||||||
# The value passed to this method is the expected value.
|
# The value passed to this method is the expected value.
|
|
@ -1,38 +0,0 @@
|
||||||
module Spectator::DSL
|
|
||||||
# Standard example group builder.
|
|
||||||
# Creates groups of examples and nested groups.
|
|
||||||
class NestedExampleGroupBuilder < ExampleGroupBuilder
|
|
||||||
# Creates a new group builder.
|
|
||||||
# The value for *what* should be the context for the group.
|
|
||||||
#
|
|
||||||
# For example, in these samples:
|
|
||||||
# ```
|
|
||||||
# describe String do
|
|
||||||
# # ...
|
|
||||||
# context "with an empty string" do
|
|
||||||
# # ...
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# ```
|
|
||||||
# The value would be "String" for the describe block
|
|
||||||
# and "with an empty string" for the context block.
|
|
||||||
# Use a `Symbol` when referencing a type name.
|
|
||||||
def initialize(@what : Symbol | String)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Builds the example group.
|
|
||||||
# A new `NestedExampleGroup` will be returned
|
|
||||||
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
|
||||||
# The *parent* should be the group that contains this group.
|
|
||||||
# The *sample_values* will be given to all of the examples (and groups) nested in this group.
|
|
||||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
|
||||||
NestedExampleGroup.new(@what, parent, hooks, conditions, doubles).tap do |group|
|
|
||||||
# Set the group's children to built versions of the children from this instance.
|
|
||||||
group.children = @children.map do |child|
|
|
||||||
# Build the child and up-cast to prevent type errors.
|
|
||||||
child.build(group, sample_values).as(ExampleComponent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
module Spectator::DSL
|
|
||||||
# Top-level example group builder.
|
|
||||||
# There should only be one instance of this class,
|
|
||||||
# and it should be at the top of the spec "tree".
|
|
||||||
class RootExampleGroupBuilder < ExampleGroupBuilder
|
|
||||||
# Creates a `RootExampleGroup` which can have instances of `Example` and `ExampleGroup` nested in it.
|
|
||||||
# The *sample_values* will be given to all of the examples (and groups) nested in this group.
|
|
||||||
def build(sample_values : Internals::SampleValues) : RootExampleGroup
|
|
||||||
RootExampleGroup.new(hooks, conditions, doubles).tap do |group|
|
|
||||||
# Set the group's children to built versions of the children from this instance.
|
|
||||||
group.children = @children.map do |child|
|
|
||||||
# Build the child and up-cast to prevent type errors.
|
|
||||||
child.build(group, sample_values).as(ExampleComponent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,73 +0,0 @@
|
||||||
require "./nested_example_group_builder"
|
|
||||||
|
|
||||||
module Spectator::DSL
|
|
||||||
# Specialized example group builder for "sample" groups.
|
|
||||||
# The type parameter `C` is the type to instantiate to create the collection.
|
|
||||||
# The type parameter `T` should be the type of each element in the sample collection.
|
|
||||||
# This builder creates a container group with groups inside for each item in the collection.
|
|
||||||
# The hooks are only defined for the container group.
|
|
||||||
# By doing so, the hooks are defined once, are inherited, and use less memory.
|
|
||||||
class SampleExampleGroupBuilder(C, T) < NestedExampleGroupBuilder
|
|
||||||
# Creates a new group builder.
|
|
||||||
# The value for *what* should be the text the user specified for the collection.
|
|
||||||
# The *collection_type* is the type to create that will produce the items.
|
|
||||||
# The *collection_builder* is a proc that takes an instance of *collection_type*
|
|
||||||
# and returns an actual array of items to create examples for.
|
|
||||||
# The *name* is the variable name that the user accesses the current collection item with.
|
|
||||||
#
|
|
||||||
# In this code:
|
|
||||||
# ```
|
|
||||||
# sample random_integers do |integer|
|
|
||||||
# # ...
|
|
||||||
# end
|
|
||||||
# ```
|
|
||||||
# The *what* would be "random_integers"
|
|
||||||
# and the collection would contain the items returned by calling *random_integers*.
|
|
||||||
# The *name* would be "integer".
|
|
||||||
#
|
|
||||||
# The *symbol* is passed along to the sample values
|
|
||||||
# so that the example code can retrieve the current item from the collection.
|
|
||||||
# The symbol should be unique.
|
|
||||||
def initialize(what : String, @collection_type : C.class, @collection_builder : C -> Array(T),
|
|
||||||
@name : String, @symbol : Symbol)
|
|
||||||
super(what)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Builds the example group.
|
|
||||||
# A new `NestedExampleGroup` will be returned
|
|
||||||
# which can have instances of `Example` and `ExampleGroup` nested in it.
|
|
||||||
# The *parent* should be the group that contains this group.
|
|
||||||
# The *sample_values* will be given to all of the examples (and groups) nested in this group.
|
|
||||||
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
|
|
||||||
collection = @collection_builder.call(@collection_type.new(sample_values))
|
|
||||||
|
|
||||||
# This creates the container for the sub-groups.
|
|
||||||
# The hooks are defined here, instead of repeating for each sub-group.
|
|
||||||
NestedExampleGroup.new(@what, parent, hooks, conditions, doubles).tap do |group|
|
|
||||||
# Set the container group's children to be sub-groups for each item in the collection.
|
|
||||||
group.children = collection.map do |value|
|
|
||||||
# Create a sub-group for each item in the collection.
|
|
||||||
build_sub_group(group, sample_values, value).as(ExampleComponent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Builds a sub-group for one item in the collection.
|
|
||||||
# The *parent* should be the container group currently being built by the `#build` call.
|
|
||||||
# The *sample_values* should be the same as what was passed to the `#build` call.
|
|
||||||
# The *value* is the current item in the collection.
|
|
||||||
# The value will be added to the sample values for the sub-group,
|
|
||||||
# so it shouldn't be added prior to calling this method.
|
|
||||||
private def build_sub_group(parent : ExampleGroup, sample_values : Internals::SampleValues, value : T) : NestedExampleGroup
|
|
||||||
# Add the value to sample values for this sub-group.
|
|
||||||
sub_values = sample_values.add(@symbol, @name, value)
|
|
||||||
NestedExampleGroup.new(value.to_s, parent, ExampleHooks.empty, ExampleConditions.empty, {} of Symbol => DoubleFactory).tap do |group|
|
|
||||||
# Set the sub-group's children to built versions of the children from this instance.
|
|
||||||
group.children = @children.map do |child|
|
|
||||||
# Build the child and up-cast to prevent type errors.
|
|
||||||
child.build(group, sub_values).as(ExampleComponent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
File diff suppressed because it is too large
Load diff
58
src/spectator/dsl/values.cr
Normal file
58
src/spectator/dsl/values.cr
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
module Spectator
|
||||||
|
module DSL
|
||||||
|
macro let(name, &block)
|
||||||
|
def %value
|
||||||
|
{{block.body}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@%wrapper : ::Spectator::ValueWrapper?
|
||||||
|
|
||||||
|
def {{name.id}}
|
||||||
|
if (wrapper = @%wrapper)
|
||||||
|
wrapper.as(::Spectator::TypedValueWrapper(typeof(%value))).value
|
||||||
|
else
|
||||||
|
%value.tap do |value|
|
||||||
|
@%wrapper = ::Spectator::TypedValueWrapper.new(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro let!(name, &block)
|
||||||
|
# TODO: Doesn't work with late-defined values (let).
|
||||||
|
@%value = {{yield}}
|
||||||
|
|
||||||
|
def {{name.id}}
|
||||||
|
@%value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro subject(&block)
|
||||||
|
{% if block.is_a?(Nop) %}
|
||||||
|
self.subject
|
||||||
|
{% else %}
|
||||||
|
let(:subject) {{block}}
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro subject(name, &block)
|
||||||
|
let({{name.id}}) {{block}}
|
||||||
|
|
||||||
|
def subject
|
||||||
|
{{name.id}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro subject!(&block)
|
||||||
|
let!(:subject) {{block}}
|
||||||
|
end
|
||||||
|
|
||||||
|
macro subject!(name, &block)
|
||||||
|
let!({{name.id}}) {{block}}
|
||||||
|
|
||||||
|
def subject
|
||||||
|
{{name.id}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,37 +0,0 @@
|
||||||
require "./runnable_example"
|
|
||||||
|
|
||||||
module Spectator
|
|
||||||
# Example that does nothing.
|
|
||||||
# This is to workaround a Crystal compiler bug.
|
|
||||||
# See: [Issue 4225](https://github.com/crystal-lang/crystal/issues/4225)
|
|
||||||
# If there are no concrete implementations of an abstract class,
|
|
||||||
# the compiler gives an error.
|
|
||||||
# The error indicates an abstract method is undefined.
|
|
||||||
# This class shouldn't be used, it's just to trick the compiler.
|
|
||||||
private class DummyExample < RunnableExample
|
|
||||||
# Dummy description.
|
|
||||||
def what : Symbol | String
|
|
||||||
"DUMMY"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy symbolic flag.
|
|
||||||
def symbolic? : Bool
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy source.
|
|
||||||
def source : Source
|
|
||||||
Source.new(__FILE__, __LINE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy instance.
|
|
||||||
def instance
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dummy run that does nothing.
|
|
||||||
def run_instance
|
|
||||||
raise "You shouldn't be running this."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +1,9 @@
|
||||||
require "./example_component"
|
require "./example_component"
|
||||||
|
require "./test_wrapper"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Base class for all types of examples.
|
# Base class for all types of examples.
|
||||||
# Concrete types must implement the `#run_impl, `#what`, `#instance`, and `#source` methods.
|
# Concrete types must implement the `#run_impl` method.
|
||||||
abstract class Example < ExampleComponent
|
abstract class Example < ExampleComponent
|
||||||
@finished = false
|
@finished = false
|
||||||
|
|
||||||
|
@ -15,10 +16,23 @@ module Spectator
|
||||||
getter group : ExampleGroup
|
getter group : ExampleGroup
|
||||||
|
|
||||||
# Retrieves the internal wrapped instance.
|
# Retrieves the internal wrapped instance.
|
||||||
abstract def instance
|
protected getter test_wrapper : TestWrapper
|
||||||
|
|
||||||
# Source where the example originated from.
|
# Source where the example originated from.
|
||||||
abstract def source : Source
|
def source : Source
|
||||||
|
@test_wrapper.source
|
||||||
|
end
|
||||||
|
|
||||||
|
def description : String | Symbol
|
||||||
|
@test_wrapper.description
|
||||||
|
end
|
||||||
|
|
||||||
|
def symbolic? : Bool
|
||||||
|
description = @test_wrapper.description
|
||||||
|
description.starts_with?('#') || description.starts_with?('.')
|
||||||
|
end
|
||||||
|
|
||||||
|
abstract def run_impl
|
||||||
|
|
||||||
protected getter sample_values : Internals::SampleValues
|
protected getter sample_values : Internals::SampleValues
|
||||||
|
|
||||||
|
@ -28,17 +42,14 @@ module Spectator
|
||||||
# An exception is raised if an attempt is made to run it more than once.
|
# An exception is raised if an attempt is made to run it more than once.
|
||||||
def run : Result
|
def run : Result
|
||||||
raise "Attempted to run example more than once (#{self})" if finished?
|
raise "Attempted to run example more than once (#{self})" if finished?
|
||||||
@finished = true
|
|
||||||
run_impl
|
run_impl
|
||||||
|
ensure
|
||||||
|
@finished = true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Implementation-specific for running the example code.
|
|
||||||
private abstract def run_impl : Result
|
|
||||||
|
|
||||||
# Creates the base of the example.
|
# Creates the base of the example.
|
||||||
# The group should be the example group the example belongs to.
|
# The group should be the example group the example belongs to.
|
||||||
# The *sample_values* are passed to the example code.
|
def initialize(@group, @test_wrapper)
|
||||||
def initialize(@group, @sample_values)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Indicates there is only one example to run.
|
# Indicates there is only one example to run.
|
||||||
|
@ -57,7 +68,7 @@ module Spectator
|
||||||
def to_s(io)
|
def to_s(io)
|
||||||
@group.to_s(io)
|
@group.to_s(io)
|
||||||
io << ' ' unless symbolic? && @group.symbolic?
|
io << ' ' unless symbolic? && @group.symbolic?
|
||||||
io << what
|
io << description
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates the JSON representation of the example,
|
# Creates the JSON representation of the example,
|
||||||
|
|
|
@ -3,7 +3,13 @@ module Spectator
|
||||||
# This is used as the base node type for the composite design pattern.
|
# This is used as the base node type for the composite design pattern.
|
||||||
abstract class ExampleComponent
|
abstract class ExampleComponent
|
||||||
# Text that describes the context or test.
|
# Text that describes the context or test.
|
||||||
abstract def what : Symbol | String
|
abstract def description : Symbol | String
|
||||||
|
|
||||||
|
def full_description
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
abstract def source : Source
|
||||||
|
|
||||||
# Indicates whether the example (or group) has been completely run.
|
# Indicates whether the example (or group) has been completely run.
|
||||||
abstract def finished? : Bool
|
abstract def finished? : Bool
|
||||||
|
|
|
@ -10,28 +10,32 @@ module Spectator
|
||||||
# This will effectively run nothing extra while running a test.
|
# This will effectively run nothing extra while running a test.
|
||||||
def self.empty
|
def self.empty
|
||||||
new(
|
new(
|
||||||
[] of ->,
|
[] of TestMetaMethod,
|
||||||
[] of ->
|
[] of TestMetaMethod
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a new set of conditions.
|
# Creates a new set of conditions.
|
||||||
def initialize(
|
def initialize(
|
||||||
@pre_conditions : Array(->),
|
@pre_conditions : Array(TestMetaMethod),
|
||||||
@post_conditions : Array(->)
|
@post_conditions : Array(TestMetaMethod)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs all pre-condition checks.
|
# Runs all pre-condition checks.
|
||||||
# These should be run before every test.
|
# These should be run before every test.
|
||||||
def run_pre_conditions
|
def run_pre_conditions(wrapper : TestWrapper, example : Example)
|
||||||
@pre_conditions.each &.call
|
@pre_conditions.each do |hook|
|
||||||
|
wrapper.call(hook, example)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs all post-condition checks.
|
# Runs all post-condition checks.
|
||||||
# These should be run after every test.
|
# These should be run after every test.
|
||||||
def run_post_conditions
|
def run_post_conditions(wrapper : TestWrapper, example : Example)
|
||||||
@post_conditions.each &.call
|
@post_conditions.each do |hook|
|
||||||
|
wrapper.call(hook, example)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,13 +15,7 @@ module Spectator
|
||||||
include Enumerable(ExampleComponent)
|
include Enumerable(ExampleComponent)
|
||||||
include Iterable(ExampleComponent)
|
include Iterable(ExampleComponent)
|
||||||
|
|
||||||
# Creates the example group.
|
|
||||||
# The hooks are stored to be triggered later.
|
|
||||||
def initialize(@hooks : ExampleHooks, @conditions : ExampleConditions, @doubles : Hash(Symbol, DSL::DoubleFactory))
|
|
||||||
@example_count = 0
|
@example_count = 0
|
||||||
@before_all_hooks_run = false
|
|
||||||
@after_all_hooks_run = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Retrieves the children in the group.
|
# Retrieves the children in the group.
|
||||||
# This only returns the direct descends (non-recursive).
|
# This only returns the direct descends (non-recursive).
|
||||||
|
@ -45,6 +39,11 @@ module Spectator
|
||||||
@doubles[id].build(sample_values)
|
@doubles[id].build(sample_values)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
getter context
|
||||||
|
|
||||||
|
def initialize(@context : TestContext)
|
||||||
|
end
|
||||||
|
|
||||||
# Yields each direct descendant.
|
# Yields each direct descendant.
|
||||||
def each
|
def each
|
||||||
children.each do |child|
|
children.each do |child|
|
||||||
|
@ -128,72 +127,5 @@ module Spectator
|
||||||
def finished? : Bool
|
def finished? : Bool
|
||||||
children.all?(&.finished?)
|
children.all?(&.finished?)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs all of the "before-each" and "before-all" hooks.
|
|
||||||
# This should run prior to every example in the group.
|
|
||||||
def run_before_hooks
|
|
||||||
run_before_all_hooks
|
|
||||||
run_before_each_hooks
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "before-all" hooks.
|
|
||||||
# This should run prior to any examples in the group.
|
|
||||||
# The hooks will be run only once.
|
|
||||||
# Subsequent calls to this method will do nothing.
|
|
||||||
protected def run_before_all_hooks : Nil
|
|
||||||
return if @before_all_hooks_run
|
|
||||||
@hooks.run_before_all
|
|
||||||
@before_all_hooks_run = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "before-each" hooks.
|
|
||||||
# This method should run prior to every example in the group.
|
|
||||||
protected def run_before_each_hooks : Nil
|
|
||||||
@hooks.run_before_each
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "after-all" and "after-each" hooks.
|
|
||||||
# This should run following every example in the group.
|
|
||||||
def run_after_hooks
|
|
||||||
run_after_each_hooks
|
|
||||||
run_after_all_hooks
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "after-all" hooks.
|
|
||||||
# This should run following all examples in the group.
|
|
||||||
# The hooks will be run only once,
|
|
||||||
# and only after all examples in the group have finished.
|
|
||||||
# Subsequent calls after the hooks have been run will do nothing.
|
|
||||||
protected def run_after_all_hooks(ignore_unfinished = false) : Nil
|
|
||||||
return if @after_all_hooks_run
|
|
||||||
return unless ignore_unfinished || finished?
|
|
||||||
|
|
||||||
@hooks.run_after_all
|
|
||||||
@after_all_hooks_run = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "after-each" hooks.
|
|
||||||
# This method should run following every example in the group.
|
|
||||||
protected def run_after_each_hooks : Nil
|
|
||||||
@hooks.run_after_each
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a proc that runs the "around-each" hooks
|
|
||||||
# in addition to a block passed to this method.
|
|
||||||
# To call the block and all "around-each" hooks,
|
|
||||||
# just invoke `Proc#call` on the returned proc.
|
|
||||||
def wrap_around_each_hooks(&block : ->) : ->
|
|
||||||
@hooks.wrap_around_each(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the pre-conditions for an example.
|
|
||||||
def run_pre_conditions
|
|
||||||
@conditions.run_pre_conditions
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the post-conditions for an example.
|
|
||||||
def run_post_conditions
|
|
||||||
@conditions.run_post_conditions
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
module Spectator
|
module Spectator
|
||||||
|
alias TestMetaMethod = ::SpectatorTest, Example ->
|
||||||
|
|
||||||
# Collection of hooks that run at various times throughout testing.
|
# Collection of hooks that run at various times throughout testing.
|
||||||
# A hook is just a `Proc` (code block) that runs at a specified time.
|
# A hook is just a `Proc` (code block) that runs at a specified time.
|
||||||
class ExampleHooks
|
class ExampleHooks
|
||||||
|
@ -7,20 +9,20 @@ module Spectator
|
||||||
def self.empty
|
def self.empty
|
||||||
new(
|
new(
|
||||||
[] of ->,
|
[] of ->,
|
||||||
|
[] of TestMetaMethod,
|
||||||
[] of ->,
|
[] of ->,
|
||||||
[] of ->,
|
[] of TestMetaMethod,
|
||||||
[] of ->,
|
[] of ::SpectatorTest, Proc(Nil) ->
|
||||||
[] of Proc(Nil) ->
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a new set of hooks.
|
# Creates a new set of hooks.
|
||||||
def initialize(
|
def initialize(
|
||||||
@before_all : Array(->),
|
@before_all : Array(->),
|
||||||
@before_each : Array(->),
|
@before_each : Array(TestMetaMethod),
|
||||||
@after_all : Array(->),
|
@after_all : Array(->),
|
||||||
@after_each : Array(->),
|
@after_each : Array(TestMetaMethod),
|
||||||
@around_each : Array(Proc(Nil) ->)
|
@around_each : Array(::SpectatorTest, Proc(Nil) ->)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,8 +34,10 @@ module Spectator
|
||||||
|
|
||||||
# Runs all "before-each" hooks.
|
# Runs all "before-each" hooks.
|
||||||
# These hooks should be run every time before each example in a group.
|
# These hooks should be run every time before each example in a group.
|
||||||
def run_before_each
|
def run_before_each(wrapper : TestWrapper, example : Example)
|
||||||
@before_each.each &.call
|
@before_each.each do |hook|
|
||||||
|
wrapper.call(hook, example)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs all "after-all" hooks.
|
# Runs all "after-all" hooks.
|
||||||
|
@ -44,27 +48,28 @@ module Spectator
|
||||||
|
|
||||||
# Runs all "after-all" hooks.
|
# Runs all "after-all" hooks.
|
||||||
# These hooks should be run every time after each example in a group.
|
# These hooks should be run every time after each example in a group.
|
||||||
def run_after_each
|
def run_after_each(wrapper : TestWrapper, example : Example)
|
||||||
@after_each.each &.call
|
@after_each.each do |hook|
|
||||||
|
wrapper.call(hook, example)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a proc that runs the "around-each" hooks
|
# Creates a proc that runs the "around-each" hooks
|
||||||
# in addition to a block passed to this method.
|
# in addition to a block passed to this method.
|
||||||
# To call the block and all "around-each" hooks,
|
# To call the block and all "around-each" hooks,
|
||||||
# just invoke `Proc#call` on the returned proc.
|
# just invoke `Proc#call` on the returned proc.
|
||||||
def wrap_around_each(&block : ->) : ->
|
def wrap_around_each(test, block : ->)
|
||||||
wrapper = block
|
wrapper = block
|
||||||
# Must wrap in reverse order,
|
# Must wrap in reverse order,
|
||||||
# otherwise hooks will run in the wrong order.
|
# otherwise hooks will run in the wrong order.
|
||||||
@around_each.reverse_each do |hook|
|
@around_each.reverse_each do |hook|
|
||||||
wrapper = wrap_proc(hook, wrapper)
|
wrapper = wrap_foo(test, hook, wrapper)
|
||||||
end
|
end
|
||||||
wrapper
|
wrapper
|
||||||
end
|
end
|
||||||
|
|
||||||
# Utility method for wrapping one proc with another.
|
private def wrap_foo(test, hook, wrapper)
|
||||||
private def wrap_proc(inner : Proc(Nil) ->, wrapper : ->)
|
->{ hook.call(test, wrapper) }
|
||||||
->{ inner.call(wrapper) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,7 +40,7 @@ module Spectator::Expectations
|
||||||
# Reports an expectation to the current harness.
|
# Reports an expectation to the current harness.
|
||||||
private def report(match_data : Matchers::MatchData)
|
private def report(match_data : Matchers::MatchData)
|
||||||
expectation = Expectation.new(match_data, @source)
|
expectation = Expectation.new(match_data, @source)
|
||||||
Internals::Harness.current.report_expectation(expectation)
|
Harness.current.report_expectation(expectation)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,7 +28,7 @@ module Spectator::Formatting
|
||||||
# Produces a single character output based on a result.
|
# Produces a single character output based on a result.
|
||||||
def end_example(result)
|
def end_example(result)
|
||||||
@previous_hierarchy.size.times { @io.print INDENT }
|
@previous_hierarchy.size.times { @io.print INDENT }
|
||||||
@io.puts result.call(Color) { result.example.what }
|
@io.puts result.call(Color) { result.example.description }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Produces a list of groups making up the hierarchy for an example.
|
# Produces a list of groups making up the hierarchy for an example.
|
||||||
|
@ -56,7 +56,7 @@ module Spectator::Formatting
|
||||||
private def print_sub_hierarchy(index, sub_hierarchy)
|
private def print_sub_hierarchy(index, sub_hierarchy)
|
||||||
sub_hierarchy.each do |group|
|
sub_hierarchy.each do |group|
|
||||||
index.times { @io.print INDENT }
|
index.times { @io.print INDENT }
|
||||||
@io.puts group.what
|
@io.puts group.description
|
||||||
index += 1
|
index += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module Spectator::Internals
|
module Spectator
|
||||||
# Helper class that acts as a gateway between example code and the test framework.
|
# Helper class that acts as a gateway between example code and the test framework.
|
||||||
# Every example must be invoked by passing it to `#run`.
|
# Every example must be invoked by passing it to `#run`.
|
||||||
# This sets up the harness so that the example code can use it.
|
# This sets up the harness so that the example code can use it.
|
||||||
|
@ -9,7 +9,7 @@ module Spectator::Internals
|
||||||
# ```
|
# ```
|
||||||
# Then from the example code, the harness can be accessed via `#current` like so:
|
# Then from the example code, the harness can be accessed via `#current` like so:
|
||||||
# ```
|
# ```
|
||||||
# harness = ::Spectator::Internals::Harness.current
|
# harness = ::Spectator::Harness.current
|
||||||
# # Do something with the harness.
|
# # Do something with the harness.
|
||||||
# ```
|
# ```
|
||||||
# Of course, the end-user shouldn't see this or work directly with the harness.
|
# Of course, the end-user shouldn't see this or work directly with the harness.
|
||||||
|
@ -34,6 +34,11 @@ module Spectator::Internals
|
||||||
# Retrieves the current running example.
|
# Retrieves the current running example.
|
||||||
getter example : Example
|
getter example : Example
|
||||||
|
|
||||||
|
# Retrieves the group for the current running example.
|
||||||
|
def group
|
||||||
|
example.group
|
||||||
|
end
|
||||||
|
|
||||||
# Reports the outcome of an expectation.
|
# Reports the outcome of an expectation.
|
||||||
# An exception will be raised when a failing result is given.
|
# An exception will be raised when a failing result is given.
|
||||||
def report_expectation(expectation : Expectations::Expectation) : Nil
|
def report_expectation(expectation : Expectations::Expectation) : Nil
|
|
@ -11,18 +11,17 @@
|
||||||
require "openssl"
|
require "openssl"
|
||||||
|
|
||||||
# First the sub-modules.
|
# First the sub-modules.
|
||||||
require "./internals"
|
|
||||||
require "./dsl"
|
require "./dsl"
|
||||||
require "./expectations"
|
require "./expectations"
|
||||||
require "./matchers"
|
require "./matchers"
|
||||||
require "./formatting"
|
require "./formatting"
|
||||||
|
|
||||||
# Then all of the top-level types.
|
# Then all of the top-level types.
|
||||||
|
require "./spec_builder"
|
||||||
require "./example_component"
|
require "./example_component"
|
||||||
require "./example"
|
require "./example"
|
||||||
require "./runnable_example"
|
require "./runnable_example"
|
||||||
require "./pending_example"
|
require "./pending_example"
|
||||||
require "./dummy_example"
|
|
||||||
|
|
||||||
require "./example_conditions"
|
require "./example_conditions"
|
||||||
require "./example_hooks"
|
require "./example_hooks"
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
require "./internals/*"
|
|
||||||
|
|
||||||
module Spectator
|
|
||||||
# Utilities and black magic (hacks) employed by the testing framework.
|
|
||||||
module Internals
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,92 +6,31 @@ module Spectator
|
||||||
class NestedExampleGroup < ExampleGroup
|
class NestedExampleGroup < ExampleGroup
|
||||||
# Description from the user of the group's contents.
|
# Description from the user of the group's contents.
|
||||||
# This is a symbol when referencing a type.
|
# This is a symbol when referencing a type.
|
||||||
getter what : Symbol | String
|
getter description : Symbol | String
|
||||||
|
|
||||||
|
getter source : Source
|
||||||
|
|
||||||
# Group that this is nested in.
|
# Group that this is nested in.
|
||||||
getter parent : ExampleGroup
|
getter parent : ExampleGroup
|
||||||
|
|
||||||
# Creates a new example group.
|
# Creates a new example group.
|
||||||
# The *what* argument is a description from the user.
|
# The *description* argument is a description from the user.
|
||||||
# The *parent* should contain this group.
|
# The *parent* should contain this group.
|
||||||
# After creating this group, the parent's children should be updated.
|
# After creating this group, the parent's children should be updated.
|
||||||
# The parent's children must contain this group,
|
# The parent's children must contain this group,
|
||||||
# otherwise there may be unexpected behavior.
|
# otherwise there may be unexpected behavior.
|
||||||
# The *hooks* are stored to be triggered later.
|
# The *hooks* are stored to be triggered later.
|
||||||
def initialize(@what, @parent, hooks : ExampleHooks, conditions : ExampleConditions, doubles : Hash(Symbol, DSL::DoubleFactory))
|
def initialize(@description, @source, @parent, context)
|
||||||
super(hooks, conditions, doubles)
|
super(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Indicates wheter the group references a type.
|
# Indicates wheter the group references a type.
|
||||||
def symbolic? : Bool
|
def symbolic? : Bool
|
||||||
@what.is_a?(Symbol)
|
@description.is_a?(Symbol)
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "before-all" hooks.
|
|
||||||
# This should run prior to any examples in the group.
|
|
||||||
# The hooks will be run only once.
|
|
||||||
# Subsequent calls to this method will do nothing.
|
|
||||||
# Parent "before-all" hooks will be run first.
|
|
||||||
protected def run_before_all_hooks : Nil
|
|
||||||
parent.run_before_all_hooks
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "before-each" hooks.
|
|
||||||
# This method should run prior to every example in the group.
|
|
||||||
# Parent "before-each" hooks will be run first.
|
|
||||||
protected def run_before_each_hooks : Nil
|
|
||||||
parent.run_before_each_hooks
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "after-all" hooks.
|
|
||||||
# This should run following all examples in the group.
|
|
||||||
# The hooks will be run only once,
|
|
||||||
# and only after all examples in the group have finished.
|
|
||||||
# Subsequent calls after the hooks have been run will do nothing.
|
|
||||||
# Parent "after-all" hooks will be run last.
|
|
||||||
protected def run_after_all_hooks(ignore_unfinished = false) : Nil
|
|
||||||
super
|
|
||||||
parent.run_after_all_hooks(ignore_unfinished)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the "after-each" hooks.
|
|
||||||
# This method should run following every example in the group.
|
|
||||||
# Parent "after-each" hooks will be run last.
|
|
||||||
protected def run_after_each_hooks : Nil
|
|
||||||
super
|
|
||||||
parent.run_after_each_hooks
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a proc that runs the "around-each" hooks
|
|
||||||
# in addition to a block passed to this method.
|
|
||||||
# To call the block and all `around_each` hooks,
|
|
||||||
# just invoke `Proc#call` on the returned proc.
|
|
||||||
# Parent "around-each" hooks will be in the outermost wrappings.
|
|
||||||
def wrap_around_each_hooks(&block : ->) : ->
|
|
||||||
wrapper = super(&block)
|
|
||||||
parent.wrap_around_each_hooks(&wrapper)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the pre-condition checks.
|
|
||||||
# This method should run prior to every example in the group.
|
|
||||||
# Parent pre-conditions will be checked first.
|
|
||||||
def run_pre_conditions : Nil
|
|
||||||
parent.run_pre_conditions
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all of the post-condition checks.
|
|
||||||
# This method should run following every example in the group.
|
|
||||||
# Parent post-conditions will be checked last.
|
|
||||||
def run_post_conditions : Nil
|
|
||||||
super
|
|
||||||
parent.run_post_conditions
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a string representation of the group.
|
# Creates a string representation of the group.
|
||||||
# The string consists of `#what` appended to the parent.
|
# The string consists of `#description` appended to the parent.
|
||||||
# This results in a string like:
|
# This results in a string like:
|
||||||
# ```text
|
# ```text
|
||||||
# Foo#bar does something
|
# Foo#bar does something
|
||||||
|
@ -109,7 +48,7 @@ module Spectator
|
||||||
def to_s(io)
|
def to_s(io)
|
||||||
parent.to_s(io)
|
parent.to_s(io)
|
||||||
io << ' ' unless (symbolic? || parent.is_a?(RootExampleGroup)) && parent.symbolic?
|
io << ' ' unless (symbolic? || parent.is_a?(RootExampleGroup)) && parent.symbolic?
|
||||||
io << what
|
io << description
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "./example"
|
||||||
module Spectator
|
module Spectator
|
||||||
# Common class for all examples marked as pending.
|
# Common class for all examples marked as pending.
|
||||||
# This class will not run example code.
|
# This class will not run example code.
|
||||||
abstract class PendingExample < Example
|
class PendingExample < Example
|
||||||
# Returns a pending result.
|
# Returns a pending result.
|
||||||
private def run_impl : Result
|
private def run_impl : Result
|
||||||
PendingResult.new(self)
|
PendingResult.new(self)
|
||||||
|
|
|
@ -5,8 +5,12 @@ module Spectator
|
||||||
# The root has no parent.
|
# The root has no parent.
|
||||||
class RootExampleGroup < ExampleGroup
|
class RootExampleGroup < ExampleGroup
|
||||||
# Dummy value - this should never be used.
|
# Dummy value - this should never be used.
|
||||||
def what : Symbol | String
|
def description : Symbol | String
|
||||||
"ROOT"
|
:root
|
||||||
|
end
|
||||||
|
|
||||||
|
def source : Source
|
||||||
|
Source.new(__FILE__, __LINE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Indicates that the group is symbolic.
|
# Indicates that the group is symbolic.
|
||||||
|
|
|
@ -1,78 +1,39 @@
|
||||||
require "./example"
|
require "./example"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Common base for all examples that can be run.
|
# Includes all the logic for running example hooks,
|
||||||
# This class includes all the logic for running example hooks,
|
|
||||||
# the example code, and capturing a result.
|
# the example code, and capturing a result.
|
||||||
# Sub-classes need to implement the `#what` and `#run_instance` methods.
|
class RunnableExample < Example
|
||||||
abstract class RunnableExample < Example
|
|
||||||
# Runs the example, hooks, and captures the result
|
# Runs the example, hooks, and captures the result
|
||||||
# and translates to a usable result.
|
# and translates to a usable result.
|
||||||
def run_impl : Result
|
def run_impl : Result
|
||||||
result = capture_result
|
result = capture_result
|
||||||
expectations = Internals::Harness.current.expectations
|
expectations = Harness.current.expectations
|
||||||
translate_result(result, expectations)
|
translate_result(result, expectations)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs the actual test code.
|
|
||||||
private abstract def run_instance
|
|
||||||
|
|
||||||
# Runs the hooks that should be performed before starting the test code.
|
|
||||||
private def run_before_hooks
|
|
||||||
group.run_before_hooks
|
|
||||||
rescue ex
|
|
||||||
# If an error occurs in the before hooks, skip running the example.
|
|
||||||
raise Exception.new("Error encountered while running before hooks", ex)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs the hooks that should be performed after the test code finishes.
|
|
||||||
private def run_after_hooks
|
|
||||||
group.run_after_hooks
|
|
||||||
rescue ex
|
|
||||||
# If an error occurs in the after hooks, elevate it to abort testing.
|
|
||||||
raise Exception.new("Error encountered while running after hooks", ex)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Runs all hooks and the example code.
|
# Runs all hooks and the example code.
|
||||||
# A captured result is returned.
|
# A captured result is returned.
|
||||||
private def capture_result
|
private def capture_result
|
||||||
|
context = group.context
|
||||||
ResultCapture.new.tap do |result|
|
ResultCapture.new.tap do |result|
|
||||||
# Get the proc that will call around-each hooks and the example.
|
context.run_before_hooks(self)
|
||||||
wrapper = wrap_run_example(result)
|
|
||||||
|
|
||||||
run_before_hooks
|
|
||||||
run_wrapper(wrapper)
|
|
||||||
run_after_hooks
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def run_wrapper(wrapper)
|
|
||||||
wrapper.call
|
|
||||||
rescue ex
|
|
||||||
# If an error occurs calling the wrapper,
|
|
||||||
# it means it came from the "around-each" hooks.
|
|
||||||
# This is because the test code is completely wrapped with a begin/rescue block.
|
|
||||||
raise Exception.new("Error encountered while running around hooks", ex)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Creates a proc that runs the test code
|
|
||||||
# and captures the result.
|
|
||||||
private def wrap_run_example(result)
|
|
||||||
# Wrap the method that runs and captures
|
|
||||||
# the test code with the around-each hooks.
|
|
||||||
group.wrap_around_each_hooks do
|
|
||||||
run_example(result)
|
run_example(result)
|
||||||
|
context.run_after_hooks(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Runs the test code and captures the result.
|
# Runs the test code and captures the result.
|
||||||
private def run_example(result)
|
private def run_example(result)
|
||||||
|
context = group.context
|
||||||
|
wrapper = test_wrapper.around_hook(context)
|
||||||
|
|
||||||
# Capture how long it takes to run the test code.
|
# Capture how long it takes to run the test code.
|
||||||
result.elapsed = Time.measure do
|
result.elapsed = Time.measure do
|
||||||
begin
|
begin
|
||||||
group.run_pre_conditions
|
context.run_pre_conditions(self)
|
||||||
run_instance # Actually run the example code.
|
wrapper.call
|
||||||
group.run_post_conditions
|
context.run_post_conditions(self)
|
||||||
rescue ex # Catch all errors and handle them later.
|
rescue ex # Catch all errors and handle them later.
|
||||||
result.error = ex
|
result.error = ex
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require "./harness"
|
||||||
|
|
||||||
module Spectator
|
module Spectator
|
||||||
# Main driver for executing tests and feeding results to formatters.
|
# Main driver for executing tests and feeding results to formatters.
|
||||||
class Runner
|
class Runner
|
||||||
|
@ -35,7 +37,7 @@ module Spectator
|
||||||
result = run_example(example).as(Result)
|
result = run_example(example).as(Result)
|
||||||
results << result
|
results << result
|
||||||
if @config.fail_fast? && result.is_a?(FailedResult)
|
if @config.fail_fast? && result.is_a?(FailedResult)
|
||||||
example.group.run_after_all_hooks(ignore_unfinished: true)
|
example.group.context.run_after_all_hooks(example.group, ignore_unfinished: true)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -57,7 +59,7 @@ module Spectator
|
||||||
result = if @config.dry_run? && example.is_a?(RunnableExample)
|
result = if @config.dry_run? && example.is_a?(RunnableExample)
|
||||||
dry_run_result(example)
|
dry_run_result(example)
|
||||||
else
|
else
|
||||||
Internals::Harness.run(example)
|
Harness.run(example)
|
||||||
end
|
end
|
||||||
@config.each_formatter(&.end_example(result))
|
@config.each_formatter(&.end_example(result))
|
||||||
result
|
result
|
||||||
|
|
|
@ -1,31 +1,14 @@
|
||||||
module Spectator::DSL
|
require "./spec_builder/*"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
# Global builder used to create the runtime instance of the spec.
|
# Global builder used to create the runtime instance of the spec.
|
||||||
# The DSL methods call into this module to generate parts of the spec.
|
# The DSL methods call into this module to generate parts of the spec.
|
||||||
# Once the DSL is done, the `#build` method can be invoked
|
# Once the DSL is done, the `#build` method can be invoked
|
||||||
# to create the entire spec as a runtime instance.
|
# to create the entire spec as a runtime instance.
|
||||||
module Builder
|
module SpecBuilder
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
# Root group that contains all examples and groups in the spec.
|
@@stack = ExampleGroupStack.new
|
||||||
private class_getter root_group = RootExampleGroupBuilder.new
|
|
||||||
|
|
||||||
# Stack for tracking the current group the spec is working in.
|
|
||||||
# The last item (top of the stack) is the current group.
|
|
||||||
# The first item (bottom of the stack) is the root group (`#root_group`).
|
|
||||||
# The root group should never be popped.
|
|
||||||
@@group_stack = Array(ExampleGroupBuilder).new(1, root_group)
|
|
||||||
|
|
||||||
# Retrieves the current group the spec is working in.
|
|
||||||
private def current_group
|
|
||||||
@@group_stack.last
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a new group to the stack.
|
|
||||||
# Calling this method indicates the spec has entered a nested group.
|
|
||||||
private def push_group(group : NestedExampleGroupBuilder)
|
|
||||||
current_group.add_child(group)
|
|
||||||
@@group_stack.push(group)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Begins a new nested group in the spec.
|
# Begins a new nested group in the spec.
|
||||||
# A corresponding `#end_group` call must be made
|
# A corresponding `#end_group` call must be made
|
||||||
|
@ -34,7 +17,7 @@ module Spectator::DSL
|
||||||
# as arguments to this method are passed directly to it.
|
# as arguments to this method are passed directly to it.
|
||||||
def start_group(*args) : Nil
|
def start_group(*args) : Nil
|
||||||
group = NestedExampleGroupBuilder.new(*args)
|
group = NestedExampleGroupBuilder.new(*args)
|
||||||
push_group(group)
|
@@stack.push(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Begins a new sample group in the spec -
|
# Begins a new sample group in the spec -
|
||||||
|
@ -43,9 +26,9 @@ module Spectator::DSL
|
||||||
# when the group being started is finished.
|
# when the group being started is finished.
|
||||||
# See `SampleExampleGroupBuilder#initialize` for the arguments
|
# See `SampleExampleGroupBuilder#initialize` for the arguments
|
||||||
# as arguments to this method are passed directly to it.
|
# as arguments to this method are passed directly to it.
|
||||||
def start_sample_group(*args) : Nil
|
def start_sample_group(*args, &block : TestValues -> Array(T)) : Nil forall T
|
||||||
group = SampleExampleGroupBuilder.new(*args)
|
group = SampleExampleGroupBuilder(T).new(*args, block)
|
||||||
push_group(group)
|
@@stack.push(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Marks the end of a group in the spec.
|
# Marks the end of a group in the spec.
|
||||||
|
@ -53,52 +36,64 @@ module Spectator::DSL
|
||||||
# It is also important to line up the start and end calls.
|
# It is also important to line up the start and end calls.
|
||||||
# Otherwise examples might get placed into wrong groups.
|
# Otherwise examples might get placed into wrong groups.
|
||||||
def end_group : Nil
|
def end_group : Nil
|
||||||
@@group_stack.pop
|
@@stack.pop
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds an example type to the current group.
|
# Adds an example type to the current group.
|
||||||
# The class name of the example should be passed as an argument.
|
# The class name of the example should be passed as an argument.
|
||||||
# The example will be instantiated later.
|
# The example will be instantiated later.
|
||||||
def add_example(example_type : Example.class) : Nil
|
def add_example(description : String, source : Source,
|
||||||
factory = ExampleFactory.new(example_type)
|
example_type : ::SpectatorTest.class, &runner : ::SpectatorTest ->) : Nil
|
||||||
current_group.add_child(factory)
|
builder = ->(values : TestValues) { example_type.new(values).as(::SpectatorTest) }
|
||||||
|
factory = RunnableExampleBuilder.new(description, source, builder, runner)
|
||||||
|
@@stack.current.add_child(factory)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds an example type to the current group.
|
||||||
|
# The class name of the example should be passed as an argument.
|
||||||
|
# The example will be instantiated later.
|
||||||
|
def add_pending_example(description : String, source : Source,
|
||||||
|
example_type : ::SpectatorTest.class, &runner : ::SpectatorTest ->) : Nil
|
||||||
|
builder = ->(values : TestValues) { example_type.new(values).as(::SpectatorTest) }
|
||||||
|
factory = PendingExampleBuilder.new(description, source, builder, runner)
|
||||||
|
@@stack.current.add_child(factory)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a block of code to run before all examples in the current group.
|
# Adds a block of code to run before all examples in the current group.
|
||||||
def add_before_all_hook(&block : ->) : Nil
|
def add_before_all_hook(&block : ->) : Nil
|
||||||
current_group.add_before_all_hook(block)
|
@@stack.current.add_before_all_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a block of code to run before each example in the current group.
|
# Adds a block of code to run before each example in the current group.
|
||||||
def add_before_each_hook(&block : ->) : Nil
|
def add_before_each_hook(&block : TestMetaMethod) : Nil
|
||||||
current_group.add_before_each_hook(block)
|
@@stack.current.add_before_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a block of code to run after all examples in the current group.
|
# Adds a block of code to run after all examples in the current group.
|
||||||
def add_after_all_hook(&block : ->) : Nil
|
def add_after_all_hook(&block : ->) : Nil
|
||||||
current_group.add_after_all_hook(block)
|
@@stack.current.add_after_all_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a block of code to run after each example in the current group.
|
# Adds a block of code to run after each example in the current group.
|
||||||
def add_after_each_hook(&block : ->) : Nil
|
def add_after_each_hook(&block : TestMetaMethod) : Nil
|
||||||
current_group.add_after_each_hook(block)
|
@@stack.current.add_after_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a block of code to run before and after each example in the current group.
|
# Adds a block of code to run before and after each example in the current group.
|
||||||
# The block of code will be given another proc as an argument.
|
# The block of code will be given another hook as an argument.
|
||||||
# It is expected that the block will call the proc.
|
# It is expected that the block will call the hook.
|
||||||
def add_around_each_hook(&block : Proc(Nil) ->) : Nil
|
def add_around_each_hook(&block : ::SpectatorTest, Proc(Nil) ->) : Nil
|
||||||
current_group.add_around_each_hook(block)
|
@@stack.current.add_around_each_hook(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a pre-condition to run at the start of every example in the current group.
|
# Adds a pre-condition to run at the start of every example in the current group.
|
||||||
def add_pre_condition(&block : ->) : Nil
|
def add_pre_condition(&block : TestMetaMethod) : Nil
|
||||||
current_group.add_pre_condition(block)
|
@@stack.current.add_pre_condition(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds a post-condition to run at the end of every example in the current group.
|
# Adds a post-condition to run at the end of every example in the current group.
|
||||||
def add_post_condition(&block : ->) : Nil
|
def add_post_condition(&block : TestMetaMethod) : Nil
|
||||||
current_group.add_post_condition(block)
|
@@stack.current.add_post_condition(block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_double(id : Symbol, double_type : Double.class) : Nil
|
def add_double(id : Symbol, double_type : Double.class) : Nil
|
||||||
|
@ -109,7 +104,7 @@ module Spectator::DSL
|
||||||
# Builds the entire spec and returns it as a test suite.
|
# Builds the entire spec and returns it as a test suite.
|
||||||
# This should be called only once after the entire spec has been defined.
|
# This should be called only once after the entire spec has been defined.
|
||||||
protected def build(filter : ExampleFilter) : TestSuite
|
protected def build(filter : ExampleFilter) : TestSuite
|
||||||
group = root_group.build(Internals::SampleValues.empty)
|
group = @@stack.root.build
|
||||||
TestSuite.new(group, filter)
|
TestSuite.new(group, filter)
|
||||||
end
|
end
|
||||||
end
|
end
|
19
src/spectator/spec_builder/example_builder.cr
Normal file
19
src/spectator/spec_builder/example_builder.cr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
require "../../spectator_test"
|
||||||
|
require "../test_values"
|
||||||
|
require "../test_wrapper"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
abstract class ExampleBuilder
|
||||||
|
alias FactoryMethod = TestValues -> ::SpectatorTest
|
||||||
|
|
||||||
|
def initialize(@description : String, @source : Source, @builder : FactoryMethod, @runner : TestMethod)
|
||||||
|
end
|
||||||
|
|
||||||
|
abstract def build(group) : ExampleComponent
|
||||||
|
|
||||||
|
private def build_test_wrapper(group)
|
||||||
|
test = @builder.call(group.context.values)
|
||||||
|
TestWrapper.new(@description, @source, test, @runner)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
67
src/spectator/spec_builder/example_group_builder.cr
Normal file
67
src/spectator/spec_builder/example_group_builder.cr
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
require "../test_context"
|
||||||
|
require "./example_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
abstract class ExampleGroupBuilder
|
||||||
|
alias Child = NestedExampleGroupBuilder | ExampleBuilder
|
||||||
|
|
||||||
|
private getter children = Deque(Child).new
|
||||||
|
|
||||||
|
@before_each_hooks = Deque(TestMetaMethod).new
|
||||||
|
@after_each_hooks = Deque(TestMetaMethod).new
|
||||||
|
@before_all_hooks = Deque(->).new
|
||||||
|
@after_all_hooks = Deque(->).new
|
||||||
|
@around_each_hooks = Deque(::SpectatorTest, Proc(Nil) ->).new
|
||||||
|
@pre_conditions = Deque(TestMetaMethod).new
|
||||||
|
@post_conditions = Deque(TestMetaMethod).new
|
||||||
|
|
||||||
|
def add_child(child : Child)
|
||||||
|
@children << child
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_before_each_hook(hook : TestMetaMethod)
|
||||||
|
@before_each_hooks << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_after_each_hook(hook : TestMetaMethod)
|
||||||
|
@after_each_hooks << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_before_all_hook(hook : ->)
|
||||||
|
@before_all_hooks << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_after_all_hook(hook : ->)
|
||||||
|
@after_all_hooks << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_around_each_hook(hook : ::SpectatorTest, Proc(Nil) ->)
|
||||||
|
@around_each_hooks << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_pre_condition(hook : TestMetaMethod)
|
||||||
|
@pre_conditions << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_post_condition(hook : TestMetaMethod)
|
||||||
|
@post_conditions << hook
|
||||||
|
end
|
||||||
|
|
||||||
|
private def build_hooks
|
||||||
|
ExampleHooks.new(
|
||||||
|
@before_all_hooks.to_a,
|
||||||
|
@before_each_hooks.to_a,
|
||||||
|
@after_all_hooks.to_a,
|
||||||
|
@after_each_hooks.to_a,
|
||||||
|
@around_each_hooks.to_a
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def build_conditions
|
||||||
|
ExampleConditions.new(
|
||||||
|
@pre_conditions.to_a,
|
||||||
|
@post_conditions.to_a
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
28
src/spectator/spec_builder/example_group_stack.cr
Normal file
28
src/spectator/spec_builder/example_group_stack.cr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
require "./root_example_group_builder"
|
||||||
|
require "./nested_example_group_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
struct ExampleGroupStack
|
||||||
|
getter root
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@root = RootExampleGroupBuilder.new
|
||||||
|
@stack = Deque(ExampleGroupBuilder).new(1, @root)
|
||||||
|
end
|
||||||
|
|
||||||
|
def current
|
||||||
|
@stack.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def push(group : NestedExampleGroupBuilder)
|
||||||
|
current.add_child(group)
|
||||||
|
@stack.push(group)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pop
|
||||||
|
raise "Attempted to pop root example group from stack" if current == root
|
||||||
|
|
||||||
|
@stack.pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
src/spectator/spec_builder/nested_example_group_builder.cr
Normal file
18
src/spectator/spec_builder/nested_example_group_builder.cr
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
require "../test_context"
|
||||||
|
require "./example_group_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
class NestedExampleGroupBuilder < ExampleGroupBuilder
|
||||||
|
def initialize(@description : String | Symbol, @source : Source)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build(parent_group)
|
||||||
|
context = TestContext.new(parent_group.context, build_hooks, build_conditions, parent_group.context.values)
|
||||||
|
NestedExampleGroup.new(@description, @source, parent_group, context).tap do |group|
|
||||||
|
group.children = children.map do |child|
|
||||||
|
child.build(group).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
src/spectator/spec_builder/pending_example_builder.cr
Normal file
10
src/spectator/spec_builder/pending_example_builder.cr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require "./example_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
class PendingExampleBuilder < ExampleBuilder
|
||||||
|
def build(group) : ExampleComponent
|
||||||
|
wrapper = build_test_wrapper(group)
|
||||||
|
PendingExample.new(group, wrapper).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
src/spectator/spec_builder/root_example_group_builder.cr
Normal file
15
src/spectator/spec_builder/root_example_group_builder.cr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require "../test_values"
|
||||||
|
require "./example_group_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
class RootExampleGroupBuilder < ExampleGroupBuilder
|
||||||
|
def build
|
||||||
|
context = TestContext.new(nil, build_hooks, build_conditions, TestValues.empty)
|
||||||
|
RootExampleGroup.new(context).tap do |group|
|
||||||
|
group.children = children.map do |child|
|
||||||
|
child.build(group).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
src/spectator/spec_builder/runnable_example_builder.cr
Normal file
10
src/spectator/spec_builder/runnable_example_builder.cr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
require "./example_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
class RunnableExampleBuilder < ExampleBuilder
|
||||||
|
def build(group) : ExampleComponent
|
||||||
|
wrapper = build_test_wrapper(group)
|
||||||
|
RunnableExample.new(group, wrapper).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
30
src/spectator/spec_builder/sample_example_group_builder.cr
Normal file
30
src/spectator/spec_builder/sample_example_group_builder.cr
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
require "./nested_example_group_builder"
|
||||||
|
|
||||||
|
module Spectator::SpecBuilder
|
||||||
|
class SampleExampleGroupBuilder(T) < NestedExampleGroupBuilder
|
||||||
|
def initialize(description : String | Symbol, source : Source, @id : Symbol, @label : String, @collection_builder : TestValues -> Array(T))
|
||||||
|
super(description, source)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build(parent_group)
|
||||||
|
values = parent_group.context.values
|
||||||
|
collection = @collection_builder.call(values)
|
||||||
|
context = TestContext.new(parent_group.context, build_hooks, build_conditions, values)
|
||||||
|
NestedExampleGroup.new(@description, @source, parent_group, context).tap do |group|
|
||||||
|
group.children = collection.map do |element|
|
||||||
|
build_sub_group(group, element).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def build_sub_group(parent_group, element)
|
||||||
|
values = parent_group.context.values.add(@id, @description.to_s, element)
|
||||||
|
context = TestContext.new(parent_group.context, ExampleHooks.empty, ExampleConditions.empty, values)
|
||||||
|
NestedExampleGroup.new("#{@label} = #{element.inspect}", @source, parent_group, context).tap do |group|
|
||||||
|
group.children = children.map do |child|
|
||||||
|
child.build(group).as(ExampleComponent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
74
src/spectator/test_context.cr
Normal file
74
src/spectator/test_context.cr
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
require "./example_hooks"
|
||||||
|
require "./test_values"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
class TestContext
|
||||||
|
getter values
|
||||||
|
|
||||||
|
def initialize(@parent : TestContext?, @hooks : ExampleHooks, @conditions : ExampleConditions, @values : TestValues)
|
||||||
|
@before_all_hooks_run = false
|
||||||
|
@after_all_hooks_run = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_before_hooks(example : Example)
|
||||||
|
run_before_all_hooks
|
||||||
|
run_before_each_hooks(example)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def run_before_all_hooks
|
||||||
|
return if @before_all_hooks_run
|
||||||
|
|
||||||
|
@parent.try &.run_before_all_hooks
|
||||||
|
@hooks.run_before_all
|
||||||
|
ensure
|
||||||
|
@before_all_hooks_run = true
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def run_before_each_hooks(example : Example)
|
||||||
|
@parent.try &.run_before_each_hooks(example)
|
||||||
|
@hooks.run_before_each(example.test_wrapper, example)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_after_hooks(example : Example)
|
||||||
|
run_after_each_hooks(example)
|
||||||
|
run_after_all_hooks(example.group)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def run_after_all_hooks(group : ExampleGroup, *, ignore_unfinished = false)
|
||||||
|
return if @after_all_hooks_run
|
||||||
|
return unless ignore_unfinished || group.finished?
|
||||||
|
|
||||||
|
@hooks.run_after_all
|
||||||
|
@parent.try do |parent_context|
|
||||||
|
parent_group = group.as(NestedExampleGroup).parent
|
||||||
|
parent_context.run_after_all_hooks(parent_group, ignore_unfinished: ignore_unfinished)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
@after_all_hooks_run = true
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def run_after_each_hooks(example : Example)
|
||||||
|
@hooks.run_after_each(example.test_wrapper, example)
|
||||||
|
@parent.try &.run_after_each_hooks(example)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrap_around_each_hooks(test, &block : ->)
|
||||||
|
wrapper = @hooks.wrap_around_each(test, block)
|
||||||
|
if (parent = @parent)
|
||||||
|
parent.wrap_around_each_hooks(test, &wrapper)
|
||||||
|
else
|
||||||
|
wrapper
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_pre_conditions(example)
|
||||||
|
@parent.try &.run_pre_conditions(example)
|
||||||
|
@conditions.run_pre_conditions(example.test_wrapper, example)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_post_conditions(example)
|
||||||
|
@conditions.run_post_conditions(example.test_wrapper, example)
|
||||||
|
@parent.try &.run_post_conditions(example)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,10 +1,11 @@
|
||||||
|
require "./typed_value_wrapper"
|
||||||
require "./value_wrapper"
|
require "./value_wrapper"
|
||||||
|
|
||||||
module Spectator::Internals
|
module Spectator
|
||||||
# Collection of test values supplied to examples.
|
# Collection of test values supplied to examples.
|
||||||
# Each value is labeled by a symbol that the example knows.
|
# Each value is labeled by a symbol that the example knows.
|
||||||
# The values also come with a name that can be given to humans.
|
# The values also come with a name that can be given to humans.
|
||||||
struct SampleValues
|
struct TestValues
|
||||||
# Creates an empty set of sample values.
|
# Creates an empty set of sample values.
|
||||||
def self.empty
|
def self.empty
|
||||||
new({} of Symbol => Entry)
|
new({} of Symbol => Entry)
|
||||||
|
@ -17,9 +18,9 @@ module Spectator::Internals
|
||||||
# Adds a new value by duplicating the current set and adding to it.
|
# Adds a new value by duplicating the current set and adding to it.
|
||||||
# The new sample values with the additional value is returned.
|
# The new sample values with the additional value is returned.
|
||||||
# The original set of sample values is not modified.
|
# The original set of sample values is not modified.
|
||||||
def add(id : Symbol, name : String, value : T) : SampleValues forall T
|
def add(id : Symbol, name : String, value : T) : TestValues forall T
|
||||||
wrapper = TypedValueWrapper(T).new(value)
|
wrapper = TypedValueWrapper(T).new(value)
|
||||||
SampleValues.new(@values.merge({
|
TestValues.new(@values.merge({
|
||||||
id => Entry.new(name, wrapper),
|
id => Entry.new(name, wrapper),
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
|
@ -58,7 +59,6 @@ module Spectator::Internals
|
||||||
end
|
end
|
||||||
|
|
||||||
# This must be after `Entry` is defined.
|
# This must be after `Entry` is defined.
|
||||||
# Could be a Cyrstal compiler bug?
|
|
||||||
include Enumerable(Entry)
|
include Enumerable(Entry)
|
||||||
end
|
end
|
||||||
end
|
end
|
36
src/spectator/test_wrapper.cr
Normal file
36
src/spectator/test_wrapper.cr
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
require "../spectator_test"
|
||||||
|
require "./source"
|
||||||
|
|
||||||
|
module Spectator
|
||||||
|
alias TestMethod = ::SpectatorTest ->
|
||||||
|
|
||||||
|
# Stores information about a end-user test.
|
||||||
|
# Used to instantiate tests and run them.
|
||||||
|
struct TestWrapper
|
||||||
|
# Description the user provided for the test.
|
||||||
|
getter description
|
||||||
|
|
||||||
|
# Location of the test in source code.
|
||||||
|
getter source
|
||||||
|
|
||||||
|
# Creates a wrapper for the test.
|
||||||
|
def initialize(@description : String, @source : Source, @test : ::SpectatorTest, @runner : TestMethod)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
call(@runner)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(method : TestMethod) : Nil
|
||||||
|
method.call(@test)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(method, *args) : Nil
|
||||||
|
method.call(@test, *args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def around_hook(context : TestContext)
|
||||||
|
context.wrap_around_each_hooks(@test) { run }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
require "./value_wrapper"
|
require "./value_wrapper"
|
||||||
|
|
||||||
module Spectator::Internals
|
module Spectator
|
||||||
# Implementation of a value wrapper for a specific type.
|
# Implementation of a value wrapper for a specific type.
|
||||||
# Instances of this class should be created to wrap values.
|
# Instances of this class should be created to wrap values.
|
||||||
# Then the wrapper should be stored as a `ValueWrapper`
|
# Then the wrapper should be stored as a `ValueWrapper`
|
|
@ -1,9 +1,7 @@
|
||||||
module Spectator::Internals
|
module Spectator
|
||||||
# Base class for proxying test values to examples.
|
# Base class for proxying test values to examples.
|
||||||
# This abstraction is required for inferring types.
|
# This abstraction is required for inferring types.
|
||||||
# The DSL makes heavy use of this to defer types.
|
# The DSL makes heavy use of this to defer types.
|
||||||
abstract class ValueWrapper
|
abstract class ValueWrapper
|
||||||
# Retrieves the underlying value.
|
|
||||||
abstract def value
|
|
||||||
end
|
end
|
||||||
end
|
end
|
11
src/spectator_test.cr
Normal file
11
src/spectator_test.cr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
require "./spectator/dsl"
|
||||||
|
|
||||||
|
# Root-level class that all tests inherit from and are contained in.
|
||||||
|
# This class is intentionally outside of the scope of Spectator,
|
||||||
|
# so that the namespace isn't leaked into tests unexpectedly.
|
||||||
|
class SpectatorTest
|
||||||
|
include ::Spectator::DSL
|
||||||
|
|
||||||
|
def initialize(@spectator_test_values : ::Spectator::TestValues)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue