PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/activesupport/test/dependencies_test.rb

https://github.com/ghar/rails
Ruby | 881 lines | 791 code | 87 blank | 3 comment | 6 complexity | 283905422f11db8bb1cfa6678a0dfd87 MD5 | raw file
  1. require 'abstract_unit'
  2. require 'pp'
  3. require 'active_support/dependencies'
  4. module ModuleWithMissing
  5. mattr_accessor :missing_count
  6. def self.const_missing(name)
  7. self.missing_count += 1
  8. name
  9. end
  10. end
  11. module ModuleWithConstant
  12. InheritedConstant = "Hello"
  13. end
  14. class DependenciesTest < Test::Unit::TestCase
  15. def teardown
  16. ActiveSupport::Dependencies.clear
  17. end
  18. def with_loading(*from)
  19. old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load
  20. this_dir = File.dirname(__FILE__)
  21. parent_dir = File.dirname(this_dir)
  22. path_copy = $LOAD_PATH.dup
  23. $LOAD_PATH.unshift(parent_dir) unless $LOAD_PATH.include?(parent_dir)
  24. prior_autoload_paths = ActiveSupport::Dependencies.autoload_paths
  25. ActiveSupport::Dependencies.autoload_paths = from.collect { |f| "#{this_dir}/#{f}" }
  26. yield
  27. ensure
  28. $LOAD_PATH.replace(path_copy)
  29. ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths
  30. ActiveSupport::Dependencies.mechanism = old_mechanism
  31. ActiveSupport::Dependencies.explicitly_unloadable_constants = []
  32. end
  33. def with_autoloading_fixtures(&block)
  34. with_loading 'autoloading_fixtures', &block
  35. end
  36. def test_tracking_loaded_files
  37. require_dependency 'dependencies/service_one'
  38. require_dependency 'dependencies/service_two'
  39. assert_equal 2, ActiveSupport::Dependencies.loaded.size
  40. ensure
  41. Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
  42. Object.send(:remove_const, :ServiceTwo) if Object.const_defined?(:ServiceTwo)
  43. end
  44. def test_tracking_identical_loaded_files
  45. require_dependency 'dependencies/service_one'
  46. require_dependency 'dependencies/service_one'
  47. assert_equal 1, ActiveSupport::Dependencies.loaded.size
  48. ensure
  49. Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
  50. end
  51. def test_missing_dependency_raises_missing_source_file
  52. assert_raise(MissingSourceFile) { require_dependency("missing_service") }
  53. end
  54. def test_missing_association_raises_nothing
  55. assert_nothing_raised { require_association("missing_model") }
  56. end
  57. def test_dependency_which_raises_exception_isnt_added_to_loaded_set
  58. with_loading do
  59. filename = 'dependencies/raises_exception'
  60. $raises_exception_load_count = 0
  61. 5.times do |count|
  62. begin
  63. require_dependency filename
  64. flunk 'should have loaded dependencies/raises_exception which raises an exception'
  65. rescue Exception => e
  66. assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
  67. end
  68. assert_equal count + 1, $raises_exception_load_count
  69. assert !ActiveSupport::Dependencies.loaded.include?(filename)
  70. assert !ActiveSupport::Dependencies.history.include?(filename)
  71. end
  72. end
  73. end
  74. def test_warnings_should_be_enabled_on_first_load
  75. with_loading 'dependencies' do
  76. old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true
  77. filename = "check_warnings"
  78. expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}")
  79. $check_warnings_load_count = 0
  80. assert !ActiveSupport::Dependencies.loaded.include?(expanded)
  81. assert !ActiveSupport::Dependencies.history.include?(expanded)
  82. silence_warnings { require_dependency filename }
  83. assert_equal 1, $check_warnings_load_count
  84. assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
  85. assert ActiveSupport::Dependencies.loaded.include?(expanded)
  86. ActiveSupport::Dependencies.clear
  87. assert !ActiveSupport::Dependencies.loaded.include?(expanded)
  88. assert ActiveSupport::Dependencies.history.include?(expanded)
  89. silence_warnings { require_dependency filename }
  90. assert_equal 2, $check_warnings_load_count
  91. assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.'
  92. assert ActiveSupport::Dependencies.loaded.include?(expanded)
  93. ActiveSupport::Dependencies.clear
  94. assert !ActiveSupport::Dependencies.loaded.include?(expanded)
  95. assert ActiveSupport::Dependencies.history.include?(expanded)
  96. enable_warnings { require_dependency filename }
  97. assert_equal 3, $check_warnings_load_count
  98. assert_equal true, $checked_verbose, 'After first load warnings should be left alone.'
  99. assert ActiveSupport::Dependencies.loaded.include?(expanded)
  100. ActiveSupport::Dependencies.warnings_on_first_load = old_warnings
  101. end
  102. end
  103. def test_mutual_dependencies_dont_infinite_loop
  104. with_loading 'dependencies' do
  105. $mutual_dependencies_count = 0
  106. assert_nothing_raised { require_dependency 'mutual_one' }
  107. assert_equal 2, $mutual_dependencies_count
  108. ActiveSupport::Dependencies.clear
  109. $mutual_dependencies_count = 0
  110. assert_nothing_raised { require_dependency 'mutual_two' }
  111. assert_equal 2, $mutual_dependencies_count
  112. end
  113. end
  114. def test_module_loading
  115. with_autoloading_fixtures do
  116. assert_kind_of Module, A
  117. assert_kind_of Class, A::B
  118. assert_kind_of Class, A::C::D
  119. assert_kind_of Class, A::C::E::F
  120. end
  121. end
  122. def test_non_existing_const_raises_name_error
  123. with_autoloading_fixtures do
  124. assert_raise(NameError) { DoesNotExist }
  125. assert_raise(NameError) { NoModule::DoesNotExist }
  126. assert_raise(NameError) { A::DoesNotExist }
  127. assert_raise(NameError) { A::B::DoesNotExist }
  128. end
  129. end
  130. def test_directories_manifest_as_modules_unless_const_defined
  131. with_autoloading_fixtures do
  132. assert_kind_of Module, ModuleFolder
  133. Object.__send__ :remove_const, :ModuleFolder
  134. end
  135. end
  136. def test_module_with_nested_class
  137. with_autoloading_fixtures do
  138. assert_kind_of Class, ModuleFolder::NestedClass
  139. Object.__send__ :remove_const, :ModuleFolder
  140. end
  141. end
  142. def test_module_with_nested_inline_class
  143. with_autoloading_fixtures do
  144. assert_kind_of Class, ModuleFolder::InlineClass
  145. Object.__send__ :remove_const, :ModuleFolder
  146. end
  147. end
  148. def test_directories_may_manifest_as_nested_classes
  149. with_autoloading_fixtures do
  150. assert_kind_of Class, ClassFolder
  151. Object.__send__ :remove_const, :ClassFolder
  152. end
  153. end
  154. def test_class_with_nested_class
  155. with_autoloading_fixtures do
  156. assert_kind_of Class, ClassFolder::NestedClass
  157. Object.__send__ :remove_const, :ClassFolder
  158. end
  159. end
  160. def test_class_with_nested_inline_class
  161. with_autoloading_fixtures do
  162. assert_kind_of Class, ClassFolder::InlineClass
  163. Object.__send__ :remove_const, :ClassFolder
  164. end
  165. end
  166. def test_class_with_nested_inline_subclass_of_parent
  167. with_autoloading_fixtures do
  168. assert_kind_of Class, ClassFolder::ClassFolderSubclass
  169. assert_kind_of Class, ClassFolder
  170. assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
  171. Object.__send__ :remove_const, :ClassFolder
  172. end
  173. end
  174. def test_nested_class_can_access_sibling
  175. with_autoloading_fixtures do
  176. sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
  177. assert defined?(ModuleFolder::NestedSibling)
  178. assert_equal ModuleFolder::NestedSibling, sibling
  179. Object.__send__ :remove_const, :ModuleFolder
  180. end
  181. end
  182. def test_doesnt_break_normal_require
  183. path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
  184. original_path = $:.dup
  185. original_features = $".dup
  186. $:.push(path)
  187. with_autoloading_fixtures do
  188. # The _ = assignments are to prevent warnings
  189. _ = RequiresConstant
  190. assert defined?(RequiresConstant)
  191. assert defined?(LoadedConstant)
  192. ActiveSupport::Dependencies.clear
  193. _ = RequiresConstant
  194. assert defined?(RequiresConstant)
  195. assert defined?(LoadedConstant)
  196. end
  197. ensure
  198. remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
  199. $".replace(original_features)
  200. $:.replace(original_path)
  201. end
  202. def test_doesnt_break_normal_require_nested
  203. path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
  204. original_path = $:.dup
  205. original_features = $".dup
  206. $:.push(path)
  207. with_autoloading_fixtures do
  208. # The _ = assignments are to prevent warnings
  209. _ = LoadsConstant
  210. assert defined?(LoadsConstant)
  211. assert defined?(LoadedConstant)
  212. ActiveSupport::Dependencies.clear
  213. _ = LoadsConstant
  214. assert defined?(LoadsConstant)
  215. assert defined?(LoadedConstant)
  216. end
  217. ensure
  218. remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
  219. $".replace(original_features)
  220. $:.replace(original_path)
  221. end
  222. def failing_test_access_thru_and_upwards_fails
  223. with_autoloading_fixtures do
  224. assert ! defined?(ModuleFolder)
  225. assert_raise(NameError) { ModuleFolder::Object }
  226. assert_raise(NameError) { ModuleFolder::NestedClass::Object }
  227. Object.__send__ :remove_const, :ModuleFolder
  228. end
  229. end
  230. def test_non_existing_const_raises_name_error_with_fully_qualified_name
  231. with_autoloading_fixtures do
  232. begin
  233. A::DoesNotExist.nil?
  234. flunk "No raise!!"
  235. rescue NameError => e
  236. assert_equal "uninitialized constant A::DoesNotExist", e.message
  237. end
  238. begin
  239. A::B::DoesNotExist.nil?
  240. flunk "No raise!!"
  241. rescue NameError => e
  242. assert_equal "uninitialized constant A::B::DoesNotExist", e.message
  243. end
  244. end
  245. end
  246. def test_smart_name_error_strings
  247. begin
  248. Object.module_eval "ImaginaryObject"
  249. flunk "No raise!!"
  250. rescue NameError => e
  251. assert e.message.include?("uninitialized constant ImaginaryObject")
  252. end
  253. end
  254. def test_loadable_constants_for_path_should_handle_empty_autoloads
  255. assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello')
  256. end
  257. def test_loadable_constants_for_path_should_handle_relative_paths
  258. fake_root = 'dependencies'
  259. relative_root = File.dirname(__FILE__) + '/dependencies'
  260. ['', '/'].each do |suffix|
  261. with_loading fake_root + suffix do
  262. assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b')
  263. end
  264. end
  265. end
  266. def test_loadable_constants_for_path_should_provide_all_results
  267. fake_root = '/usr/apps/backpack'
  268. with_loading fake_root, fake_root + '/lib' do
  269. root = ActiveSupport::Dependencies.autoload_paths.first
  270. assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b')
  271. end
  272. end
  273. def test_loadable_constants_for_path_should_uniq_results
  274. fake_root = '/usr/apps/backpack/lib'
  275. with_loading fake_root, fake_root + '/' do
  276. root = ActiveSupport::Dependencies.autoload_paths.first
  277. assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b')
  278. end
  279. end
  280. def test_loadable_constants_with_load_path_without_trailing_slash
  281. path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb'
  282. with_loading 'autoloading_fixtures/class/' do
  283. assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path)
  284. end
  285. end
  286. def test_qualified_const_defined
  287. assert ActiveSupport::Dependencies.qualified_const_defined?("Object")
  288. assert ActiveSupport::Dependencies.qualified_const_defined?("::Object")
  289. assert ActiveSupport::Dependencies.qualified_const_defined?("::Object::Kernel")
  290. assert ActiveSupport::Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
  291. end
  292. def test_qualified_const_defined_should_not_call_const_missing
  293. ModuleWithMissing.missing_count = 0
  294. assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A")
  295. assert_equal 0, ModuleWithMissing.missing_count
  296. assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
  297. assert_equal 0, ModuleWithMissing.missing_count
  298. end
  299. def test_qualified_const_defined_explodes_with_invalid_const_name
  300. assert_raises(NameError) { ActiveSupport::Dependencies.qualified_const_defined?("invalid") }
  301. end
  302. def test_autoloaded?
  303. with_autoloading_fixtures do
  304. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
  305. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
  306. assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
  307. assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
  308. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
  309. assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
  310. assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
  311. assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
  312. assert ActiveSupport::Dependencies.autoloaded?("::ModuleFolder")
  313. assert ActiveSupport::Dependencies.autoloaded?(:ModuleFolder)
  314. # Anonymous modules aren't autoloaded.
  315. assert !ActiveSupport::Dependencies.autoloaded?(Module.new)
  316. nil_name = Module.new
  317. def nil_name.name() nil end
  318. assert !ActiveSupport::Dependencies.autoloaded?(nil_name)
  319. Object.class_eval { remove_const :ModuleFolder }
  320. end
  321. end
  322. def test_qualified_name_for
  323. assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(Object, :A)
  324. assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(:Object, :A)
  325. assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("Object", :A)
  326. assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Object", :A)
  327. assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(:'ActiveSupport::Dependencies', :A)
  328. assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(ActiveSupport::Dependencies, :A)
  329. end
  330. def test_file_search
  331. with_loading 'dependencies' do
  332. root = ActiveSupport::Dependencies.autoload_paths.first
  333. assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three')
  334. assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three.rb')
  335. assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one')
  336. assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one.rb')
  337. end
  338. end
  339. def test_file_search_uses_first_in_load_path
  340. with_loading 'dependencies', 'autoloading_fixtures' do
  341. deps, autoload = ActiveSupport::Dependencies.autoload_paths
  342. assert_match %r/dependencies/, deps
  343. assert_match %r/autoloading_fixtures/, autoload
  344. assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
  345. end
  346. with_loading 'autoloading_fixtures', 'dependencies' do
  347. autoload, deps = ActiveSupport::Dependencies.autoload_paths
  348. assert_match %r/dependencies/, deps
  349. assert_match %r/autoloading_fixtures/, autoload
  350. assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
  351. end
  352. end
  353. def test_custom_const_missing_should_work
  354. Object.module_eval <<-end_eval, __FILE__, __LINE__ + 1
  355. module ModuleWithCustomConstMissing
  356. def self.const_missing(name)
  357. const_set name, name.to_s.hash
  358. end
  359. module A
  360. end
  361. end
  362. end_eval
  363. with_autoloading_fixtures do
  364. assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
  365. assert_kind_of Module, ::ModuleWithCustomConstMissing::A
  366. assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
  367. end
  368. end
  369. def test_const_missing_should_not_double_load
  370. $counting_loaded_times = 0
  371. with_autoloading_fixtures do
  372. require_dependency '././counting_loader'
  373. assert_equal 1, $counting_loaded_times
  374. assert_raise(NameError) { ActiveSupport::Dependencies.load_missing_constant Object, :CountingLoader }
  375. assert_equal 1, $counting_loaded_times
  376. end
  377. end
  378. def test_const_missing_within_anonymous_module
  379. $counting_loaded_times = 0
  380. m = Module.new
  381. m.module_eval "def a() CountingLoader; end"
  382. extend m
  383. kls = nil
  384. with_autoloading_fixtures do
  385. kls = nil
  386. assert_nothing_raised { kls = a }
  387. assert_equal "CountingLoader", kls.name
  388. assert_equal 1, $counting_loaded_times
  389. assert_nothing_raised { kls = a }
  390. assert_equal 1, $counting_loaded_times
  391. end
  392. end
  393. def test_removal_from_tree_should_be_detected
  394. with_loading 'dependencies' do
  395. c = ServiceOne
  396. ActiveSupport::Dependencies.clear
  397. assert ! defined?(ServiceOne)
  398. begin
  399. ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing)
  400. flunk "Expected exception"
  401. rescue ArgumentError => e
  402. assert_match %r{ServiceOne has been removed from the module tree}i, e.message
  403. end
  404. end
  405. end
  406. def test_references_should_work
  407. with_loading 'dependencies' do
  408. c = ActiveSupport::Dependencies.reference("ServiceOne")
  409. service_one_first = ServiceOne
  410. assert_equal service_one_first, c.get("ServiceOne")
  411. ActiveSupport::Dependencies.clear
  412. assert ! defined?(ServiceOne)
  413. service_one_second = ServiceOne
  414. assert_not_equal service_one_first, c.get("ServiceOne")
  415. assert_equal service_one_second, c.get("ServiceOne")
  416. end
  417. end
  418. def test_constantize_shortcut_for_cached_constant_lookups
  419. with_loading 'dependencies' do
  420. assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne")
  421. end
  422. end
  423. def test_nested_load_error_isnt_rescued
  424. with_loading 'dependencies' do
  425. assert_raise(MissingSourceFile) do
  426. RequiresNonexistent1
  427. end
  428. end
  429. end
  430. def test_autoload_once_paths_do_not_add_to_autoloaded_constants
  431. with_autoloading_fixtures do
  432. ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths.dup
  433. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
  434. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
  435. assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
  436. 1 if ModuleFolder::NestedClass # 1 if to avoid warning
  437. assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
  438. end
  439. ensure
  440. Object.class_eval { remove_const :ModuleFolder }
  441. ActiveSupport::Dependencies.autoload_once_paths = []
  442. end
  443. def test_autoload_once_pathnames_do_not_add_to_autoloaded_constants
  444. with_autoloading_fixtures do
  445. pathnames = ActiveSupport::Dependencies.autoload_paths.collect{|p| Pathname.new(p)}
  446. ActiveSupport::Dependencies.autoload_paths = pathnames
  447. ActiveSupport::Dependencies.autoload_once_paths = pathnames
  448. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
  449. assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
  450. assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
  451. 1 if ModuleFolder::NestedClass # 1 if to avoid warning
  452. assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
  453. end
  454. ensure
  455. Object.class_eval { remove_const :ModuleFolder }
  456. ActiveSupport::Dependencies.autoload_once_paths = []
  457. end
  458. def test_application_should_special_case_application_controller
  459. with_autoloading_fixtures do
  460. require_dependency 'application'
  461. assert_equal 10, ApplicationController
  462. assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController)
  463. end
  464. end
  465. def test_preexisting_constants_are_not_marked_as_autoloaded
  466. with_autoloading_fixtures do
  467. require_dependency 'e'
  468. assert ActiveSupport::Dependencies.autoloaded?(:E)
  469. ActiveSupport::Dependencies.clear
  470. end
  471. Object.const_set :E, Class.new
  472. with_autoloading_fixtures do
  473. require_dependency 'e'
  474. assert ! ActiveSupport::Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
  475. ActiveSupport::Dependencies.clear
  476. end
  477. ensure
  478. Object.class_eval { remove_const :E }
  479. end
  480. def test_unloadable
  481. with_autoloading_fixtures do
  482. Object.const_set :M, Module.new
  483. M.unloadable
  484. ActiveSupport::Dependencies.clear
  485. assert ! defined?(M)
  486. Object.const_set :M, Module.new
  487. ActiveSupport::Dependencies.clear
  488. assert ! defined?(M), "Dependencies should unload unloadable constants each time"
  489. end
  490. end
  491. def test_unloadable_should_fail_with_anonymous_modules
  492. with_autoloading_fixtures do
  493. m = Module.new
  494. assert_raise(ArgumentError) { m.unloadable }
  495. end
  496. end
  497. def test_unloadable_should_return_change_flag
  498. with_autoloading_fixtures do
  499. Object.const_set :M, Module.new
  500. assert_equal true, M.unloadable
  501. assert_equal false, M.unloadable
  502. end
  503. end
  504. def test_unloadable_constants_should_receive_callback
  505. Object.const_set :C, Class.new
  506. C.unloadable
  507. C.expects(:before_remove_const).once
  508. assert C.respond_to?(:before_remove_const)
  509. ActiveSupport::Dependencies.clear
  510. assert !defined?(C)
  511. ensure
  512. Object.class_eval { remove_const :C } if defined?(C)
  513. end
  514. def test_new_contants_in_without_constants
  515. assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
  516. assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
  517. end
  518. def test_new_constants_in_with_a_single_constant
  519. assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) {
  520. Object.const_set :Hello, 10
  521. }.map(&:to_s)
  522. assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
  523. ensure
  524. Object.class_eval { remove_const :Hello }
  525. end
  526. def test_new_constants_in_with_nesting
  527. outer = ActiveSupport::Dependencies.new_constants_in(Object) do
  528. Object.const_set :OuterBefore, 10
  529. assert_equal ["Inner"], ActiveSupport::Dependencies.new_constants_in(Object) {
  530. Object.const_set :Inner, 20
  531. }.map(&:to_s)
  532. Object.const_set :OuterAfter, 30
  533. end
  534. assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
  535. assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
  536. ensure
  537. %w(OuterBefore Inner OuterAfter).each do |name|
  538. Object.class_eval { remove_const name if const_defined?(name) }
  539. end
  540. end
  541. def test_new_constants_in_module
  542. Object.const_set :M, Module.new
  543. outer = ActiveSupport::Dependencies.new_constants_in(M) do
  544. M.const_set :OuterBefore, 10
  545. inner = ActiveSupport::Dependencies.new_constants_in(M) do
  546. M.const_set :Inner, 20
  547. end
  548. assert_equal ["M::Inner"], inner
  549. M.const_set :OuterAfter, 30
  550. end
  551. assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
  552. assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
  553. ensure
  554. Object.class_eval { remove_const :M }
  555. end
  556. def test_new_constants_in_module_using_name
  557. outer = ActiveSupport::Dependencies.new_constants_in(:M) do
  558. Object.const_set :M, Module.new
  559. M.const_set :OuterBefore, 10
  560. inner = ActiveSupport::Dependencies.new_constants_in(:M) do
  561. M.const_set :Inner, 20
  562. end
  563. assert_equal ["M::Inner"], inner
  564. M.const_set :OuterAfter, 30
  565. end
  566. assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
  567. assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
  568. ensure
  569. Object.class_eval { remove_const :M }
  570. end
  571. def test_new_constants_in_with_inherited_constants
  572. m = ActiveSupport::Dependencies.new_constants_in(:Object) do
  573. Object.class_eval { include ModuleWithConstant }
  574. end
  575. assert_equal [], m
  576. end
  577. def test_new_constants_in_with_illegal_module_name_raises_correct_error
  578. assert_raise(NameError) do
  579. ActiveSupport::Dependencies.new_constants_in("Illegal-Name") {}
  580. end
  581. end
  582. def test_file_with_multiple_constants_and_require_dependency
  583. with_autoloading_fixtures do
  584. assert ! defined?(MultipleConstantFile)
  585. assert ! defined?(SiblingConstant)
  586. require_dependency 'multiple_constant_file'
  587. assert defined?(MultipleConstantFile)
  588. assert defined?(SiblingConstant)
  589. assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
  590. assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
  591. ActiveSupport::Dependencies.clear
  592. assert ! defined?(MultipleConstantFile)
  593. assert ! defined?(SiblingConstant)
  594. end
  595. end
  596. def test_file_with_multiple_constants_and_auto_loading
  597. with_autoloading_fixtures do
  598. assert ! defined?(MultipleConstantFile)
  599. assert ! defined?(SiblingConstant)
  600. assert_equal 10, MultipleConstantFile
  601. assert defined?(MultipleConstantFile)
  602. assert defined?(SiblingConstant)
  603. assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
  604. assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
  605. ActiveSupport::Dependencies.clear
  606. assert ! defined?(MultipleConstantFile)
  607. assert ! defined?(SiblingConstant)
  608. end
  609. end
  610. def test_nested_file_with_multiple_constants_and_require_dependency
  611. with_autoloading_fixtures do
  612. assert ! defined?(ClassFolder::NestedClass)
  613. assert ! defined?(ClassFolder::SiblingClass)
  614. require_dependency 'class_folder/nested_class'
  615. assert defined?(ClassFolder::NestedClass)
  616. assert defined?(ClassFolder::SiblingClass)
  617. assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
  618. assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
  619. ActiveSupport::Dependencies.clear
  620. assert ! defined?(ClassFolder::NestedClass)
  621. assert ! defined?(ClassFolder::SiblingClass)
  622. end
  623. end
  624. def test_nested_file_with_multiple_constants_and_auto_loading
  625. with_autoloading_fixtures do
  626. assert ! defined?(ClassFolder::NestedClass)
  627. assert ! defined?(ClassFolder::SiblingClass)
  628. assert_kind_of Class, ClassFolder::NestedClass
  629. assert defined?(ClassFolder::NestedClass)
  630. assert defined?(ClassFolder::SiblingClass)
  631. assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
  632. assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
  633. ActiveSupport::Dependencies.clear
  634. assert ! defined?(ClassFolder::NestedClass)
  635. assert ! defined?(ClassFolder::SiblingClass)
  636. end
  637. end
  638. def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
  639. with_autoloading_fixtures do
  640. assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
  641. 2.times do
  642. assert_raise(NoMethodError) { RaisesNoMethodError }
  643. assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
  644. end
  645. end
  646. ensure
  647. Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
  648. end
  649. def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
  650. with_autoloading_fixtures do
  651. assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
  652. 2.times do
  653. assert_raise(NoMethodError) { ::RaisesNoMethodError }
  654. assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
  655. end
  656. end
  657. ensure
  658. Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
  659. end
  660. def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load
  661. with_autoloading_fixtures do
  662. ActiveSupport::Dependencies.mechanism = :require
  663. 2.times do
  664. assert_raise(NameError) { assert_equal 123, ::RaisesNameError::FooBarBaz }
  665. end
  666. end
  667. end
  668. def test_autoload_doesnt_shadow_name_error
  669. with_autoloading_fixtures do
  670. Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
  671. 2.times do |i|
  672. begin
  673. ::RaisesNameError::FooBarBaz.object_id
  674. flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
  675. rescue NameError => e
  676. assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
  677. end
  678. assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
  679. end
  680. assert !defined?(::RaisesNameError)
  681. 2.times do
  682. assert_raise(NameError) { ::RaisesNameError }
  683. assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
  684. end
  685. end
  686. ensure
  687. Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
  688. end
  689. def test_remove_constant_handles_double_colon_at_start
  690. Object.const_set 'DeleteMe', Module.new
  691. DeleteMe.const_set 'OrMe', Module.new
  692. ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe"
  693. assert ! defined?(DeleteMe::OrMe)
  694. assert defined?(DeleteMe)
  695. ActiveSupport::Dependencies.remove_constant "::DeleteMe"
  696. assert ! defined?(DeleteMe)
  697. end
  698. def test_load_once_constants_should_not_be_unloaded
  699. with_autoloading_fixtures do
  700. ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths
  701. ::A.to_s
  702. assert defined?(A)
  703. ActiveSupport::Dependencies.clear
  704. assert defined?(A)
  705. end
  706. ensure
  707. ActiveSupport::Dependencies.autoload_once_paths = []
  708. Object.class_eval { remove_const :A if const_defined?(:A) }
  709. end
  710. def test_autoload_once_paths_should_behave_when_recursively_loading
  711. with_loading 'dependencies', 'autoloading_fixtures' do
  712. ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last]
  713. assert !defined?(CrossSiteDependency)
  714. assert_nothing_raised { CrossSiteDepender.nil? }
  715. assert defined?(CrossSiteDependency)
  716. assert !ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
  717. "CrossSiteDependency shouldn't be marked as autoloaded!"
  718. ActiveSupport::Dependencies.clear
  719. assert defined?(CrossSiteDependency),
  720. "CrossSiteDependency shouldn't have been unloaded!"
  721. end
  722. ensure
  723. ActiveSupport::Dependencies.autoload_once_paths = []
  724. end
  725. def test_hook_called_multiple_times
  726. assert_nothing_raised { ActiveSupport::Dependencies.hook! }
  727. end
  728. def test_unhook
  729. ActiveSupport::Dependencies.unhook!
  730. assert !Module.new.respond_to?(:const_missing_without_dependencies)
  731. assert !Module.new.respond_to?(:load_without_new_constant_marking)
  732. ensure
  733. ActiveSupport::Dependencies.hook!
  734. end
  735. private
  736. def remove_constants(*constants)
  737. constants.each do |constant|
  738. Object.send(:remove_const, constant) if Object.const_defined?(constant)
  739. end
  740. end
  741. end