diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index fecabc4086..a7a93dc6a5 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative "dependencies_test_helpers" +require_relative "constantize_test_helpers" module Ace module Base @@ -27,7 +27,7 @@ class Object end module ConstantizeTestCases - include DependenciesTestHelpers + include ConstantizeTestHelpers def run_constantize_tests_on assert_equal Ace::Base::Case, yield("Ace::Base::Case") @@ -75,11 +75,6 @@ module ConstantizeTestCases yield("RaisesNoMethodError") end end - - with_autoloading_fixtures do - yield("Prepend::SubClassConflict") - assert_equal "constant", defined?(Prepend::SubClassConflict) - end end def run_safe_constantize_tests_on @@ -112,10 +107,6 @@ module ConstantizeTestCases assert_nil yield("A::Object::B") assert_nil yield("A::Object::Object::Object::B") - with_autoloading_fixtures do - assert_nil yield("Em") - end - assert_raises(LoadError) do with_autoloading_fixtures do yield("RaisesLoadError") diff --git a/activesupport/test/constantize_test_helpers.rb b/activesupport/test/constantize_test_helpers.rb new file mode 100644 index 0000000000..e6e7afe84e --- /dev/null +++ b/activesupport/test/constantize_test_helpers.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module ConstantizeTestHelpers + ROOT_DIR = File.realpath("#{__dir__}/autoloading_fixtures") + AUTOLOADS = { + "RaisesLoadError" => "#{ROOT_DIR}/raises_load_error", + "RaisesNameError" => "#{ROOT_DIR}/raises_name_error", + "RaisesNoMethodError" => "#{ROOT_DIR}/raises_no_method_error" + } + + def with_autoloading_fixtures + define_autoloads + yield + ensure + remove_autoloads + end + + def define_autoloads + AUTOLOADS.each do |constant, realpath| + Object.autoload(constant, realpath) + end + end + + def remove_autoloads + AUTOLOADS.each do |constant, realpath| + Object.send(:remove_const, constant) if Object.const_defined?(constant) + $LOADED_FEATURES.delete(realpath) + end + end +end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 5d938d0eb5..3066ec544c 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -3,7 +3,6 @@ require_relative "abstract_unit" require "pp" require "active_support/dependencies" -require_relative "dependencies_test_helpers" module ModuleWithMissing mattr_accessor :missing_count @@ -18,8 +17,6 @@ module ModuleWithConstant end class DependenciesTest < ActiveSupport::TestCase - include DependenciesTestHelpers - setup do @loaded_features_copy = $LOADED_FEATURES.dup $LOAD_PATH << "test" @@ -49,427 +46,10 @@ class DependenciesTest < ActiveSupport::TestCase assert_equal "No such file to load -- omgwtfbbq.rb", e.message end - def test_require_dependency_accepts_an_object_which_implements_to_path - o = Object.new - def o.to_path; "dependencies/service_one"; end - assert_nothing_raised { - require_dependency o - } - assert defined?(ServiceOne) - ensure - remove_constants(:ServiceOne) - end - - def test_tracking_loaded_files - with_loading do - require_dependency "dependencies/service_one" - require_dependency "dependencies/service_two" - assert_equal 2, ActiveSupport::Dependencies.loaded.size - end - ensure - remove_constants(:ServiceOne, :ServiceTwo) - end - - def test_tracking_identical_loaded_files - with_loading do - require_dependency "dependencies/service_one" - require_dependency "dependencies/service_one" - assert_equal 1, ActiveSupport::Dependencies.loaded.size - end - ensure - remove_constants(:ServiceOne) - end - def test_missing_dependency_raises_missing_source_file assert_raise(LoadError) { require_dependency("missing_service") } end - def test_dependency_which_raises_exception_isnt_added_to_loaded_set - with_loading do - filename = "dependencies/raises_exception" - expanded = File.expand_path(filename) - $raises_exception_load_count = 0 - - 5.times do |count| - e = assert_raise Exception, "should have loaded dependencies/raises_exception which raises an exception" do - require_dependency filename - end - - assert_equal "Loading me failed, so do not add to loaded or history.", e.message - assert_equal count + 1, $raises_exception_load_count - - assert_not ActiveSupport::Dependencies.loaded.include?(expanded) - assert_not ActiveSupport::Dependencies.history.include?(expanded) - end - end - end - - def test_mutual_dependencies_dont_infinite_loop - with_loading "dependencies" do - $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency "mutual_one" } - assert_equal 2, $mutual_dependencies_count - - ActiveSupport::Dependencies.clear - - $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency "mutual_two" } - assert_equal 2, $mutual_dependencies_count - end - end - - def test_circular_autoloading_detection - with_autoloading_fixtures do - e = assert_raise(RuntimeError) { Circular1 } - assert_equal "Circular dependency detected while autoloading constant Circular1", e.message - end - end - - def test_ensures_the_expected_constant_is_defined - with_autoloading_fixtures do - e = assert_raise(LoadError) { Typo } - assert_match %r{Unable to autoload constant Typo, expected .*/test/autoloading_fixtures/typo.rb to define it}, e.message - end - end - - def test_require_dependency_does_not_assume_any_particular_constant_is_defined - with_autoloading_fixtures do - require_dependency "typo" - assert_equal 1, TypO - end - end - - # Regression, see https://github.com/rails/rails/issues/16468. - def test_require_dependency_interaction_with_autoloading - with_autoloading_fixtures do - require_dependency "typo" - assert_equal 1, TypO - - e = assert_raise(LoadError) { Typo } - assert_match %r{Unable to autoload constant Typo, expected .*/test/autoloading_fixtures/typo.rb to define it}, e.message - end - end - - # Regression see https://github.com/rails/rails/issues/31694 - def test_included_constant_that_changes_to_have_exception_then_back_does_not_loop_forever - # This constant references a nested constant whose namespace will be auto-generated - parent_constant = <<-RUBY - class ConstantReloadError - AnotherConstant::ReloadError - end - RUBY - - # This constant's namespace will be auto-generated, - # also, we'll edit it to contain an error at load-time - child_constant = <<-RUBY - class AnotherConstant::ReloadError - # no_such_method_as_this - end - RUBY - - # Create a version which contains an error during loading - child_constant_with_error = child_constant.sub("# no_such_method_as_this", "no_such_method_as_this") - - fixtures_path = File.join(__dir__, "autoloading_fixtures") - Dir.mktmpdir(nil, fixtures_path) do |tmpdir| - # Set up the file structure where constants will be loaded from - child_constant_path = "#{tmpdir}/another_constant/reload_error.rb" - File.write("#{tmpdir}/constant_reload_error.rb", parent_constant) - Dir.mkdir("#{tmpdir}/another_constant") - File.write(child_constant_path, child_constant_with_error) - - tmpdir_name = tmpdir.split("/").last - with_loading("autoloading_fixtures/#{tmpdir_name}") do - # Load the file, with the error: - assert_raises(NameError) { - ConstantReloadError - } - - Timeout.timeout(0.1) do - # Remove the constant, as if Rails development middleware is reloading changed files: - ActiveSupport::Dependencies.remove_unloadable_constants! - assert_not defined?(AnotherConstant::ReloadError) - end - - # Change the file, so that it is **correct** this time: - File.write(child_constant_path, child_constant) - - # Again: Remove the constant, as if Rails development middleware is reloading changed files: - ActiveSupport::Dependencies.remove_unloadable_constants! - assert_not defined?(AnotherConstant::ReloadError) - - # Now, reload the _fixed_ constant: - assert ConstantReloadError - assert AnotherConstant::ReloadError - end - end - end - - def test_module_loading - with_autoloading_fixtures do - assert_kind_of Module, A - assert_kind_of Class, A::B - assert_kind_of Class, A::C::D - assert_kind_of Class, A::C::EM::F - end - end - - def test_non_existing_const_raises_name_error - with_autoloading_fixtures do - assert_raise(NameError) { DoesNotExist } - assert_raise(NameError) { NoModule::DoesNotExist } - assert_raise(NameError) { A::DoesNotExist } - assert_raise(NameError) { A::B::DoesNotExist } - end - end - - def test_directories_manifest_as_modules_unless_const_defined - with_autoloading_fixtures do - assert_kind_of Module, ModuleFolder - end - ensure - remove_constants(:ModuleFolder) - end - - def test_module_with_nested_class - with_autoloading_fixtures do - assert_kind_of Class, ModuleFolder::NestedClass - end - ensure - remove_constants(:ModuleFolder) - end - - def test_module_with_nested_inline_class - with_autoloading_fixtures do - assert_kind_of Class, ModuleFolder::InlineClass - end - ensure - remove_constants(:ModuleFolder) - end - - def test_module_with_nested_class_requiring_lib_class - with_autoloading_fixtures do - _ = ModuleFolder::NestedWithRequire # assignment to silence parse-time warning "possibly useless use of :: in void context" - - assert defined?(ModuleFolder::LibClass) - assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ModuleFolder::LibClass") - assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ConstFromLib") - end - ensure - remove_constants(:ModuleFolder) - remove_constants(:ConstFromLib) - end - - def test_module_with_nested_class_and_parent_requiring_lib_class - with_autoloading_fixtures do - _ = NestedWithRequireParent # assignment to silence parse-time warning "possibly useless use of a constant in void context" - - assert defined?(ModuleFolder::LibClass) - assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ModuleFolder::LibClass") - assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ConstFromLib") - end - ensure - remove_constants(:ModuleFolder) - remove_constants(:ConstFromLib) - end - - def test_directories_may_manifest_as_nested_classes - with_autoloading_fixtures do - assert_kind_of Class, ClassFolder - end - ensure - remove_constants(:ClassFolder) - end - - def test_class_with_nested_class - with_autoloading_fixtures do - assert_kind_of Class, ClassFolder::NestedClass - end - ensure - remove_constants(:ClassFolder) - end - - def test_class_with_nested_inline_class - with_autoloading_fixtures do - assert_kind_of Class, ClassFolder::InlineClass - end - ensure - remove_constants(:ClassFolder) - end - - def test_class_with_nested_inline_subclass_of_parent - with_autoloading_fixtures do - assert_kind_of Class, ClassFolder::ClassFolderSubclass - assert_kind_of Class, ClassFolder - assert_equal "indeed", ClassFolder::ClassFolderSubclass::ConstantInClassFolder - end - ensure - remove_constants(:ClassFolder) - end - - def test_nested_class_can_access_sibling - with_autoloading_fixtures do - sibling = ModuleFolder::NestedClass.class_eval "NestedSibling" - assert defined?(ModuleFolder::NestedSibling) - assert_equal ModuleFolder::NestedSibling, sibling - end - ensure - remove_constants(:ModuleFolder) - end - - def test_raising_discards_autoloaded_constants - with_autoloading_fixtures do - e = assert_raises(Exception) { RaisesArbitraryException } - assert_equal("arbitrary exception message", e.message) - assert_not defined?(A) - assert_not defined?(RaisesArbitraryException) - end - ensure - remove_constants(:A, :RaisesArbitraryException) - end - - def test_throwing_discards_autoloaded_constants - with_autoloading_fixtures do - catch :t do - Throws - end - assert_not defined?(A) - assert_not defined?(Throws) - end - ensure - remove_constants(:A, :Throws) - end - - def test_doesnt_break_normal_require - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - with_autoloading_fixtures do - # The _ = assignments are to prevent warnings - _ = RequiresConstant - assert defined?(RequiresConstant) - assert defined?(LoadedConstant) - ActiveSupport::Dependencies.clear - _ = RequiresConstant - assert defined?(RequiresConstant) - assert defined?(LoadedConstant) - end - ensure - remove_constants(:RequiresConstant, :LoadedConstant) - $:.replace(original_path) - end - - def test_doesnt_break_normal_require_nested - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - - with_autoloading_fixtures do - # The _ = assignments are to prevent warnings - _ = LoadsConstant - assert defined?(LoadsConstant) - assert defined?(LoadedConstant) - ActiveSupport::Dependencies.clear - _ = LoadsConstant - assert defined?(LoadsConstant) - assert defined?(LoadedConstant) - end - ensure - remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant) - $:.replace(original_path) - end - - def test_require_returns_true_when_file_not_yet_required - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - - with_loading do - assert_equal true, require("loaded_constant") - end - ensure - remove_constants(:LoadedConstant) - $:.replace(original_path) - end - - def test_require_returns_true_when_file_not_yet_required_even_when_no_new_constants_added - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - - with_loading do - Object.module_eval "module LoadedConstant; end" - assert_equal true, require("loaded_constant") - end - ensure - remove_constants(:LoadedConstant) - $:.replace(original_path) - end - - def test_require_returns_false_when_file_already_required - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - - with_loading do - require "loaded_constant" - assert_equal false, require("loaded_constant") - end - ensure - remove_constants(:LoadedConstant) - $:.replace(original_path) - end - - def test_require_raises_load_error_when_file_not_found - with_loading do - assert_raise(LoadError) { require "this_file_dont_exist_dude" } - end - end - - def test_load_returns_true_when_file_found - path = File.expand_path("autoloading_fixtures/load_path", __dir__) - original_path = $:.dup - $:.push(path) - - with_loading do - assert_equal true, load("loaded_constant.rb") - assert_equal true, load("loaded_constant.rb") - end - ensure - remove_constants(:LoadedConstant) - $:.replace(original_path) - end - - def test_load_raises_load_error_when_file_not_found - with_loading do - assert_raise(LoadError) { load "this_file_dont_exist_dude.rb" } - end - end - - def test_access_thru_and_upwards_fails - with_autoloading_fixtures do - assert_not defined?(ModuleFolder) - assert_raise(NameError) { ModuleFolder::Object } - assert_raise(NameError) { ModuleFolder::NestedClass::Object } - end - ensure - remove_constants(:ModuleFolder) - end - - def test_non_existing_const_raises_name_error_with_fully_qualified_name - with_autoloading_fixtures do - e = assert_raise(NameError) { A::DoesNotExist.nil? } - assert_equal "uninitialized constant A::DoesNotExist", e.message - assert_equal :DoesNotExist, e.name - - e = assert_raise(NameError) { A::B::DoesNotExist.nil? } - assert_equal "uninitialized constant A::B::DoesNotExist", e.message - assert_equal :DoesNotExist, e.name - end - ensure - remove_constants(:A) - end - def test_smart_name_error_strings e = assert_raise NameError do Object.module_eval "ImaginaryObject" @@ -481,39 +61,6 @@ class DependenciesTest < ActiveSupport::TestCase assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path("hello") end - def test_loadable_constants_for_path_should_handle_relative_paths - fake_root = "dependencies" - relative_root = File.expand_path("dependencies", __dir__) - ["", "/"].each do |suffix| - with_loading fake_root + suffix do - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + "/a/b") - end - end - end - - def test_loadable_constants_for_path_should_provide_all_results - fake_root = "/usr/apps/backpack" - with_loading fake_root, fake_root + "/lib" do - root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/lib/a/b") - end - end - - def test_loadable_constants_for_path_should_uniq_results - fake_root = "/usr/apps/backpack/lib" - with_loading fake_root, fake_root + "/" do - root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/a/b") - end - end - - def test_loadable_constants_with_load_path_without_trailing_slash - path = File.expand_path("autoloading_fixtures/class_folder/inline_class.rb", __dir__) - with_loading "autoloading_fixtures/class/" do - assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path) - end - end - def test_qualified_const_defined assert ActiveSupport::Dependencies.qualified_const_defined?("Object") assert ActiveSupport::Dependencies.qualified_const_defined?("::Object") @@ -533,42 +80,6 @@ class DependenciesTest < ActiveSupport::TestCase assert_raises(NameError) { ActiveSupport::Dependencies.qualified_const_defined?("invalid") } end - def test_autoloaded? - with_autoloading_fixtures do - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder") - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass") - - assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder) - - assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder") - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass") - - assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass) - - assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder") - assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass") - - assert ActiveSupport::Dependencies.autoloaded?("::ModuleFolder") - assert ActiveSupport::Dependencies.autoloaded?(:ModuleFolder) - - # Anonymous modules aren't autoloaded. - assert_not ActiveSupport::Dependencies.autoloaded?(Module.new) - - nil_name = Module.new - def nil_name.name() nil end - assert_not ActiveSupport::Dependencies.autoloaded?(nil_name) - - invalid_constant_name = Module.new do - def self.name - "primary::SchemaMigration" - end - end - assert_not ActiveSupport::Dependencies.autoloaded?(invalid_constant_name) - end - ensure - remove_constants(:ModuleFolder) - end - def test_qualified_name_for assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(Object, :A) assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(:Object, :A) @@ -579,290 +90,6 @@ class DependenciesTest < ActiveSupport::TestCase assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(ActiveSupport::Dependencies, :A) end - def test_file_search - with_loading "dependencies" do - root = ActiveSupport::Dependencies.autoload_paths.first - assert_nil ActiveSupport::Dependencies.search_for_file("service_three") - assert_nil ActiveSupport::Dependencies.search_for_file("service_three.rb") - assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one") - assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one.rb") - end - end - - def test_file_search_uses_first_in_load_path - with_loading "dependencies", "autoloading_fixtures" do - deps, autoload = ActiveSupport::Dependencies.autoload_paths - assert_match %r/dependencies/, deps - assert_match %r/autoloading_fixtures/, autoload - - assert_equal deps + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") - end - with_loading "autoloading_fixtures", "dependencies" do - autoload, deps = ActiveSupport::Dependencies.autoload_paths - assert_match %r/dependencies/, deps - assert_match %r/autoloading_fixtures/, autoload - - assert_equal autoload + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") - end - end - - def test_custom_const_missing_should_work - Object.module_eval <<-end_eval, __FILE__, __LINE__ + 1 - module ModuleWithCustomConstMissing - def self.const_missing(name) - const_set name, name.to_s.hash - end - - module A - end - end - end_eval - - with_autoloading_fixtures do - assert_kind_of Integer, ::ModuleWithCustomConstMissing::B - assert_kind_of Module, ::ModuleWithCustomConstMissing::A - assert_kind_of String, ::ModuleWithCustomConstMissing::A::B - end - ensure - remove_constants(:ModuleWithCustomConstMissing) - end - - def test_const_missing_in_anonymous_modules_loads_top_level_constants - with_autoloading_fixtures do - # class_eval STRING pushes the class to the nesting of the eval'ed code. - klass = Class.new.class_eval "EM" - assert_equal EM, klass - end - ensure - remove_constants(:EM) - end - - def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object - with_autoloading_fixtures do - require_dependency "em" - - mod = Module.new - e = assert_raise(NameError) { mod::EM } - assert_equal "EM cannot be autoloaded from an anonymous class or module", e.message - assert_equal :EM, e.name - end - ensure - remove_constants(:EM) - end - - def test_removal_from_tree_should_be_detected - with_loading "dependencies" do - c = ServiceOne - ActiveSupport::Dependencies.clear - assert_not defined?(ServiceOne) - e = assert_raise ArgumentError do - ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing) - end - assert_match %r{ServiceOne has been removed from the module tree}i, e.message - end - ensure - remove_constants(:ServiceOne) - end - - def test_constantize_shortcut_for_cached_constant_lookups - with_loading "dependencies" do - assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne") - end - ensure - remove_constants(:ServiceOne) - end - - def test_nested_load_error_isnt_rescued - with_loading "dependencies" do - assert_raise(LoadError) do - RequiresNonexistent1 - end - end - end - - def test_autoload_once_paths_do_not_add_to_autoloaded_constants - old_path = ActiveSupport::Dependencies.autoload_once_paths - with_autoloading_fixtures do - ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths.dup - - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder") - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass") - assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder) - - 1 if ModuleFolder::NestedClass # 1 if to avoid warning - assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass) - end - ensure - remove_constants(:ModuleFolder) - ActiveSupport::Dependencies.autoload_once_paths = old_path - end - - def test_autoload_once_pathnames_do_not_add_to_autoloaded_constants - with_autoloading_fixtures do - pathnames = ActiveSupport::Dependencies.autoload_paths.collect { |p| Pathname.new(p) } - ActiveSupport::Dependencies.autoload_paths = pathnames - ActiveSupport::Dependencies.autoload_once_paths = pathnames - - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder") - assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass") - assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder) - - 1 if ModuleFolder::NestedClass # 1 if to avoid warning - assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass) - end - ensure - remove_constants(:ModuleFolder) - ActiveSupport::Dependencies.autoload_once_paths = [] - end - - def test_application_should_special_case_application_controller - with_autoloading_fixtures do - require_dependency "application" - assert_equal 10, ApplicationController - assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController) - end - ensure - remove_constants(:ApplicationController) - end - - def test_preexisting_constants_are_not_marked_as_autoloaded - with_autoloading_fixtures do - require_dependency "em" - assert ActiveSupport::Dependencies.autoloaded?(:EM) - ActiveSupport::Dependencies.clear - end - - Object.const_set :EM, Class.new - with_autoloading_fixtures do - require_dependency "em" - assert_not ActiveSupport::Dependencies.autoloaded?(:EM), "EM shouldn't be marked autoloaded!" - ActiveSupport::Dependencies.clear - end - ensure - remove_constants(:EM) - end - - def test_constants_in_capitalized_nesting_marked_as_autoloaded - with_autoloading_fixtures do - ActiveSupport::Dependencies.load_missing_constant(HTML, "SomeClass") - - assert ActiveSupport::Dependencies.autoloaded?("HTML::SomeClass") - end - ensure - remove_constants(:HTML) - end - - def test_unloadable - with_autoloading_fixtures do - Object.const_set :M, Module.new - M.unloadable - - ActiveSupport::Dependencies.clear - assert_not defined?(M) - - Object.const_set :M, Module.new - ActiveSupport::Dependencies.clear - assert_not defined?(M), "Dependencies should unload unloadable constants each time" - end - end - - def test_unloadable_should_fail_with_anonymous_modules - with_autoloading_fixtures do - m = Module.new - assert_raise(ArgumentError) { m.unloadable } - end - end - - def test_unloadable_should_return_change_flag - with_autoloading_fixtures do - Object.const_set :M, Module.new - assert_equal true, M.unloadable - assert_equal false, M.unloadable - end - ensure - remove_constants(:M) - end - - def test_unloadable_constants_should_receive_callback - Object.const_set :C, Class.new { def self.before_remove_const; end } - C.unloadable - assert_called(C, :before_remove_const, times: 1) do - assert_respond_to C, :before_remove_const - ActiveSupport::Dependencies.clear - assert_not defined?(C) - end - ensure - remove_constants(:C) - end - - def test_new_constants_in_without_constants - assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { }) - assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } - end - - def test_new_constants_in_with_a_single_constant - assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) { - Object.const_set :Hello, 10 - }.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } - ensure - remove_constants(:Hello) - end - - def test_new_constants_in_with_nesting - outer = ActiveSupport::Dependencies.new_constants_in(Object) do - Object.const_set :OuterBefore, 10 - - assert_equal ["Inner"], ActiveSupport::Dependencies.new_constants_in(Object) { - Object.const_set :Inner, 20 - }.map(&:to_s) - - Object.const_set :OuterAfter, 30 - end - - assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } - ensure - remove_constants(:OuterBefore, :Inner, :OuterAfter) - end - - def test_new_constants_in_module - Object.const_set :M, Module.new - - outer = ActiveSupport::Dependencies.new_constants_in(M) do - M.const_set :OuterBefore, 10 - - inner = ActiveSupport::Dependencies.new_constants_in(M) do - M.const_set :Inner, 20 - end - assert_equal ["M::Inner"], inner - - M.const_set :OuterAfter, 30 - end - assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } - ensure - remove_constants(:M) - end - - def test_new_constants_in_module_using_name - outer = ActiveSupport::Dependencies.new_constants_in(:M) do - Object.const_set :M, Module.new - M.const_set :OuterBefore, 10 - - inner = ActiveSupport::Dependencies.new_constants_in(:M) do - M.const_set :Inner, 20 - end - assert_equal ["M::Inner"], inner - - M.const_set :OuterAfter, 30 - end - assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } - ensure - remove_constants(:M) - end - def test_new_constants_in_with_inherited_constants m = ActiveSupport::Dependencies.new_constants_in(:Object) do Object.class_eval { include ModuleWithConstant } @@ -876,224 +103,6 @@ class DependenciesTest < ActiveSupport::TestCase end end - def test_file_with_multiple_constants_and_require_dependency - with_autoloading_fixtures do - assert_not defined?(MultipleConstantFile) - assert_not defined?(SiblingConstant) - - require_dependency "multiple_constant_file" - assert defined?(MultipleConstantFile) - assert defined?(SiblingConstant) - assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile) - assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant) - ActiveSupport::Dependencies.clear - - assert_not defined?(MultipleConstantFile) - assert_not defined?(SiblingConstant) - end - ensure - remove_constants(:MultipleConstantFile, :SiblingConstant) - end - - def test_file_with_multiple_constants_and_auto_loading - with_autoloading_fixtures do - assert_not defined?(MultipleConstantFile) - assert_not defined?(SiblingConstant) - - assert_equal 10, MultipleConstantFile - - assert defined?(MultipleConstantFile) - assert defined?(SiblingConstant) - assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile) - assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant) - - ActiveSupport::Dependencies.clear - - assert_not defined?(MultipleConstantFile) - assert_not defined?(SiblingConstant) - end - ensure - remove_constants(:MultipleConstantFile, :SiblingConstant) - end - - def test_nested_file_with_multiple_constants_and_require_dependency - with_autoloading_fixtures do - assert_not defined?(ClassFolder::NestedClass) - assert_not defined?(ClassFolder::SiblingClass) - - require_dependency "class_folder/nested_class" - - assert defined?(ClassFolder::NestedClass) - assert defined?(ClassFolder::SiblingClass) - assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass") - assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass") - - ActiveSupport::Dependencies.clear - - assert_not defined?(ClassFolder::NestedClass) - assert_not defined?(ClassFolder::SiblingClass) - end - ensure - remove_constants(:ClassFolder) - end - - def test_nested_file_with_multiple_constants_and_auto_loading - with_autoloading_fixtures do - assert_not defined?(ClassFolder::NestedClass) - assert_not defined?(ClassFolder::SiblingClass) - - assert_kind_of Class, ClassFolder::NestedClass - - assert defined?(ClassFolder::NestedClass) - assert defined?(ClassFolder::SiblingClass) - assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass") - assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass") - - ActiveSupport::Dependencies.clear - - assert_not defined?(ClassFolder::NestedClass) - assert_not defined?(ClassFolder::SiblingClass) - end - ensure - remove_constants(:ClassFolder) - end - - def test_autoload_doesnt_shadow_no_method_error_with_relative_constant - with_autoloading_fixtures do - assert_not defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!" - 2.times do - assert_raise(NoMethodError) { RaisesNoMethodError } - assert_not defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!" - end - end - ensure - remove_constants(:RaisesNoMethodError) - end - - def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant - with_autoloading_fixtures do - assert_not defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!" - 2.times do - assert_raise(NoMethodError) { ::RaisesNoMethodError } - assert_not defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!" - end - end - ensure - remove_constants(:RaisesNoMethodError) - end - - def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load - with_autoloading_fixtures do - ActiveSupport::Dependencies.mechanism = :require - 2.times do - assert_raise(NameError) { assert_equal 123, ::RaisesNameError::FooBarBaz } - end - end - ensure - remove_constants(:RaisesNameError) - end - - def test_autoload_doesnt_shadow_name_error - with_autoloading_fixtures do - 2.times do - e = assert_raise NameError do - ::RaisesNameError::FooBarBaz.object_id - end - assert_equal "uninitialized constant RaisesNameError::FooBarBaz", e.message - assert_not defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!" - end - - assert_not defined?(::RaisesNameError) - 2.times do - assert_raise(NameError) { ::RaisesNameError } - assert_not defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!" - end - end - ensure - remove_constants(:RaisesNameError) - end - - def test_remove_constant_handles_double_colon_at_start - Object.const_set "DeleteMe", Module.new - DeleteMe.const_set "OrMe", Module.new - ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe" - assert_not defined?(DeleteMe::OrMe) - assert defined?(DeleteMe) - ActiveSupport::Dependencies.remove_constant "::DeleteMe" - assert_not defined?(DeleteMe) - ensure - remove_constants(:DeleteMe) - end - - def test_remove_constant_does_not_trigger_loading_autoloads - constant = "ShouldNotBeAutoloaded" - Object.class_eval do - autoload constant, File.expand_path("autoloading_fixtures/should_not_be_required", __dir__) - end - - assert_nil ActiveSupport::Dependencies.remove_constant(constant), "Kernel#autoload has been triggered by remove_constant" - assert_not defined?(ShouldNotBeAutoloaded) - ensure - remove_constants(constant) - end - - def test_remove_constant_does_not_autoload_already_removed_parents_as_a_side_effect - with_autoloading_fixtures do - _ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context" - _ = ::A::B # assignment to silence parse-time warning "possibly useless use of :: in void context" - ActiveSupport::Dependencies.remove_constant("A") - ActiveSupport::Dependencies.remove_constant("A::B") - assert_not defined?(A) - end - ensure - remove_constants(:A) - end - - def test_load_once_constants_should_not_be_unloaded - old_path = ActiveSupport::Dependencies.autoload_once_paths - with_autoloading_fixtures do - ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths - _ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context" - assert defined?(A) - ActiveSupport::Dependencies.clear - assert defined?(A) - end - ensure - ActiveSupport::Dependencies.autoload_once_paths = old_path - remove_constants(:A) - end - - def test_access_unloaded_constants_for_reload - with_autoloading_fixtures do - assert_kind_of Module, A - assert_kind_of Class, A::B # Necessary to load A::B for the test - ActiveSupport::Dependencies.mark_for_unload(A::B) - ActiveSupport::Dependencies.remove_unloadable_constants! - - A::B # Make sure no circular dependency error - end - ensure - remove_constants(:A) - end - - def test_autoload_once_paths_should_behave_when_recursively_loading - old_path = ActiveSupport::Dependencies.autoload_once_paths - with_loading "dependencies", "autoloading_fixtures" do - ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last] - assert_not defined?(CrossSiteDependency) - assert_nothing_raised { CrossSiteDepender.nil? } - assert defined?(CrossSiteDependency) - assert_not ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency), - "CrossSiteDependency shouldn't be marked as autoloaded!" - ActiveSupport::Dependencies.clear - assert defined?(CrossSiteDependency), - "CrossSiteDependency shouldn't have been unloaded!" - end - ensure - ActiveSupport::Dependencies.autoload_once_paths = old_path - remove_constants(:CrossSiteDependency) - end - def test_hook_called_multiple_times assert_nothing_raised { ActiveSupport::Dependencies.hook! } end diff --git a/activesupport/test/dependencies_test_helpers.rb b/activesupport/test/dependencies_test_helpers.rb deleted file mode 100644 index b54a7e70c8..0000000000 --- a/activesupport/test/dependencies_test_helpers.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module DependenciesTestHelpers - def with_loading(*from) - old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load - this_dir = __dir__ - parent_dir = File.dirname(this_dir) - path_copy = $LOAD_PATH.dup - $LOAD_PATH.unshift(parent_dir) unless $LOAD_PATH.include?(parent_dir) - prior_autoload_paths = ActiveSupport::Dependencies.autoload_paths - ActiveSupport::Dependencies.autoload_paths = from.collect { |f| "#{this_dir}/#{f}" } - yield - ensure - $LOAD_PATH.replace(path_copy) - ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths - ActiveSupport::Dependencies.mechanism = old_mechanism - ActiveSupport::Dependencies.explicitly_unloadable_constants = [] - ActiveSupport::Dependencies.clear - end - - def with_autoloading_fixtures(&block) - with_loading "autoloading_fixtures", &block - end - - def remove_constants(*constants) - constants.each do |constant| - Object.send(:remove_const, constant) if Object.const_defined?(constant) - end - end -end