require 'abstract_unit' require 'active_support/time' require 'active_support/core_ext/object' require 'active_support/core_ext/class/removal' class ClassA; end class ClassB < ClassA; end class ClassC < ClassB; end class ClassD < ClassA; end class ClassI; end class ClassJ < ClassI; end class ClassK end module Nested class << self def on_const_missing(&callback) @on_const_missing = callback end private def const_missing(mod_id) @on_const_missing[mod_id] if @on_const_missing super end end class ClassL < ClassK end end module Bar def bar; end end module Baz def baz; end end class Foo include Bar end class ClassExtTest < Test::Unit::TestCase def test_subclasses_of_should_find_nested_classes assert Object.subclasses_of(ClassK).include?(Nested::ClassL) end def test_subclasses_of_should_not_return_removed_classes # First create the removed class old_class = Nested.class_eval { remove_const :ClassL } new_class = Class.new(ClassK) Nested.const_set :ClassL, new_class assert_equal "Nested::ClassL", new_class.name # Sanity check subclasses = Object.subclasses_of(ClassK) assert subclasses.include?(new_class) assert ! subclasses.include?(old_class) ensure Nested.const_set :ClassL, old_class unless defined?(Nested::ClassL) end def test_subclasses_of_should_not_trigger_const_missing const_missing = false Nested.on_const_missing { const_missing = true } subclasses = Object.subclasses_of ClassK assert !const_missing assert_equal [ Nested::ClassL ], subclasses removed = Nested.class_eval { remove_const :ClassL } # keep it in memory subclasses = Object.subclasses_of ClassK assert !const_missing assert subclasses.empty? ensure Nested.const_set :ClassL, removed unless defined?(Nested::ClassL) end def test_subclasses_of_with_multiple_roots classes = Object.subclasses_of(ClassI, ClassK) assert_equal %w(ClassJ Nested::ClassL), classes.collect(&:to_s).sort end def test_subclasses_of_doesnt_find_anonymous_classes assert_equal [], Object.subclasses_of(Foo) bar = Class.new(Foo) assert_nothing_raised do assert_equal [bar], Object.subclasses_of(Foo) end end end class ObjectTests < Test::Unit::TestCase def test_extended_by foo = Foo.new assert foo.extended_by.include?(Bar) foo.extend(Baz) assert(([Bar, Baz] - foo.extended_by).empty?, "Expected Bar, Baz in #{foo.extended_by.inspect}") end def test_extend_with_included_modules_from foo, object = Foo.new, Object.new assert !object.respond_to?(:bar) assert !object.respond_to?(:baz) object.extend_with_included_modules_from(foo) assert object.respond_to?(:bar) assert !object.respond_to?(:baz) foo.extend(Baz) object.extend_with_included_modules_from(foo) assert object.respond_to?(:bar) assert object.respond_to?(:baz) end class DuckTime def acts_like_time? true end end def test_duck_typing object = Object.new time = Time.now date = Date.today dt = DateTime.new duck = DuckTime.new assert !object.acts_like?(:time) assert !object.acts_like?(:date) assert time.acts_like?(:time) assert !time.acts_like?(:date) assert !date.acts_like?(:time) assert date.acts_like?(:date) assert dt.acts_like?(:time) assert dt.acts_like?(:date) assert duck.acts_like?(:time) assert !duck.acts_like?(:date) end def test_metaclass string = "Hello" string.metaclass.instance_eval do define_method(:foo) { "bar" } end assert_equal "bar", string.foo end end class ObjectInstanceVariableTest < Test::Unit::TestCase def setup @source, @dest = Object.new, Object.new @source.instance_variable_set(:@bar, 'bar') @source.instance_variable_set(:@baz, 'baz') end def test_instance_variable_names assert_equal %w(@bar @baz), @source.instance_variable_names.sort end def test_copy_instance_variables_from_without_explicit_excludes assert_equal [], @dest.instance_variables @dest.copy_instance_variables_from(@source) assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s) %w(@bar @baz).each do |name| assert_equal @source.instance_variable_get(name).object_id, @dest.instance_variable_get(name).object_id end end def test_copy_instance_variables_from_with_explicit_excludes @dest.copy_instance_variables_from(@source, ['@baz']) assert !@dest.instance_variable_defined?('@baz') assert_equal 'bar', @dest.instance_variable_get('@bar') end def test_copy_instance_variables_automatically_excludes_protected_instance_variables @source.instance_variable_set(:@quux, 'quux') class << @source def protected_instance_variables ['@bar', :@quux] end end @dest.copy_instance_variables_from(@source) assert !@dest.instance_variable_defined?('@bar') assert !@dest.instance_variable_defined?('@quux') assert_equal 'baz', @dest.instance_variable_get('@baz') end def test_instance_values object = Object.new object.instance_variable_set :@a, 1 object.instance_variable_set :@b, 2 assert_equal({'a' => 1, 'b' => 2}, object.instance_values) end def test_instance_exec_passes_arguments_to_block assert_equal %w(hello goodbye), 'hello'.instance_exec('goodbye') { |v| [self, v] } end def test_instance_exec_with_frozen_obj assert_equal %w(olleh goodbye), 'hello'.freeze.instance_exec('goodbye') { |v| [reverse, v] } end def test_instance_exec_nested assert_equal %w(goodbye olleh bar), 'hello'.instance_exec('goodbye') { |arg| [arg] + instance_exec('bar') { |v| [reverse, v] } } end end class ObjectTryTest < Test::Unit::TestCase def setup @string = "Hello" end def test_nonexisting_method method = :undefined_method assert !@string.respond_to?(method) assert_raise(NoMethodError) { @string.try(method) } end def test_valid_method assert_equal 5, @string.try(:size) end def test_argument_forwarding assert_equal 'Hey', @string.try(:sub, 'llo', 'y') end def test_block_forwarding assert_equal 'Hey', @string.try(:sub, 'llo') { |match| 'y' } end def test_nil_to_type assert_nil nil.try(:to_s) assert_nil nil.try(:to_i) end def test_false_try assert_equal 'false', false.try(:to_s) end end