dependencies_test.rb 28.9 KB
Newer Older
1
require 'abstract_unit'
2
require 'pp'
J
Jeremy Kemper 已提交
3
require 'active_support/dependencies'
4
require 'active_support/core_ext/kernel/reporting'
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 19
class DependenciesTest < Test::Unit::TestCase
  def teardown
20
    ActiveSupport::Dependencies.clear
21
  end
22

23
  def with_loading(*from)
24
    old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load
25 26 27
    this_dir = File.dirname(__FILE__)
    parent_dir = File.dirname(this_dir)
    $LOAD_PATH.unshift(parent_dir) unless $LOAD_PATH.include?(parent_dir)
28 29
    prior_autoload_paths = ActiveSupport::Dependencies.autoload_paths
    ActiveSupport::Dependencies.autoload_paths = from.collect { |f| "#{this_dir}/#{f}" }
30 31
    yield
  ensure
32
    ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths
33 34
    ActiveSupport::Dependencies.mechanism = old_mechanism
    ActiveSupport::Dependencies.explicitly_unloadable_constants = []
35
  end
36

J
Jeremy Kemper 已提交
37 38 39 40
  def with_autoloading_fixtures(&block)
    with_loading 'autoloading_fixtures', &block
  end

41
  def test_tracking_loaded_files
42 43
    require_dependency 'dependencies/service_one'
    require_dependency 'dependencies/service_two'
44
    assert_equal 2, ActiveSupport::Dependencies.loaded.size
45 46 47
  ensure
    Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
    Object.send(:remove_const, :ServiceTwo) if Object.const_defined?(:ServiceTwo)
48
  end
49 50

  def test_tracking_identical_loaded_files
51 52
    require_dependency 'dependencies/service_one'
    require_dependency 'dependencies/service_one'
53
    assert_equal 1, ActiveSupport::Dependencies.loaded.size
54 55
  ensure
    Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
56 57
  end

58
  def test_missing_dependency_raises_missing_source_file
59
    assert_raise(MissingSourceFile) { require_dependency("missing_service") }
60
  end
61 62

  def test_missing_association_raises_nothing
63 64
    assert_nothing_raised { require_association("missing_model") }
  end
65 66

  def test_dependency_which_raises_exception_isnt_added_to_loaded_set
67
    with_loading do
68
      filename = 'dependencies/raises_exception'
69
      $raises_exception_load_count = 0
70

71
      5.times do |count|
72 73 74 75 76 77
        begin
          require_dependency filename
          flunk 'should have loaded dependencies/raises_exception which raises an exception'
        rescue Exception => e
          assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
        end
78
        assert_equal count + 1, $raises_exception_load_count
79

80 81
        assert !ActiveSupport::Dependencies.loaded.include?(filename)
        assert !ActiveSupport::Dependencies.history.include?(filename)
82
      end
83 84 85 86
    end
  end

  def test_warnings_should_be_enabled_on_first_load
87
    with_loading 'dependencies' do
88
      old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true
89

90
      filename = "check_warnings"
91
      expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}")
92
      $check_warnings_load_count = 0
93

94 95
      assert !ActiveSupport::Dependencies.loaded.include?(expanded)
      assert !ActiveSupport::Dependencies.history.include?(expanded)
96

97 98 99
      silence_warnings { require_dependency filename }
      assert_equal 1, $check_warnings_load_count
      assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
100

101 102 103 104
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
      ActiveSupport::Dependencies.clear
      assert !ActiveSupport::Dependencies.loaded.include?(expanded)
      assert ActiveSupport::Dependencies.history.include?(expanded)
105

106 107 108
      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.'
109

110 111 112 113
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
      ActiveSupport::Dependencies.clear
      assert !ActiveSupport::Dependencies.loaded.include?(expanded)
      assert ActiveSupport::Dependencies.history.include?(expanded)
114

115 116 117
      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.'
118

119
      assert ActiveSupport::Dependencies.loaded.include?(expanded)
120
      ActiveSupport::Dependencies.warnings_on_first_load = old_warnings
121
    end
122
  end
123 124

  def test_mutual_dependencies_dont_infinite_loop
125 126 127 128
    with_loading 'dependencies' do
      $mutual_dependencies_count = 0
      assert_nothing_raised { require_dependency 'mutual_one' }
      assert_equal 2, $mutual_dependencies_count
129

130
      ActiveSupport::Dependencies.clear
131

132 133 134 135
      $mutual_dependencies_count = 0
      assert_nothing_raised { require_dependency 'mutual_two' }
      assert_equal 2, $mutual_dependencies_count
    end
136
  end
137

138
  def test_module_loading
J
Jeremy Kemper 已提交
139
    with_autoloading_fixtures do
140 141 142 143 144 145
      assert_kind_of Module, A
      assert_kind_of Class, A::B
      assert_kind_of Class, A::C::D
      assert_kind_of Class, A::C::E::F
    end
  end
146

147
  def test_non_existing_const_raises_name_error
J
Jeremy Kemper 已提交
148
    with_autoloading_fixtures do
149 150 151 152
      assert_raise(NameError) { DoesNotExist }
      assert_raise(NameError) { NoModule::DoesNotExist }
      assert_raise(NameError) { A::DoesNotExist }
      assert_raise(NameError) { A::B::DoesNotExist }
153
    end
154
  end
155

156
  def test_directories_manifest_as_modules_unless_const_defined
J
Jeremy Kemper 已提交
157
    with_autoloading_fixtures do
158
      assert_kind_of Module, ModuleFolder
159
      Object.__send__ :remove_const, :ModuleFolder
160 161
    end
  end
162

163
  def test_module_with_nested_class
J
Jeremy Kemper 已提交
164
    with_autoloading_fixtures do
165
      assert_kind_of Class, ModuleFolder::NestedClass
166
      Object.__send__ :remove_const, :ModuleFolder
167 168
    end
  end
169

170
  def test_module_with_nested_inline_class
J
Jeremy Kemper 已提交
171
    with_autoloading_fixtures do
172
      assert_kind_of Class, ModuleFolder::InlineClass
173
      Object.__send__ :remove_const, :ModuleFolder
174 175 176 177
    end
  end

  def test_directories_may_manifest_as_nested_classes
J
Jeremy Kemper 已提交
178
    with_autoloading_fixtures do
179
      assert_kind_of Class, ClassFolder
180
      Object.__send__ :remove_const, :ClassFolder
181 182 183 184
    end
  end

  def test_class_with_nested_class
J
Jeremy Kemper 已提交
185
    with_autoloading_fixtures do
186
      assert_kind_of Class, ClassFolder::NestedClass
187
      Object.__send__ :remove_const, :ClassFolder
188 189 190 191
    end
  end

  def test_class_with_nested_inline_class
J
Jeremy Kemper 已提交
192
    with_autoloading_fixtures do
193
      assert_kind_of Class, ClassFolder::InlineClass
194
      Object.__send__ :remove_const, :ClassFolder
195 196 197
    end
  end

198
  def test_class_with_nested_inline_subclass_of_parent
J
Jeremy Kemper 已提交
199
    with_autoloading_fixtures do
200 201 202
      assert_kind_of Class, ClassFolder::ClassFolderSubclass
      assert_kind_of Class, ClassFolder
      assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
203
      Object.__send__ :remove_const, :ClassFolder
204 205 206
    end
  end

207
  def test_nested_class_can_access_sibling
J
Jeremy Kemper 已提交
208
    with_autoloading_fixtures do
209 210 211
      sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
      assert defined?(ModuleFolder::NestedSibling)
      assert_equal ModuleFolder::NestedSibling, sibling
212
      Object.__send__ :remove_const, :ModuleFolder
213 214
    end
  end
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  def test_doesnt_break_normal_require
    path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
    original_path = $:.dup
    original_features = $".dup
    $:.push(path)

    with_autoloading_fixtures do
      RequiresConstant
      assert defined?(RequiresConstant)
      assert defined?(LoadedConstant)
      ActiveSupport::Dependencies.clear
      RequiresConstant
      assert defined?(RequiresConstant)
      assert defined?(LoadedConstant)
    end
  ensure
    remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
    $".replace(original_features)
    $:.replace(original_path)
  end

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

    with_autoloading_fixtures do
      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_features)
    $:.replace(original_path)
  end

258
  def failing_test_access_thru_and_upwards_fails
J
Jeremy Kemper 已提交
259
    with_autoloading_fixtures do
260
      assert ! defined?(ModuleFolder)
261 262
      assert_raise(NameError) { ModuleFolder::Object }
      assert_raise(NameError) { ModuleFolder::NestedClass::Object }
263
      Object.__send__ :remove_const, :ModuleFolder
264 265
    end
  end
266

267
  def test_non_existing_const_raises_name_error_with_fully_qualified_name
J
Jeremy Kemper 已提交
268
    with_autoloading_fixtures do
269
      begin
270
        A::DoesNotExist.nil?
271 272 273 274 275
        flunk "No raise!!"
      rescue NameError => e
        assert_equal "uninitialized constant A::DoesNotExist", e.message
      end
      begin
276
        A::B::DoesNotExist.nil?
277 278 279 280 281 282
        flunk "No raise!!"
      rescue NameError => e
        assert_equal "uninitialized constant A::B::DoesNotExist", e.message
      end
    end
  end
283

284 285 286 287 288 289 290 291
  def test_smart_name_error_strings
    begin
      Object.module_eval "ImaginaryObject"
      flunk "No raise!!"
    rescue NameError => e
      assert e.message.include?("uninitialized constant ImaginaryObject")
    end
  end
292

293
  def test_loadable_constants_for_path_should_handle_empty_autoloads
294
    assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello')
295
  end
296

297
  def test_loadable_constants_for_path_should_handle_relative_paths
298 299 300 301
    fake_root = 'dependencies'
    relative_root = File.dirname(__FILE__) + '/dependencies'
    ['', '/'].each do |suffix|
      with_loading fake_root + suffix do
302
        assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b')
303 304 305
      end
    end
  end
306

307
  def test_loadable_constants_for_path_should_provide_all_results
308 309
    fake_root = '/usr/apps/backpack'
    with_loading fake_root, fake_root + '/lib' do
310
      root = ActiveSupport::Dependencies.autoload_paths.first
311
      assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b')
312 313
    end
  end
314

315
  def test_loadable_constants_for_path_should_uniq_results
316 317
    fake_root = '/usr/apps/backpack/lib'
    with_loading fake_root, fake_root + '/' do
318
      root = ActiveSupport::Dependencies.autoload_paths.first
319
      assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b')
320 321
    end
  end
322

323 324 325
  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
326
      assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path)
327 328
    end
  end
329

330
  def test_qualified_const_defined
331 332 333 334
    assert ActiveSupport::Dependencies.qualified_const_defined?("Object")
    assert ActiveSupport::Dependencies.qualified_const_defined?("::Object")
    assert ActiveSupport::Dependencies.qualified_const_defined?("::Object::Kernel")
    assert ActiveSupport::Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
335
  end
336

337
  def test_qualified_const_defined_should_not_call_const_missing
338
    ModuleWithMissing.missing_count = 0
339
    assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A")
340
    assert_equal 0, ModuleWithMissing.missing_count
341
    assert ! ActiveSupport::Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
342 343
    assert_equal 0, ModuleWithMissing.missing_count
  end
344

345 346 347 348
  def test_qualified_const_defined_explodes_with_invalid_const_name
    assert_raises(NameError) { ActiveSupport::Dependencies.qualified_const_defined?("invalid") }
  end

349
  def test_autoloaded?
J
Jeremy Kemper 已提交
350
    with_autoloading_fixtures do
351 352
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
353

354
      assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
355

356 357
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
358

359
      assert ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
360

361 362
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
363

364 365
      assert ActiveSupport::Dependencies.autoloaded?("::ModuleFolder")
      assert ActiveSupport::Dependencies.autoloaded?(:ModuleFolder)
366

367
      # Anonymous modules aren't autoloaded.
368
      assert !ActiveSupport::Dependencies.autoloaded?(Module.new)
369 370 371

      nil_name = Module.new
      def nil_name.name() nil end
372
      assert !ActiveSupport::Dependencies.autoloaded?(nil_name)
373

J
Jeremy Kemper 已提交
374
      Object.class_eval { remove_const :ModuleFolder }
375 376
    end
  end
377

378
  def test_qualified_name_for
379 380 381 382
    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)
383

384 385
    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)
386
  end
387

388 389
  def test_file_search
    with_loading 'dependencies' do
390
      root = ActiveSupport::Dependencies.autoload_paths.first
391 392 393 394
      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')
395 396
    end
  end
397

398
  def test_file_search_uses_first_in_load_path
399
    with_loading 'dependencies', 'autoloading_fixtures' do
400
      deps, autoload = ActiveSupport::Dependencies.autoload_paths
401 402
      assert_match %r/dependencies/, deps
      assert_match %r/autoloading_fixtures/, autoload
403

404
      assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
405 406
    end
    with_loading 'autoloading_fixtures', 'dependencies' do
407
      autoload, deps = ActiveSupport::Dependencies.autoload_paths
408 409
      assert_match %r/dependencies/, deps
      assert_match %r/autoloading_fixtures/, autoload
410

411
      assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict')
412
    end
413

414
  end
415

416
  def test_custom_const_missing_should_work
417
    Object.module_eval <<-end_eval, __FILE__, __LINE__ + 1
418 419 420 421 422 423 424 425 426
      module ModuleWithCustomConstMissing
        def self.const_missing(name)
          const_set name, name.to_s.hash
        end

        module A
        end
      end
    end_eval
427

J
Jeremy Kemper 已提交
428
    with_autoloading_fixtures do
429 430 431 432 433
      assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
      assert_kind_of Module, ::ModuleWithCustomConstMissing::A
      assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
    end
  end
434

435
  def test_const_missing_should_not_double_load
436
    $counting_loaded_times = 0
J
Jeremy Kemper 已提交
437
    with_autoloading_fixtures do
438
      require_dependency '././counting_loader'
439
      assert_equal 1, $counting_loaded_times
440
      assert_raise(ArgumentError) { ActiveSupport::Dependencies.load_missing_constant Object, :CountingLoader }
441 442 443
      assert_equal 1, $counting_loaded_times
    end
  end
444

445 446 447 448 449
  def test_const_missing_within_anonymous_module
    $counting_loaded_times = 0
    m = Module.new
    m.module_eval "def a() CountingLoader; end"
    extend m
450
    kls = nil
J
Jeremy Kemper 已提交
451
    with_autoloading_fixtures do
452 453 454 455
      kls = nil
      assert_nothing_raised { kls = a }
      assert_equal "CountingLoader", kls.name
      assert_equal 1, $counting_loaded_times
456

457
      assert_nothing_raised { kls = a }
458 459 460
      assert_equal 1, $counting_loaded_times
    end
  end
461

462 463 464
  def test_removal_from_tree_should_be_detected
    with_loading 'dependencies' do
      c = ServiceOne
465
      ActiveSupport::Dependencies.clear
466 467
      assert ! defined?(ServiceOne)
      begin
468
        ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing)
469 470 471 472 473 474
        flunk "Expected exception"
      rescue ArgumentError => e
        assert_match %r{ServiceOne has been removed from the module tree}i, e.message
      end
    end
  end
475

W
wycats 已提交
476 477 478 479 480 481 482 483 484 485 486 487 488 489
  def test_references_should_work
    with_loading 'dependencies' do
      c = ActiveSupport::Dependencies.ref("ServiceOne")
      service_one_first = ServiceOne
      assert_equal service_one_first, c.get
      ActiveSupport::Dependencies.clear
      assert ! defined?(ServiceOne)

      service_one_second = ServiceOne
      assert_not_equal service_one_first, c.get
      assert_equal service_one_second, c.get
    end
  end

490 491 492 493 494 495
  def test_constantize_shortcut_for_cached_constant_lookups
    with_loading 'dependencies' do
      assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne")
    end
  end

N
Nicholas Seckar 已提交
496 497
  def test_nested_load_error_isnt_rescued
    with_loading 'dependencies' do
498
      assert_raise(MissingSourceFile) do
N
Nicholas Seckar 已提交
499 500 501 502
        RequiresNonexistent1
      end
    end
  end
503

504
  def test_autoload_once_paths_do_not_add_to_autoloaded_constants
J
Jeremy Kemper 已提交
505
    with_autoloading_fixtures do
506
      ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths.dup
507

508 509 510
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
      assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
      assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
511

512
      1 if ModuleFolder::NestedClass # 1 if to avoid warning
513
      assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
514 515
    end
  ensure
J
Jeremy Kemper 已提交
516
    Object.class_eval { remove_const :ModuleFolder }
517
    ActiveSupport::Dependencies.autoload_once_paths = []
518
  end
519

520
  def test_application_should_special_case_application_controller
J
Jeremy Kemper 已提交
521
    with_autoloading_fixtures do
522 523
      require_dependency 'application'
      assert_equal 10, ApplicationController
524
      assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController)
525 526
    end
  end
527

528
  def test_preexisting_constants_are_not_marked_as_autoloaded
J
Jeremy Kemper 已提交
529
    with_autoloading_fixtures do
530
      require_dependency 'e'
531 532
      assert ActiveSupport::Dependencies.autoloaded?(:E)
      ActiveSupport::Dependencies.clear
533
    end
534

535
    Object.const_set :E, Class.new
J
Jeremy Kemper 已提交
536
    with_autoloading_fixtures do
537
      require_dependency 'e'
538 539
      assert ! ActiveSupport::Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
      ActiveSupport::Dependencies.clear
540
    end
541

542
  ensure
J
Jeremy Kemper 已提交
543
    Object.class_eval { remove_const :E }
544
  end
545

546
  def test_unloadable
J
Jeremy Kemper 已提交
547
    with_autoloading_fixtures do
548 549
      Object.const_set :M, Module.new
      M.unloadable
550

551
      ActiveSupport::Dependencies.clear
552
      assert ! defined?(M)
553

554
      Object.const_set :M, Module.new
555
      ActiveSupport::Dependencies.clear
556 557 558
      assert ! defined?(M), "Dependencies should unload unloadable constants each time"
    end
  end
559

560
  def test_unloadable_should_fail_with_anonymous_modules
J
Jeremy Kemper 已提交
561
    with_autoloading_fixtures do
562
      m = Module.new
563
      assert_raise(ArgumentError) { m.unloadable }
564 565
    end
  end
566

567
  def test_unloadable_should_return_change_flag
J
Jeremy Kemper 已提交
568
    with_autoloading_fixtures do
569 570 571 572 573
      Object.const_set :M, Module.new
      assert_equal true, M.unloadable
      assert_equal false, M.unloadable
    end
  end
574

575
  def test_new_contants_in_without_constants
576 577
    assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
    assert ActiveSupport::Dependencies.constant_watch_stack.empty?
578
  end
579

580
  def test_new_constants_in_with_a_single_constant
581
    assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) {
J
Jeremy Kemper 已提交
582 583
                              Object.const_set :Hello, 10
                            }.map(&:to_s)
584
    assert ActiveSupport::Dependencies.constant_watch_stack.empty?
585
  ensure
J
Jeremy Kemper 已提交
586
    Object.class_eval { remove_const :Hello }
587
  end
588

589
  def test_new_constants_in_with_nesting
590
    outer = ActiveSupport::Dependencies.new_constants_in(Object) do
591
      Object.const_set :OuterBefore, 10
592

593
      assert_equal ["Inner"], ActiveSupport::Dependencies.new_constants_in(Object) {
J
Jeremy Kemper 已提交
594 595
                                Object.const_set :Inner, 20
                              }.map(&:to_s)
596

597 598
      Object.const_set :OuterAfter, 30
    end
599

J
Jeremy Kemper 已提交
600
    assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
601
    assert ActiveSupport::Dependencies.constant_watch_stack.empty?
602 603
  ensure
    %w(OuterBefore Inner OuterAfter).each do |name|
J
Jeremy Kemper 已提交
604
      Object.class_eval { remove_const name if const_defined?(name) }
605 606
    end
  end
607

608 609
  def test_new_constants_in_module
    Object.const_set :M, Module.new
610

611
    outer = ActiveSupport::Dependencies.new_constants_in(M) do
612
      M.const_set :OuterBefore, 10
613

614
      inner = ActiveSupport::Dependencies.new_constants_in(M) do
615 616 617
        M.const_set :Inner, 20
      end
      assert_equal ["M::Inner"], inner
618

619 620 621
      M.const_set :OuterAfter, 30
    end
    assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
622
    assert ActiveSupport::Dependencies.constant_watch_stack.empty?
623
  ensure
J
Jeremy Kemper 已提交
624
    Object.class_eval { remove_const :M }
625
  end
626

627
  def test_new_constants_in_module_using_name
628
    outer = ActiveSupport::Dependencies.new_constants_in(:M) do
629 630
      Object.const_set :M, Module.new
      M.const_set :OuterBefore, 10
631

632
      inner = ActiveSupport::Dependencies.new_constants_in(:M) do
633 634 635
        M.const_set :Inner, 20
      end
      assert_equal ["M::Inner"], inner
636

637 638 639
      M.const_set :OuterAfter, 30
    end
    assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
640
    assert ActiveSupport::Dependencies.constant_watch_stack.empty?
641
  ensure
J
Jeremy Kemper 已提交
642
    Object.class_eval { remove_const :M }
643
  end
644

645
  def test_new_constants_in_with_inherited_constants
646
    m = ActiveSupport::Dependencies.new_constants_in(:Object) do
J
Jeremy Kemper 已提交
647
      Object.class_eval { include ModuleWithConstant }
648 649 650 651
    end
    assert_equal [], m
  end

652
  def test_new_constants_in_with_illegal_module_name_raises_correct_error
653
    assert_raise(NameError) do
654
      ActiveSupport::Dependencies.new_constants_in("Illegal-Name") {}
655 656 657
    end
  end

658
  def test_file_with_multiple_constants_and_require_dependency
J
Jeremy Kemper 已提交
659
    with_autoloading_fixtures do
660 661
      assert ! defined?(MultipleConstantFile)
      assert ! defined?(SiblingConstant)
662

663 664 665
      require_dependency 'multiple_constant_file'
      assert defined?(MultipleConstantFile)
      assert defined?(SiblingConstant)
666 667
      assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
      assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
668

669
      ActiveSupport::Dependencies.clear
670

671 672 673 674
      assert ! defined?(MultipleConstantFile)
      assert ! defined?(SiblingConstant)
    end
  end
675

676
  def test_file_with_multiple_constants_and_auto_loading
J
Jeremy Kemper 已提交
677
    with_autoloading_fixtures do
678 679
      assert ! defined?(MultipleConstantFile)
      assert ! defined?(SiblingConstant)
680

681
      assert_equal 10, MultipleConstantFile
682

683 684
      assert defined?(MultipleConstantFile)
      assert defined?(SiblingConstant)
685 686
      assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
      assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
687

688
      ActiveSupport::Dependencies.clear
689

690 691 692 693
      assert ! defined?(MultipleConstantFile)
      assert ! defined?(SiblingConstant)
    end
  end
694

695
  def test_nested_file_with_multiple_constants_and_require_dependency
J
Jeremy Kemper 已提交
696
    with_autoloading_fixtures do
697 698
      assert ! defined?(ClassFolder::NestedClass)
      assert ! defined?(ClassFolder::SiblingClass)
699

700
      require_dependency 'class_folder/nested_class'
701

702 703
      assert defined?(ClassFolder::NestedClass)
      assert defined?(ClassFolder::SiblingClass)
704 705
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
706

707
      ActiveSupport::Dependencies.clear
708

709 710 711 712
      assert ! defined?(ClassFolder::NestedClass)
      assert ! defined?(ClassFolder::SiblingClass)
    end
  end
713

714
  def test_nested_file_with_multiple_constants_and_auto_loading
J
Jeremy Kemper 已提交
715
    with_autoloading_fixtures do
716 717
      assert ! defined?(ClassFolder::NestedClass)
      assert ! defined?(ClassFolder::SiblingClass)
718

719
      assert_kind_of Class, ClassFolder::NestedClass
720

721 722
      assert defined?(ClassFolder::NestedClass)
      assert defined?(ClassFolder::SiblingClass)
723 724
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::NestedClass")
      assert ActiveSupport::Dependencies.autoloaded?("ClassFolder::SiblingClass")
725

726
      ActiveSupport::Dependencies.clear
727

728 729 730 731 732
      assert ! defined?(ClassFolder::NestedClass)
      assert ! defined?(ClassFolder::SiblingClass)
    end
  end

J
Jeremy Kemper 已提交
733
  def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
J
Jeremy Kemper 已提交
734
    with_autoloading_fixtures do
J
Jeremy Kemper 已提交
735
      assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
736 737
      2.times do
        assert_raise(NoMethodError) { RaisesNoMethodError }
J
Jeremy Kemper 已提交
738
        assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
739
      end
J
Jeremy Kemper 已提交
740
    end
741

742
  ensure
J
Jeremy Kemper 已提交
743
    Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
J
Jeremy Kemper 已提交
744
  end
745

J
Jeremy Kemper 已提交
746
  def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
J
Jeremy Kemper 已提交
747
    with_autoloading_fixtures do
J
Jeremy Kemper 已提交
748
      assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
749 750
      2.times do
        assert_raise(NoMethodError) { ::RaisesNoMethodError }
J
Jeremy Kemper 已提交
751
        assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
752 753
      end
    end
754

755
  ensure
J
Jeremy Kemper 已提交
756
    Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
757 758
  end

759
  def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load
J
Jeremy Kemper 已提交
760
    with_autoloading_fixtures do
761
      ActiveSupport::Dependencies.mechanism = :require
762
      2.times do
763
        assert_raise(NameError) { assert_equal 123, ::RaisesNameError::FooBarBaz }
764 765 766 767
      end
    end
  end

768
  def test_autoload_doesnt_shadow_name_error
J
Jeremy Kemper 已提交
769
    with_autoloading_fixtures do
770
      Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
771
      2.times do |i|
772
        begin
773
          ::RaisesNameError::FooBarBaz.object_id
774 775 776 777
          flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
        rescue NameError => e
          assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
        end
J
Jeremy Kemper 已提交
778
        assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
779 780
      end

781
      assert !defined?(::RaisesNameError)
782
      2.times do
783
        assert_raise(NameError) { ::RaisesNameError }
J
Jeremy Kemper 已提交
784
        assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
785 786
      end
    end
J
Jeremy Kemper 已提交
787

788
  ensure
J
Jeremy Kemper 已提交
789
    Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
790
  end
791

792 793 794
  def test_remove_constant_handles_double_colon_at_start
    Object.const_set 'DeleteMe', Module.new
    DeleteMe.const_set 'OrMe', Module.new
795
    ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe"
796 797
    assert ! defined?(DeleteMe::OrMe)
    assert defined?(DeleteMe)
798
    ActiveSupport::Dependencies.remove_constant "::DeleteMe"
799 800
    assert ! defined?(DeleteMe)
  end
801

802
  def test_load_once_constants_should_not_be_unloaded
J
Jeremy Kemper 已提交
803
    with_autoloading_fixtures do
804
      ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths
805
      ::A.to_s
806
      assert defined?(A)
807
      ActiveSupport::Dependencies.clear
808 809 810
      assert defined?(A)
    end
  ensure
811
    ActiveSupport::Dependencies.autoload_once_paths = []
J
Jeremy Kemper 已提交
812
    Object.class_eval { remove_const :A if const_defined?(:A) }
813
  end
814

815
  def test_autoload_once_paths_should_behave_when_recursively_loading
816
    with_loading 'dependencies', 'autoloading_fixtures' do
817
      ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last]
818 819
      assert !defined?(CrossSiteDependency)
      assert_nothing_raised { CrossSiteDepender.nil? }
820
      assert defined?(CrossSiteDependency)
821
      assert !ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
822
        "CrossSiteDependency shouldn't be marked as autoloaded!"
823
      ActiveSupport::Dependencies.clear
824 825 826 827
      assert defined?(CrossSiteDependency),
        "CrossSiteDependency shouldn't have been unloaded!"
    end
  ensure
828
    ActiveSupport::Dependencies.autoload_once_paths = []
829
  end
830 831 832 833 834 835 836 837 838 839 840 841

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

  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
842 843 844 845 846 847 848

private
  def remove_constants(*constants)
    constants.each do |constant|
      Object.send(:remove_const, constant) if Object.const_defined?(constant)
    end
  end
849
end