Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions core/fiber/kill_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,108 @@
rescue_executed.should == false
end

it "returns the fiber" do
fiber = Fiber.new { Fiber.yield }
fiber.resume

fiber.kill.should.equal?(fiber)
end

it "returns the fiber when it is already dead" do
fiber = Fiber.new { :done }
fiber.resume

fiber.kill.should.equal?(fiber)
end

it "does nothing when killing a fiber twice" do
fiber = Fiber.new { Fiber.yield }
fiber.resume

fiber.kill
fiber.kill
fiber.alive?.should == false
end

it "runs the ensure block in the fiber being killed, while it is still alive" do
states = []

fiber = Fiber.new do
Fiber.yield
ensure
states << Fiber.current.equal?(fiber) << fiber.alive?
end

fiber.resume
fiber.kill
states.should == [true, true]
end

it "propagates an exception raised by the ensure block to the killing fiber" do
fiber = Fiber.new do
Fiber.yield
ensure
raise "from ensure"
end

fiber.resume
-> { fiber.kill }.should.raise(RuntimeError, "from ensure")
end

it "raises a FiberError when killing a fiber from a different Thread" do
fiber = Fiber.new { Fiber.yield }
fiber.resume

Thread.new do
-> { fiber.kill }.should.raise(FiberError)
end.join
end

it "kills a fiber which transferred, from the fiber it transferred to" do
states = []
outer = nil

outer = Fiber.new do
Fiber.new do
outer.kill
states << :inner_resumed
end.transfer
states << :outer_resumed
end

outer.resume
# Killing outer transfers into it to unwind, and the inner fiber is left
# suspended, so neither fiber runs again.
states.should == []
outer.alive?.should == false
end

it "kills a fiber whose ensure block transfers to another fiber" do
other = Fiber.new { :other }

fiber = Fiber.new do
Fiber.yield
ensure
other.transfer
end

fiber.resume
fiber.kill
fiber.alive?.should == false
other.alive?.should == false
end

it "returns control to the transferring fiber when killing a fiber entered by Fiber#transfer" do
states = []
runner = Fiber.new do
Fiber.new { Fiber.current.kill; states << :unreachable }.transfer
states << :runner_resumed
end

runner.resume
states.should == [:runner_resumed]
end

it "repeatedly kills a fiber" do
fiber = Fiber.new do
while true; Fiber.yield; end
Expand Down
48 changes: 48 additions & 0 deletions core/fiber/transfer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,54 @@
f2.transfer.should == :fiber_2
end

it "returns control to the transferring fiber when the target finishes" do
states = []
runner = Fiber.new do
Fiber.new { states << :target_end }.transfer
states << :runner_resumed
end

runner.resume
states.should == [:target_end, :runner_resumed]
end

it "returns control to a transferring fiber which was itself entered by Fiber#raise" do
states = []
target = Fiber.new do
begin
Fiber.yield
rescue RuntimeError
Fiber.new { states << :inner_end }.transfer
states << :target_after_transfer
end
end

target.resume
target.raise "raised"
states.should == [:inner_end, :target_after_transfer]
end

it "returns control according to the resume chain, not to the Fiber which transferred" do
states = []
outer = Fiber.new do
middle = Fiber.new do
inner = Fiber.new do
Fiber.new { states << :leaf_end }.transfer
states << :inner_after_transfer
end
inner.resume
states << :middle_after_resume
end
middle.transfer
states << :outer_after_transfer
end

outer.resume
# The leaf has no resumer, so control follows resumes down from the root Fiber and
# stops at outer. inner, which transferred to the leaf, stays suspended.
states.should == [:leaf_end, :outer_after_transfer]
end

it "can be invoked from the same Fiber it transfers control to" do
states = []
fiber = Fiber.new { states << :start; fiber.transfer; states << :end }
Expand Down