dependencies_test.rb 34.9 KB
Newer Older
1
require 'abstract_unit'
2
require 'pp'
J
Jeremy Kemper 已提交
3
require 'active_support/dependencies'
4
require 'dependencies_test_helpers'
5

6 7 8 9 10 11 12 13
module ModuleWithMissing
  mattr_accessor :missing_count
  def self.const_missing(name)
    self.missing_count += 1
    name
  end
end

14 15 16 17
module ModuleWithConstant
  InheritedConstant = "Hello"
end

18
class DependenciesTest < ActiveSupport::TestCase
19 20 21 22
  include DependenciesTestHelpers

  setup do
    @loaded_features_copy = $LOADED_FEATURES.dup
23
  end
24

25 26 27 28
  teardown do
    ActiveSupport::Dependencies.clear
    $LOADED_FEATURES.replace(@loaded_features_copy)
  end
J
Jeremy Kemper 已提交
29

30 31 32 33 34 35 36 37 38 39 40
  def test_depend_on_path
    expected = assert_raises(LoadError) do
      Kernel.require 'omgwtfbbq'
    end

    e = assert_raises(LoadError) do
      ActiveSupport::Dependencies.depend_on 'omgwtfbbq'
    end
    assert_equal expected.path, e.path
  end

41 42 43 44 45 46 47 48 49 50 51
  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

52
  def test_tracking_loaded_files
53 54 55 56 57
    with_loading do
      require_dependency 'dependencies/service_one'
      require_dependency 'dependencies/service_two'
      assert_equal 2, ActiveSupport::Dependencies.loaded.size
    end
58
  ensure
59
    remove_constants(:ServiceOne, :ServiceTwo)
60
  end
61 62

  def test_tracking_identical_loaded_files
63 64 65 66 67
    with_loading do
      require_dependency 'dependencies/service_one'
      require_dependency 'dependencies/service_one'
      assert_equal 1, ActiveSupport::Dependencies.loaded.size
    end
68
  ensure
69
    remove_constants(:ServiceOne)
70 71
  end

72
  def test_missing_dependency_raises_missing_source_file
73
    assert_raise(LoadError) { require_dependency("missing_service") }
74
  end
75 76

  def test_dependency_which_raises_exception_isnt_added_to_loaded_set
77
    with_loading do
78
      filename = 'dependencies/raises_exception'
79
      $raises_exception_load_count = 0
80

81
      5.times do |count|
82
        e = assert_raise Exception, 'should have loaded dependencies/raises_exception which raises an exception' do
83 84
          require_dependency filename
        end
85 86

        assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
87
        assert_equal count + 1, $raises_exception_load_count
88

89 90
        assert_not ActiveSupport::Dependencies.loaded.include?(filename)
        assert_not ActiveSupport::Dependencies.history.include?(filename)
91
      end
92 93 94
    end
  end

95 96 97 98 99 100 101
  def test_dependency_which_raises_doesnt_blindly_call_blame_file!
    with_loading do
      filename = 'dependencies/raises_exception_without_blame_file'
      assert_raises(Exception) { require_dependency filename }
    end
  end

102
  def test_warnings_should_be_enabled_on_first_load
103
    with_loading 'dependencies' do
104
      old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true
105
      filename = "check_warnings"
106
      expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}")
107
      $check_warnings_load_count = 0
108

109 110
      assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
      assert_not ActiveSupport::Dependencies.history.include?(expanded)
111

112 113 114
      silence_warnings { require_dependency filename }
      assert_equal 1, $check_warnings_load_count
      assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
115

116 117
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
      ActiveSupport::Dependencies.clear
118
      assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
119
      assert ActiveSupport::Dependencies.history.include?(expanded)
120

121 122 123
      silence_warnings { require_dependency filename }
      assert_equal 2, $check_warnings_load_count
      assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.'
124

125 126
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
      ActiveSupport::Dependencies.clear
127
      assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
128
      assert ActiveSupport::Dependencies.history.include?(expanded)
129

130 131 132
      enable_warnings { require_dependency filename }
      assert_equal 3, $check_warnings_load_count
      assert_equal true, $checked_verbose, 'After first load warnings should be left alone.'
133

134
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
135
      ActiveSupport::Dependencies.warnings_on_first_load = old_warnings
136
    end
137
  end
138 139

  def test_mutual_dependencies_dont_infinite_loop
140 141 142 143
    with_loading 'dependencies' do
      $mutual_dependencies_count = 0
      assert_nothing_raised { require_dependency 'mutual_one' }
      assert_equal 2, $mutual_dependencies_count
144

145
      ActiveSupport::Dependencies.clear
146

147 148 149 150
      $mutual_dependencies_count = 0
      assert_nothing_raised { require_dependency 'mutual_two' }
      assert_equal 2, $mutual_dependencies_count
    end
151
  end
152

153 154
  def test_circular_autoloading_detection
    with_autoloading_fixtures do
155 156
      e = assert_raise(RuntimeError) { Circular1 }
      assert_equal "Circular dependency detected while autoloading constant Circular1", e.message
157 158 159
    end
  end

160 161 162
  def test_ensures_the_expected_constant_is_defined
    with_autoloading_fixtures do
      e = assert_raise(LoadError) { Typo }
163
      assert_match %r{Unable to autoload constant Typo, expected .*/test/autoloading_fixtures/typo.rb to define it}, e.message
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    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 }
181
      assert_match %r{Unable to autoload constant Typo, expected .*/test/autoloading_fixtures/typo.rb to define it}, e.message
182 183 184
    end
  end

185
  def test_module_loading
J
Jeremy Kemper 已提交
186
    with_autoloading_fixtures do
187 188 189
      assert_kind_of Module, A
      assert_kind_of Class, A::B
      assert_kind_of Class, A::C::D
190
      assert_kind_of Class, A::C::EM::F
191 192
    end
  end
193

194
  def test_non_existing_const_raises_name_error
J
Jeremy Kemper 已提交
195
    with_autoloading_fixtures do
196 197 198 199
      assert_raise(NameError) { DoesNotExist }
      assert_raise(NameError) { NoModule::DoesNotExist }
      assert_raise(NameError) { A::DoesNotExist }
      assert_raise(NameError) { A::B::DoesNotExist }
200
    end
201
  end
202

203
  def test_directories_manifest_as_modules_unless_const_defined
J
Jeremy Kemper 已提交
204
    with_autoloading_fixtures do
205 206
      assert_kind_of Module, ModuleFolder
    end
207 208
  ensure
    remove_constants(:ModuleFolder)
209
  end
210

211
  def test_module_with_nested_class
J
Jeremy Kemper 已提交
212
    with_autoloading_fixtures do
213 214
      assert_kind_of Class, ModuleFolder::NestedClass
    end
215 216
  ensure
    remove_constants(:ModuleFolder)
217
  end
218

219
  def test_module_with_nested_inline_class
J
Jeremy Kemper 已提交
220
    with_autoloading_fixtures do
221 222
      assert_kind_of Class, ModuleFolder::InlineClass
    end
223 224
  ensure
    remove_constants(:ModuleFolder)
225 226 227
  end

  def test_directories_may_manifest_as_nested_classes
J
Jeremy Kemper 已提交
228
    with_autoloading_fixtures do
229 230
      assert_kind_of Class, ClassFolder
    end
231 232
  ensure
    remove_constants(:ClassFolder)
233 234 235
  end

  def test_class_with_nested_class
J
Jeremy Kemper 已提交
236
    with_autoloading_fixtures do
237 238
      assert_kind_of Class, ClassFolder::NestedClass
    end
239 240
  ensure
    remove_constants(:ClassFolder)
241 242 243
  end

  def test_class_with_nested_inline_class
J
Jeremy Kemper 已提交
244
    with_autoloading_fixtures do
245 246
      assert_kind_of Class, ClassFolder::InlineClass
    end
247 248
  ensure
    remove_constants(:ClassFolder)
249 250
  end

251
  def test_class_with_nested_inline_subclass_of_parent
J
Jeremy Kemper 已提交
252
    with_autoloading_fixtures do
253 254 255 256
      assert_kind_of Class, ClassFolder::ClassFolderSubclass
      assert_kind_of Class, ClassFolder
      assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
    end
257 258
  ensure
    remove_constants(:ClassFolder)
259 260
  end

261
  def test_nested_class_can_access_sibling
J
Jeremy Kemper 已提交
262
    with_autoloading_fixtures do
263 264 265 266
      sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
      assert defined?(ModuleFolder::NestedSibling)
      assert_equal ModuleFolder::NestedSibling, sibling
    end
267 268
  ensure
    remove_constants(:ModuleFolder)
269
  end
270

271 272 273 274 275
  def test_doesnt_break_normal_require
    path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
    original_path = $:.dup
    $:.push(path)
    with_autoloading_fixtures do
276 277
      # The _ = assignments are to prevent warnings
      _ = RequiresConstant
278 279 280
      assert defined?(RequiresConstant)
      assert defined?(LoadedConstant)
      ActiveSupport::Dependencies.clear
281
      _ = RequiresConstant
282 283 284 285
      assert defined?(RequiresConstant)
      assert defined?(LoadedConstant)
    end
  ensure
286
    remove_constants(:RequiresConstant, :LoadedConstant)
287 288 289 290 291 292 293 294 295
    $:.replace(original_path)
  end

  def test_doesnt_break_normal_require_nested
    path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
    original_path = $:.dup
    $:.push(path)

    with_autoloading_fixtures do
296 297
      # The _ = assignments are to prevent warnings
      _ = LoadsConstant
298 299 300
      assert defined?(LoadsConstant)
      assert defined?(LoadedConstant)
      ActiveSupport::Dependencies.clear
301
      _ = LoadsConstant
302 303 304 305 306 307 308 309
      assert defined?(LoadsConstant)
      assert defined?(LoadedConstant)
    end
  ensure
    remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
    $:.replace(original_path)
  end

310 311 312 313 314
  def test_require_returns_true_when_file_not_yet_required
    path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
    original_path = $:.dup
    $:.push(path)

S
Sam Umbach 已提交
315
    with_loading do
316 317 318 319 320 321 322 323 324 325 326 327
      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", __FILE__)
    original_path = $:.dup
    $:.push(path)

S
Sam Umbach 已提交
328
    with_loading do
329 330 331 332 333 334 335 336 337 338 339 340 341
      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", __FILE__)
    original_path = $:.dup
    $:.push(path)

S
Sam Umbach 已提交
342
    with_loading do
343 344 345 346 347 348 349 350
      require 'loaded_constant'
      assert_equal false, require('loaded_constant')
    end
  ensure
    remove_constants(:LoadedConstant)
    $:.replace(original_path)
  end

351 352 353 354 355 356
  def test_require_raises_load_error_when_file_not_found
    with_loading do
      assert_raise(LoadError) { require 'this_file_dont_exist_dude' }
    end
  end

357 358 359 360 361
  def test_load_returns_true_when_file_found
    path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
    original_path = $:.dup
    $:.push(path)

S
Sam Umbach 已提交
362
    with_loading do
363 364 365 366 367 368 369 370
      assert_equal true, load('loaded_constant.rb')
      assert_equal true, load('loaded_constant.rb')
    end
  ensure
    remove_constants(:LoadedConstant)
    $:.replace(original_path)
  end

371 372 373 374 375 376
  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

377
  def failing_test_access_thru_and_upwards_fails
J
Jeremy Kemper 已提交
378
    with_autoloading_fixtures do
379
      assert_not defined?(ModuleFolder)
380 381
      assert_raise(NameError) { ModuleFolder::Object }
      assert_raise(NameError) { ModuleFolder::NestedClass::Object }
382
    end
383 384
  ensure
    remove_constants(:ModuleFolder)
385
  end
386

387
  def test_non_existing_const_raises_name_error_with_fully_qualified_name
J
Jeremy Kemper 已提交
388
    with_autoloading_fixtures do
389 390
      e = assert_raise(NameError) { A::DoesNotExist.nil? }
      assert_equal "uninitialized constant A::DoesNotExist", e.message
391
      assert_equal :DoesNotExist, e.name
392 393 394

      e = assert_raise(NameError) { A::B::DoesNotExist.nil? }
      assert_equal "uninitialized constant A::B::DoesNotExist", e.message
395
      assert_equal :DoesNotExist, e.name
396
    end
397 398
  ensure
    remove_constants(:A)
399
  end
400

401
  def test_smart_name_error_strings
402 403 404 405
    e = assert_raise NameError do
      Object.module_eval "ImaginaryObject"
    end
    assert_includes "uninitialized constant ImaginaryObject", e.message
406
  end
407

408
  def test_loadable_constants_for_path_should_handle_empty_autoloads
409
    assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello')
410
  end
411

412
  def test_loadable_constants_for_path_should_handle_relative_paths
413 414 415 416
    fake_root = 'dependencies'
    relative_root = File.dirname(__FILE__) + '/dependencies'
    ['', '/'].each do |suffix|
      with_loading fake_root + suffix do
417
        assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b')
418 419 420
      end
    end
  end
421

422
  def test_loadable_constants_for_path_should_provide_all_results
423 424
    fake_root = '/usr/apps/backpack'
    with_loading fake_root, fake_root + '/lib' do
425
      root = ActiveSupport::Dependencies.autoload_paths.first
426
      assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b')
427 428
    end
  end
429

430
  def test_loadable_constants_for_path_should_uniq_results
431 432
    fake_root = '/usr/apps/backpack/lib'
    with_loading fake_root, fake_root + '/' do
433
      root = ActiveSupport::Dependencies.autoload_paths.first
434
      assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b')
435 436
    end
  end
437

438 439 440
  def test_loadable_constants_with_load_path_without_trailing_slash
    path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb'
    with_loading 'autoloading_fixtures/class/' do
441
      assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path)
442 443
    end
  end
444

445
  def test_qualified_const_defined
446 447 448
    assert ActiveSupport::Dependencies.qualified_const_defined?("Object")
    assert ActiveSupport::Dependencies.qualified_const_defined?("::Object")
    assert ActiveSupport::Dependencies.qualified_const_defined?("::Object::Kernel")
449
    assert ActiveSupport::Dependencies.qualified_const_defined?("::ActiveSupport::TestCase")
450
  end
451

452
  def test_qualified_const_defined_should_not_call_const_missing
453
    ModuleWithMissing.missing_count = 0
454
    assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A")
455
    assert_equal 0, ModuleWithMissing.missing_count
456
    assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
457 458
    assert_equal 0, ModuleWithMissing.missing_count
  end
459

460 461 462 463
  def test_qualified_const_defined_explodes_with_invalid_const_name
    assert_raises(NameError) { ActiveSupport::Dependencies.qualified_const_defined?("invalid") }
  end

464
  def test_autoloaded?
J
Jeremy Kemper 已提交
465
    with_autoloading_fixtures do
466 467
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
468

469
      assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
470

471 472
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
473

474
      assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
475

476 477
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
478

479 480
      assert ActiveSupport::Dependencies.autoloaded?("::ModuleFolder")
      assert ActiveSupport::Dependencies.autoloaded?(:ModuleFolder)
481

482
      # Anonymous modules aren't autoloaded.
483
      assert !ActiveSupport::Dependencies.autoloaded?(Module.new)
484 485 486

      nil_name = Module.new
      def nil_name.name() nil end
487
      assert !ActiveSupport::Dependencies.autoloaded?(nil_name)
488
    end
489 490
  ensure
    remove_constants(:ModuleFolder)
491
  end
492

493
  def test_qualified_name_for
494 495 496 497
    assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(Object, :A)
    assert_equal "A", ActiveSupport::Dependencies.qualified_name_for(:Object, :A)
    assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("Object", :A)
    assert_equal "A", ActiveSupport::Dependencies.qualified_name_for("::Object", :A)
498

499 500
    assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(:'ActiveSupport::Dependencies', :A)
    assert_equal "ActiveSupport::Dependencies::A", ActiveSupport::Dependencies.qualified_name_for(ActiveSupport::Dependencies, :A)
501
  end
502

503 504
  def test_file_search
    with_loading 'dependencies' do
505
      root = ActiveSupport::Dependencies.autoload_paths.first
506 507 508 509
      assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three')
      assert_equal 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')
510 511
    end
  end
512

513
  def test_file_search_uses_first_in_load_path
514
    with_loading 'dependencies', 'autoloading_fixtures' do
515
      deps, autoload = ActiveSupport::Dependencies.autoload_paths
516 517
      assert_match %r/dependencies/, deps
      assert_match %r/autoloading_fixtures/, autoload
518

519
      assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
520 521
    end
    with_loading 'autoloading_fixtures', 'dependencies' do
522
      autoload, deps = ActiveSupport::Dependencies.autoload_paths
523 524
      assert_match %r/dependencies/, deps
      assert_match %r/autoloading_fixtures/, autoload
525

526
      assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
527
    end
528

529
  end
530

531
  def test_custom_const_missing_should_work
532
    Object.module_eval <<-end_eval, __FILE__, __LINE__ + 1
533 534 535 536 537 538 539 540 541
      module ModuleWithCustomConstMissing
        def self.const_missing(name)
          const_set name, name.to_s.hash
        end

        module A
        end
      end
    end_eval
542

J
Jeremy Kemper 已提交
543
    with_autoloading_fixtures do
544 545 546 547
      assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
      assert_kind_of Module, ::ModuleWithCustomConstMissing::A
      assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
    end
548 549
  ensure
    remove_constants(:ModuleWithCustomConstMissing)
550
  end
551

552
  def test_const_missing_in_anonymous_modules_loads_top_level_constants
J
Jeremy Kemper 已提交
553
    with_autoloading_fixtures do
554
      # class_eval STRING pushes the class to the nesting of the eval'ed code.
555 556
      klass = Class.new.class_eval "EM"
      assert_equal EM, klass
557
    end
558
  ensure
559
    remove_constants(:EM)
560
  end
561

562
  def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object
J
Jeremy Kemper 已提交
563
    with_autoloading_fixtures do
564
      require_dependency 'em'
565

566
      mod = Module.new
567 568 569
      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
570
    end
571
  ensure
572
    remove_constants(:EM)
573
  end
574

575 576 577
  def test_removal_from_tree_should_be_detected
    with_loading 'dependencies' do
      c = ServiceOne
578
      ActiveSupport::Dependencies.clear
579
      assert_not defined?(ServiceOne)
580
      e = assert_raise ArgumentError do
581
        ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing)
582
      end
583
      assert_match %r{ServiceOne has been removed from the module tree}i, e.message
584
    end
585 586
  ensure
    remove_constants(:ServiceOne)
587
  end
588

W
wycats 已提交
589 590
  def test_references_should_work
    with_loading 'dependencies' do
591
      c = ActiveSupport::Dependencies.reference("ServiceOne")
W
wycats 已提交
592
      service_one_first = ServiceOne
593
      assert_equal service_one_first, c.get("ServiceOne")
W
wycats 已提交
594
      ActiveSupport::Dependencies.clear
595
      assert_not defined?(ServiceOne)
W
wycats 已提交
596
      service_one_second = ServiceOne
597 598
      assert_not_equal service_one_first, c.get("ServiceOne")
      assert_equal service_one_second, c.get("ServiceOne")
W
wycats 已提交
599
    end
600 601
  ensure
    remove_constants(:ServiceOne)
W
wycats 已提交
602 603
  end

604 605 606 607
  def test_constantize_shortcut_for_cached_constant_lookups
    with_loading 'dependencies' do
      assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne")
    end
608 609
  ensure
    remove_constants(:ServiceOne)
610 611
  end

N
Nicholas Seckar 已提交
612 613
  def test_nested_load_error_isnt_rescued
    with_loading 'dependencies' do
614
      assert_raise(LoadError) do
N
Nicholas Seckar 已提交
615 616 617 618
        RequiresNonexistent1
      end
    end
  end
619

620
  def test_autoload_once_paths_do_not_add_to_autoloaded_constants
621
    old_path = ActiveSupport::Dependencies.autoload_once_paths
J
Jeremy Kemper 已提交
622
    with_autoloading_fixtures do
623
      ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths.dup
624

625 626 627
      assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
      assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
628

629
      1 if ModuleFolder::NestedClass # 1 if to avoid warning
630
      assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
631 632
    end
  ensure
633 634
    remove_constants(:ModuleFolder)
    ActiveSupport::Dependencies.autoload_once_paths = old_path
635
  end
636

637 638 639 640 641 642
  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

643 644 645
      assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
      assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
646 647

      1 if ModuleFolder::NestedClass # 1 if to avoid warning
648
      assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
649 650
    end
  ensure
651
    remove_constants(:ModuleFolder)
652 653 654
    ActiveSupport::Dependencies.autoload_once_paths = []
  end

655
  def test_application_should_special_case_application_controller
J
Jeremy Kemper 已提交
656
    with_autoloading_fixtures do
657 658
      require_dependency 'application'
      assert_equal 10, ApplicationController
659
      assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController)
660
    end
661 662
  ensure
    remove_constants(:ApplicationController)
663
  end
664

665
  def test_preexisting_constants_are_not_marked_as_autoloaded
J
Jeremy Kemper 已提交
666
    with_autoloading_fixtures do
667 668
      require_dependency 'em'
      assert ActiveSupport::Dependencies.autoloaded?(:EM)
669
      ActiveSupport::Dependencies.clear
670
    end
671

672
    Object.const_set :EM, Class.new
J
Jeremy Kemper 已提交
673
    with_autoloading_fixtures do
674 675
      require_dependency 'em'
      assert ! ActiveSupport::Dependencies.autoloaded?(:EM), "EM shouldn't be marked autoloaded!"
676
      ActiveSupport::Dependencies.clear
677 678
    end
  ensure
679
    remove_constants(:EM)
680
  end
681

682 683 684 685 686 687
  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
688 689
  ensure
    remove_constants(:HTML)
690 691
  end

692
  def test_unloadable
J
Jeremy Kemper 已提交
693
    with_autoloading_fixtures do
694 695
      Object.const_set :M, Module.new
      M.unloadable
696

697
      ActiveSupport::Dependencies.clear
698
      assert ! defined?(M)
699

700
      Object.const_set :M, Module.new
701
      ActiveSupport::Dependencies.clear
702 703 704
      assert ! defined?(M), "Dependencies should unload unloadable constants each time"
    end
  end
705

706
  def test_unloadable_should_fail_with_anonymous_modules
J
Jeremy Kemper 已提交
707
    with_autoloading_fixtures do
708
      m = Module.new
709
      assert_raise(ArgumentError) { m.unloadable }
710 711
    end
  end
712

713
  def test_unloadable_should_return_change_flag
J
Jeremy Kemper 已提交
714
    with_autoloading_fixtures do
715 716 717 718
      Object.const_set :M, Module.new
      assert_equal true, M.unloadable
      assert_equal false, M.unloadable
    end
719
  ensure
720
    remove_constants(:M)
721
  end
722

723 724 725 726 727 728 729 730
  def test_unloadable_constants_should_receive_callback
    Object.const_set :C, Class.new
    C.unloadable
    C.expects(:before_remove_const).once
    assert C.respond_to?(:before_remove_const)
    ActiveSupport::Dependencies.clear
    assert !defined?(C)
  ensure
731
    remove_constants(:C)
732 733
  end

734
  def test_new_contants_in_without_constants
735
    assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
W
wycats 已提交
736
    assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
737
  end
738

739
  def test_new_constants_in_with_a_single_constant
740
    assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) {
J
Jeremy Kemper 已提交
741 742
                              Object.const_set :Hello, 10
                            }.map(&:to_s)
W
wycats 已提交
743
    assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
744
  ensure
745
    remove_constants(:Hello)
746
  end
747

748
  def test_new_constants_in_with_nesting
749
    outer = ActiveSupport::Dependencies.new_constants_in(Object) do
750
      Object.const_set :OuterBefore, 10
751

752
      assert_equal ["Inner"], ActiveSupport::Dependencies.new_constants_in(Object) {
J
Jeremy Kemper 已提交
753 754
                                Object.const_set :Inner, 20
                              }.map(&:to_s)
755

756 757
      Object.const_set :OuterAfter, 30
    end
758

J
Jeremy Kemper 已提交
759
    assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
W
wycats 已提交
760
    assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
761
  ensure
762
    remove_constants(:OuterBefore, :Inner, :OuterAfter)
763
  end
764

765 766
  def test_new_constants_in_module
    Object.const_set :M, Module.new
767

768
    outer = ActiveSupport::Dependencies.new_constants_in(M) do
769
      M.const_set :OuterBefore, 10
770

771
      inner = ActiveSupport::Dependencies.new_constants_in(M) do
772 773 774
        M.const_set :Inner, 20
      end
      assert_equal ["M::Inner"], inner
775

776 777 778
      M.const_set :OuterAfter, 30
    end
    assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
W
wycats 已提交
779
    assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
780
  ensure
781
    remove_constants(:M)
782
  end
783

784
  def test_new_constants_in_module_using_name
785
    outer = ActiveSupport::Dependencies.new_constants_in(:M) do
786 787
      Object.const_set :M, Module.new
      M.const_set :OuterBefore, 10
788

789
      inner = ActiveSupport::Dependencies.new_constants_in(:M) do
790 791 792
        M.const_set :Inner, 20
      end
      assert_equal ["M::Inner"], inner
793

794 795 796
      M.const_set :OuterAfter, 30
    end
    assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
W
wycats 已提交
797
    assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
798
  ensure
799
    remove_constants(:M)
800
  end
801

802
  def test_new_constants_in_with_inherited_constants
803
    m = ActiveSupport::Dependencies.new_constants_in(:Object) do
J
Jeremy Kemper 已提交
804
      Object.class_eval { include ModuleWithConstant }
805 806 807 808
    end
    assert_equal [], m
  end

809
  def test_new_constants_in_with_illegal_module_name_raises_correct_error
810
    assert_raise(NameError) do
811
      ActiveSupport::Dependencies.new_constants_in("Illegal-Name") {}
812 813 814
    end
  end

815
  def test_file_with_multiple_constants_and_require_dependency
J
Jeremy Kemper 已提交
816
    with_autoloading_fixtures do
817 818
      assert_not defined?(MultipleConstantFile)
      assert_not defined?(SiblingConstant)
819

820 821 822
      require_dependency 'multiple_constant_file'
      assert defined?(MultipleConstantFile)
      assert defined?(SiblingConstant)
823 824 825
      assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
      assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
      ActiveSupport::Dependencies.clear
826

827 828
      assert_not defined?(MultipleConstantFile)
      assert_not defined?(SiblingConstant)
829
    end
830 831
  ensure
    remove_constants(:MultipleConstantFile, :SiblingConstant)
832
  end
833

834
  def test_file_with_multiple_constants_and_auto_loading
J
Jeremy Kemper 已提交
835
    with_autoloading_fixtures do
836 837
      assert_not defined?(MultipleConstantFile)
      assert_not defined?(SiblingConstant)
838

839
      assert_equal 10, MultipleConstantFile
840

841 842
      assert defined?(MultipleConstantFile)
      assert defined?(SiblingConstant)
843 844
      assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
      assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
845

846
      ActiveSupport::Dependencies.clear
847

848 849
      assert_not defined?(MultipleConstantFile)
      assert_not defined?(SiblingConstant)
850
    end
851 852
  ensure
    remove_constants(:MultipleConstantFile, :SiblingConstant)
853
  end
854

855
  def test_nested_file_with_multiple_constants_and_require_dependency
J
Jeremy Kemper 已提交
856
    with_autoloading_fixtures do
857 858
      assert_not defined?(ClassFolder::NestedClass)
      assert_not defined?(ClassFolder::SiblingClass)
859

860
      require_dependency 'class_folder/nested_class'
861

862 863
      assert defined?(ClassFolder::NestedClass)
      assert defined?(ClassFolder::SiblingClass)
864 865
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
866

867
      ActiveSupport::Dependencies.clear
868

869 870
      assert_not defined?(ClassFolder::NestedClass)
      assert_not defined?(ClassFolder::SiblingClass)
871
    end
872 873
  ensure
    remove_constants(:ClassFolder)
874
  end
875

876
  def test_nested_file_with_multiple_constants_and_auto_loading
J
Jeremy Kemper 已提交
877
    with_autoloading_fixtures do
878 879
      assert_not defined?(ClassFolder::NestedClass)
      assert_not defined?(ClassFolder::SiblingClass)
880

881
      assert_kind_of Class, ClassFolder::NestedClass
882

883 884
      assert defined?(ClassFolder::NestedClass)
      assert defined?(ClassFolder::SiblingClass)
885 886
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
887

888
      ActiveSupport::Dependencies.clear
889

890 891
      assert_not defined?(ClassFolder::NestedClass)
      assert_not defined?(ClassFolder::SiblingClass)
892
    end
893 894
  ensure
    remove_constants(:ClassFolder)
895 896
  end

J
Jeremy Kemper 已提交
897
  def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
J
Jeremy Kemper 已提交
898
    with_autoloading_fixtures do
J
Jeremy Kemper 已提交
899
      assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
900 901
      2.times do
        assert_raise(NoMethodError) { RaisesNoMethodError }
J
Jeremy Kemper 已提交
902
        assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
903
      end
J
Jeremy Kemper 已提交
904
    end
905
  ensure
906
    remove_constants(:RaisesNoMethodError)
J
Jeremy Kemper 已提交
907
  end
908

J
Jeremy Kemper 已提交
909
  def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
J
Jeremy Kemper 已提交
910
    with_autoloading_fixtures do
J
Jeremy Kemper 已提交
911
      assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
912 913
      2.times do
        assert_raise(NoMethodError) { ::RaisesNoMethodError }
J
Jeremy Kemper 已提交
914
        assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
915 916
      end
    end
917
  ensure
918
    remove_constants(:RaisesNoMethodError)
919 920
  end

921
  def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load
J
Jeremy Kemper 已提交
922
    with_autoloading_fixtures do
923
      ActiveSupport::Dependencies.mechanism = :require
924
      2.times do
925
        assert_raise(NameError) { assert_equal 123, ::RaisesNameError::FooBarBaz }
926 927
      end
    end
G
Guo Xiang Tan 已提交
928 929
  ensure
    remove_constants(:RaisesNameError)
930 931
  end

932
  def test_autoload_doesnt_shadow_name_error
J
Jeremy Kemper 已提交
933
    with_autoloading_fixtures do
V
Vipul A M 已提交
934
      2.times do
935
        e = assert_raise NameError do
936
          ::RaisesNameError::FooBarBaz.object_id
937
        end
938
        assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
J
Jeremy Kemper 已提交
939
        assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
940 941
      end

942
      assert !defined?(::RaisesNameError)
943
      2.times do
944
        assert_raise(NameError) { ::RaisesNameError }
J
Jeremy Kemper 已提交
945
        assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
946 947
      end
    end
948
  ensure
949
    remove_constants(:RaisesNameError)
950
  end
951

952 953 954
  def test_remove_constant_handles_double_colon_at_start
    Object.const_set 'DeleteMe', Module.new
    DeleteMe.const_set 'OrMe', Module.new
955
    ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe"
956
    assert_not defined?(DeleteMe::OrMe)
957
    assert defined?(DeleteMe)
958
    ActiveSupport::Dependencies.remove_constant "::DeleteMe"
959 960 961
    assert_not defined?(DeleteMe)
  ensure
    remove_constants(:DeleteMe)
962
  end
963

964 965 966 967 968 969
  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', __FILE__)
    end

970
    assert_nil ActiveSupport::Dependencies.remove_constant(constant), "Kernel#autoload has been triggered by remove_constant"
971 972 973
    assert_not defined?(ShouldNotBeAutoloaded)
  ensure
    remove_constants(constant)
974 975
  end

976 977
  def test_remove_constant_does_not_autoload_already_removed_parents_as_a_side_effect
    with_autoloading_fixtures do
978 979
      _ = ::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"
980 981
      ActiveSupport::Dependencies.remove_constant('A')
      ActiveSupport::Dependencies.remove_constant('A::B')
982
      assert_not defined?(A)
983
    end
984 985
  ensure
    remove_constants(:A)
986 987
  end

988
  def test_load_once_constants_should_not_be_unloaded
989
    old_path = ActiveSupport::Dependencies.autoload_once_paths
J
Jeremy Kemper 已提交
990
    with_autoloading_fixtures do
991
      ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths
992
      _ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context"
993
      assert defined?(A)
994
      ActiveSupport::Dependencies.clear
995 996 997
      assert defined?(A)
    end
  ensure
998 999
    ActiveSupport::Dependencies.autoload_once_paths = old_path
    remove_constants(:A)
1000
  end
1001

1002 1003 1004 1005 1006 1007
  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!
1008

1009 1010
      A::B # Make sure no circular dependency error
    end
1011 1012
  ensure
    remove_constants(:A)
1013 1014 1015
  end


1016
  def test_autoload_once_paths_should_behave_when_recursively_loading
1017
    old_path = ActiveSupport::Dependencies.autoload_once_paths
1018
    with_loading 'dependencies', 'autoloading_fixtures' do
1019
      ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last]
1020
      assert_not defined?(CrossSiteDependency)
1021
      assert_nothing_raised { CrossSiteDepender.nil? }
1022
      assert defined?(CrossSiteDependency)
1023
      assert_not ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
1024
        "CrossSiteDependency shouldn't be marked as autoloaded!"
1025
      ActiveSupport::Dependencies.clear
1026 1027 1028 1029
      assert defined?(CrossSiteDependency),
        "CrossSiteDependency shouldn't have been unloaded!"
    end
  ensure
1030 1031
    ActiveSupport::Dependencies.autoload_once_paths = old_path
    remove_constants(:CrossSiteDependency)
1032
  end
1033 1034 1035 1036 1037

  def test_hook_called_multiple_times
    assert_nothing_raised { ActiveSupport::Dependencies.hook! }
  end

1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
  def test_load_and_require_stay_private
    assert Object.private_methods.include?(:load)
    assert Object.private_methods.include?(:require)

    ActiveSupport::Dependencies.unhook!

    assert Object.private_methods.include?(:load)
    assert Object.private_methods.include?(:require)
  ensure
    ActiveSupport::Dependencies.hook!
  end

1050 1051 1052 1053 1054 1055 1056
  def test_unhook
    ActiveSupport::Dependencies.unhook!
    assert !Module.new.respond_to?(:const_missing_without_dependencies)
    assert !Module.new.respond_to?(:load_without_new_constant_marking)
  ensure
    ActiveSupport::Dependencies.hook!
  end
1057
end