Skip to content

Commit

Permalink
Add an autoload spec for the behavior inside autoload but after the c…
Browse files Browse the repository at this point in the history
…onstant is defined
  • Loading branch information
byroot authored and eregon committed Feb 5, 2024
1 parent e73308b commit 40265a0
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 27 deletions.
91 changes: 64 additions & 27 deletions core/module/autoload_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,29 @@ module ModuleSpecs::Autoload
end
end

def check_before_during_thread_after(const, &check)
before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
ScratchPad.record -> {
from_autoload_thread.push check.call
to_autoload_thread.pop
}
t = Thread.new {
in_loading_thread = from_autoload_thread.pop
in_other_thread = check.call
to_autoload_thread.push :done
[in_loading_thread, in_other_thread]
}
in_loading_thread, in_other_thread = nil
begin
ModuleSpecs::Autoload.const_get(const)
ensure
in_loading_thread, in_other_thread = t.value
end
after = check.call
[before, in_loading_thread, in_other_thread, after]
end

describe "during the autoload before the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
Expand All @@ -350,58 +373,72 @@ module ModuleSpecs::Autoload
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end

def check_before_during_thread_after(&check)
before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
ScratchPad.record -> {
from_autoload_thread.push check.call
to_autoload_thread.pop
}
t = Thread.new {
in_loading_thread = from_autoload_thread.pop
in_other_thread = check.call
to_autoload_thread.push :done
[in_loading_thread, in_other_thread]
}
in_loading_thread, in_other_thread = nil
begin
ModuleSpecs::Autoload::DuringAutoload
ensure
in_loading_thread, in_other_thread = t.value
end
after = check.call
[before, in_loading_thread, in_other_thread, after]
end

it "returns nil in autoload thread and 'constant' otherwise for defined?" do
results = check_before_during_thread_after {
results = check_before_during_thread_after(:DuringAutoload) {
defined?(ModuleSpecs::Autoload::DuringAutoload)
}
results.should == ['constant', nil, 'constant', 'constant']
end

it "keeps the constant in Module#constants" do
results = check_before_during_thread_after {
results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.constants(false).include?(:DuringAutoload)
}
results.should == [true, true, true, true]
end

it "returns false in autoload thread and true otherwise for Module#const_defined?" do
results = check_before_during_thread_after {
results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.const_defined?(:DuringAutoload, false)
}
results.should == [true, false, true, true]
end

it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
results = check_before_during_thread_after {
results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.autoload?(:DuringAutoload)
}
results.should == [@path, nil, @path, nil]
end
end

describe "during the autoload after the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload_after_define.rb")
ModuleSpecs::Autoload.autoload :DuringAutoloadAfterDefine, @path
@remove << :DuringAutoloadAfterDefine
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine) == @path
end

it "returns 'constant' in both threads" do
results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
defined?(ModuleSpecs::Autoload::DuringAutoloadAfterDefine)
}
results.should == ['constant', 'constant', 'constant', 'constant']
end

it "Module#constants include the autoloaded in both threads" do
results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
ModuleSpecs::Autoload.constants(false).include?(:DuringAutoloadAfterDefine)
}
results.should == [true, true, true, true]
end

it "Module#const_defined? returns true in both threads" do
results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
ModuleSpecs::Autoload.const_defined?(:DuringAutoloadAfterDefine, false)
}
results.should == [true, true, true, true]
end

it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine)
}
results.should == [@path, nil, @path, nil]
end
end

it "does not remove the constant from Module#constants if load fails and keeps it as an autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent

Expand Down
6 changes: 6 additions & 0 deletions core/module/fixtures/autoload_during_autoload_after_define.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module ModuleSpecs::Autoload
class DuringAutoloadAfterDefine
block = ScratchPad.recorded
ScratchPad.record(block.call)
end
end

0 comments on commit 40265a0

Please sign in to comment.