Skip to content

Commit 49cf7db

Browse files
committed
Add tests for ReloadableRequire
Add integration tests covering: - require and require_relative with nested dependencies - autoload with nested require - reload command behavior - $LOADED_FEATURES and $LOAD_PATH consistency
1 parent c30568a commit 49cf7db

1 file changed

Lines changed: 294 additions & 0 deletions

File tree

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# frozen_string_literal: true
2+
3+
require "tempfile"
4+
require "fileutils"
5+
6+
require_relative "helper"
7+
8+
module TestIRB
9+
class ReloadableRequireIntegrationTest < IntegrationTestCase
10+
def setup
11+
super
12+
13+
omit "ReloadableRequire requires Ruby::Box" if !defined?(Ruby::Box) || !Ruby::Box.enabled?
14+
15+
@envs["RUBY_BOX"] = "1"
16+
17+
setup_lib_files
18+
19+
write_rc <<~RUBY
20+
IRB.conf[:RELOADABLE_REQUIRE] = true
21+
$LOAD_PATH.unshift('#{@lib_dir}')
22+
RUBY
23+
end
24+
25+
def teardown
26+
super
27+
FileUtils.rm_rf(@lib_dir) if @lib_dir
28+
@pwd_files&.each { |f| File.delete(f) if File.exist?(f) }
29+
end
30+
31+
def test_require_enables_reload
32+
write_ruby <<~'RUBY'
33+
binding.irb
34+
RUBY
35+
36+
output = run_ruby_file do
37+
type "require 'nested_a'"
38+
type "NESTED_A_VALUE"
39+
type "NESTED_B_VALUE"
40+
type "reload"
41+
type "exit!"
42+
end
43+
44+
assert_include output, "=> \"from_a\""
45+
assert_include output, "=> \"from_b\""
46+
assert_include output, "Reloaded: #{@nested_a_path}"
47+
assert_include output, "Reloaded: #{@nested_b_path}"
48+
end
49+
50+
def test_require_relative_from_irb_prompt_enables_reload
51+
write_ruby <<~'RUBY'
52+
binding.irb
53+
RUBY
54+
55+
output = run_ruby_file do
56+
type "require_relative 'require_relative_lib'"
57+
type "REQUIRE_RELATIVE_LIB_VALUE"
58+
type "REQUIRE_RELATIVE_DEP"
59+
type "reload"
60+
type "exit!"
61+
end
62+
63+
assert_include output, "=> 42"
64+
assert_include output, "=> \"dep\""
65+
assert_include output, "Reloaded: #{@require_relative_lib_path}"
66+
assert_include output, "Reloaded: #{@require_relative_dep_path}"
67+
end
68+
69+
def test_require_with_nested_require_relative_enables_reload
70+
write_ruby <<~'RUBY'
71+
binding.irb
72+
RUBY
73+
74+
output = run_ruby_file do
75+
type "require '#{@relative_nested_a_path}'"
76+
type "RELATIVE_NESTED_A"
77+
type "RELATIVE_NESTED_B"
78+
type "reload"
79+
type "exit!"
80+
end
81+
82+
assert_include output, "=> \"from_a\""
83+
assert_include output, "=> \"from_b\""
84+
assert_include output, "Reloaded: #{@relative_nested_a_path}"
85+
assert_include output, "Reloaded: #{@relative_nested_b_path}"
86+
end
87+
88+
def test_autoload_enables_reload
89+
write_ruby <<~'RUBY'
90+
binding.irb
91+
RUBY
92+
93+
output = run_ruby_file do
94+
type "autoload :AutoloadMain, 'autoload_main'"
95+
type "AutoloadMain::VALUE"
96+
type "AUTOLOAD_DEP_VALUE"
97+
type "reload"
98+
type "exit!"
99+
end
100+
101+
assert_include output, "=> \"main\""
102+
assert_include output, "=> \"dependency\""
103+
assert_include output, "Reloaded: #{@autoload_main_path}"
104+
assert_include output, "Reloaded: #{@autoload_dep_path}"
105+
end
106+
107+
def test_reload_without_any_loaded_files
108+
write_ruby <<~'RUBY'
109+
binding.irb
110+
RUBY
111+
112+
output = run_ruby_file do
113+
type "reload"
114+
type "exit!"
115+
end
116+
117+
assert_include output, "No files to reload"
118+
end
119+
120+
def test_reload_reflects_file_changes
121+
write_ruby <<~'RUBY'
122+
binding.irb
123+
RUBY
124+
125+
output = run_ruby_file do
126+
type "require '#{@changeable_lib_path}'"
127+
type "CHANGEABLE_VALUE"
128+
type "File.write('#{@changeable_lib_path}', \"CHANGEABLE_VALUE = 'modified'\\n\")"
129+
type "reload"
130+
type "CHANGEABLE_VALUE"
131+
type "exit!"
132+
end
133+
134+
assert_include output, "=> \"original\""
135+
assert_include output, "Reloaded: #{@changeable_lib_path}"
136+
assert_include output, "=> \"modified\""
137+
end
138+
139+
def test_reload_command_without_reloadable_require_enabled
140+
write_rc <<~'RUBY'
141+
IRB.conf[:RELOADABLE_REQUIRE] = false
142+
RUBY
143+
144+
write_ruby <<~'RUBY'
145+
binding.irb
146+
RUBY
147+
148+
output = run_ruby_file do
149+
type "reload"
150+
type "exit!"
151+
end
152+
153+
assert_include output, "requires IRB.conf[:RELOADABLE_REQUIRE] = true"
154+
end
155+
156+
def test_require_updates_loaded_features
157+
write_ruby <<~'RUBY'
158+
binding.irb
159+
RUBY
160+
161+
output = run_ruby_file do
162+
type "require 'nested_a'"
163+
type "$LOADED_FEATURES.include?('#{@nested_a_path}')"
164+
type "$LOADED_FEATURES.include?('#{@nested_b_path}')"
165+
type "exit!"
166+
end
167+
168+
# Both files should be in $LOADED_FEATURES
169+
assert_equal 2, output.scan("=> true").count
170+
end
171+
172+
def test_autoload_updates_loaded_features
173+
write_ruby <<~'RUBY'
174+
binding.irb
175+
RUBY
176+
177+
output = run_ruby_file do
178+
type "autoload :AutoloadMain, 'autoload_main'"
179+
type "AutoloadMain"
180+
type "$LOADED_FEATURES.include?('#{@autoload_main_path}')"
181+
type "$LOADED_FEATURES.include?('#{@autoload_dep_path}')"
182+
type "exit!"
183+
end
184+
185+
# Both files should be in $LOADED_FEATURES
186+
assert_equal 2, output.scan("=> true").count
187+
end
188+
189+
def test_reload_preserves_loaded_features
190+
write_ruby <<~'RUBY'
191+
binding.irb
192+
RUBY
193+
194+
output = run_ruby_file do
195+
type "require 'nested_a'"
196+
type "$LOADED_FEATURES.include?('#{@nested_a_path}')"
197+
type "reload"
198+
type "$LOADED_FEATURES.include?('#{@nested_a_path}')"
199+
type "exit!"
200+
end
201+
202+
# Both checks should return true (before and after reload)
203+
assert_equal 2, output.scan("=> true").count
204+
end
205+
206+
def test_require_does_not_modify_load_path
207+
write_ruby <<~'RUBY'
208+
binding.irb
209+
RUBY
210+
211+
output = run_ruby_file do
212+
type "load_path_before = $LOAD_PATH.dup"
213+
type "require 'nested_a'"
214+
type "$LOAD_PATH == load_path_before"
215+
type "exit!"
216+
end
217+
218+
assert_include output, "=> true"
219+
end
220+
221+
private
222+
223+
def setup_lib_files
224+
@lib_dir = Dir.mktmpdir
225+
@pwd_files = []
226+
227+
# Nested require files (primary test files)
228+
@nested_b_path = create_lib_file("nested_b.rb", "NESTED_B_VALUE = 'from_b'\n")
229+
@nested_a_path = create_lib_file("nested_a.rb", "require 'nested_b'\nNESTED_A_VALUE = 'from_a'\n")
230+
231+
# Nested require_relative files (for testing require that internally uses require_relative)
232+
@relative_nested_b_path = create_lib_file("relative_nested_b.rb", "RELATIVE_NESTED_B = 'from_b'\n")
233+
@relative_nested_a_path = create_lib_file(
234+
"relative_nested_a.rb",
235+
"require_relative 'relative_nested_b'\nRELATIVE_NESTED_A = 'from_a'\n"
236+
)
237+
238+
# Files in Dir.pwd for require_relative from IRB prompt (with nested dependency)
239+
@require_relative_dep_path = create_pwd_file("require_relative_dep.rb", "REQUIRE_RELATIVE_DEP = 'dep'\n")
240+
@require_relative_lib_path = create_pwd_file(
241+
"require_relative_lib.rb",
242+
"require_relative 'require_relative_dep'\nREQUIRE_RELATIVE_LIB_VALUE = 42\n"
243+
)
244+
245+
# Autoload files with nested require
246+
@autoload_dep_path = create_lib_file("autoload_dep.rb", "AUTOLOAD_DEP_VALUE = 'dependency'\n")
247+
@autoload_main_path = create_lib_file(
248+
"autoload_main.rb",
249+
"require 'autoload_dep'\nmodule AutoloadMain; VALUE = 'main'; end\n"
250+
)
251+
252+
# Changeable file (for testing reload reflects changes)
253+
@changeable_lib_path = create_lib_file("changeable.rb", "CHANGEABLE_VALUE = 'original'\n")
254+
end
255+
256+
def create_lib_file(name, content)
257+
path = File.join(@lib_dir, name)
258+
File.write(path, content)
259+
File.realpath(path)
260+
end
261+
262+
def create_pwd_file(name, content)
263+
path = File.join(Dir.pwd, name)
264+
File.write(path, content)
265+
@pwd_files << path
266+
File.realpath(path)
267+
end
268+
end
269+
270+
class ReloadableRequireDisabledTest < IntegrationTestCase
271+
def setup
272+
super
273+
274+
omit "This test is for Ruby::Box disabled environment" if defined?(Ruby::Box) && Ruby::Box.enabled?
275+
end
276+
277+
def test_reload_command_shows_error_without_ruby_box
278+
write_rc <<~'RUBY'
279+
IRB.conf[:RELOADABLE_REQUIRE] = true
280+
RUBY
281+
282+
write_ruby <<~'RUBY'
283+
binding.irb
284+
RUBY
285+
286+
output = run_ruby_file do
287+
type "reload"
288+
type "exit!"
289+
end
290+
291+
assert_include output, "requires IRB.conf[:RELOADABLE_REQUIRE] = true and Ruby::Box"
292+
end
293+
end
294+
end

0 commit comments

Comments
 (0)