Skip to content

Instantly share code, notes, and snippets.

@icy-arctic-fox
Created May 22, 2019 19:40
Show Gist options
  • Save icy-arctic-fox/4043b16ecfa496144684e3b66350a09b to your computer and use it in GitHub Desktop.
Save icy-arctic-fox/4043b16ecfa496144684e3b66350a09b to your computer and use it in GitHub Desktop.
Crystal Inheritance Bug
# Monkey-patch to show the relevant code.
# These methods are identical to what is implemented in Spectator,
# except that comments are removed and a `puts` debug line has been added.
# `super` is not called.
# The `SampleExampleGroupBuilder` overrides the same `#build` method in `NestedExampleGroupBuilder`.
# In the output, we can see the debug statements indicate that the wrong method is called.
module Spectator::DSL
class NestedExampleGroupBuilder < ExampleGroupBuilder
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
puts "DEBUG: NestedExampleGroupBuilder#build (#{self.class})"
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group|
group.children = @children.map do |child|
child.build(group, sample_values).as(ExampleComponent)
end
end
end
end
class SampleExampleGroupBuilder(T) < NestedExampleGroupBuilder
def build(parent : ExampleGroup, sample_values : Internals::SampleValues) : NestedExampleGroup
puts "DEBUG: SampleExampleGroupBuilder#build (#{self.class})"
NestedExampleGroup.new(@what, parent, hooks, conditions).tap do |group|
group.children = @collection.map do |value|
build_sub_group(group, sample_values, value).as(ExampleComponent)
end
end
end
end
end
# Very small example spec that reproduces the issue.
# For some reason, the wrong method is being called in the inheritance chain.
# A `NestedExampleGroupBuilder` is the object that builds typical example groups.
# A `SampleExampleGroupBuilder(T)` handles `sample` blocks and uses a generic type, which is the element type.
# It also inherits from `NestedExampleGroupBuilder`, but overrides the `#build` method.
# In the following code (Crystal v0.28.0), when Spectator builds the groups,
# the wrong method is called and results in an unexpected error (see output).
# The builders recursively call nested group builders.
# The first sample block is handled just fine, but the second isn't.
# For the first call, `SampleExapleGroupBuilder#build` is called, as it should.
# For the second, `NestedExampleGroupBuilder#build` is called, which is incorrect.
# The object type for both is a `SampleExampleGroupBuilder`, yet the `#build` method for `NestedExampleGroupBuilder` is called.
require "spectator"
require "./debug"
# There are two `sample` blocks, that receive different element types.
# When the element types are identical, the issue does not occur.
Spectator.describe "Something" do
sample [0, 1, 2] do |int|
it { p int }
end
sample %i[a b c] do |sym|
it { p sym }
end
end
DEBUG: NestedExampleGroupBuilder#build (Spectator::DSL::NestedExampleGroupBuilder)
DEBUG: SampleExampleGroupBuilder#build (Spectator::DSL::SampleExampleGroupBuilder(Int32))
DEBUG: NestedExampleGroupBuilder#build (Spectator::DSL::SampleExampleGroupBuilder(Symbol))
Encountered an unexpected error in framework
Caused by: Missing hash key: :__temp_33
/usr/share/crystal/src/hash.cr:0:9 in '[]'
lib/spectator/src/spectator/internals/sample_values.cr:30:7 in 'get_wrapper'
main.cr:9:3 in 'initialize'
main.cr:10:5 in 'initialize'
main.cr:10:5 in 'new'
main.cr:10:5 in 'initialize'
main.cr:10:5 in 'new'
lib/spectator/src/spectator/dsl/example_factory.cr:12:7 in 'build'
debug.cr:7:11 in 'build'
debug.cr:7:11 in 'build'
lib/spectator/src/spectator/dsl/root_example_group_builder.cr:13:11 in 'build'
lib/spectator/src/spectator/dsl/builder.cr:107:7 in 'build'
lib/spectator/src/spectator.cr:106:13 in 'run'
lib/spectator/src/spectator.cr:81:29 in '->'
/usr/share/crystal/src/kernel.cr:255:3 in 'run'
/usr/share/crystal/src/crystal/main.cr:47:5 in 'main'
/usr/share/crystal/src/crystal/main.cr:106:3 in 'main'
__libc_start_main
_start
???
name: crystal-bug
version: 0.0.1
development_dependencies:
spectator:
gitlab: arctic-fox/spectator
@icy-arctic-fox
Copy link
Author

Line 3 of the output shows the discrepancy.

@icy-arctic-fox
Copy link
Author

Confirmed fixed in v0.29.0 of Crystal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment