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 committed Jan 22, 2024
1 parent b841e32 commit b4b35b1
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 27 deletions.
91 changes: 64 additions & 27 deletions spec/ruby/core/module/autoload_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,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 @@ -351,58 +374,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
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 b4b35b1

Please sign in to comment.