diff options
Diffstat (limited to 'activesupport/test')
87 files changed, 3121 insertions, 1586 deletions
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index dd17cb64f4..52fbaf8a85 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -8,7 +8,6 @@ ensure end require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/string/encoding' silence_warnings do Encoding.default_internal = "UTF-8" @@ -16,7 +15,6 @@ silence_warnings do end require 'active_support/testing/autorun' -require 'empty_bool' ENV['NO_RELOAD'] = '1' require 'active_support' @@ -25,3 +23,23 @@ Thread.abort_on_exception = true # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true + +# Disable available locale checks to avoid warnings running the test suite. +I18n.enforce_available_locales = false + +# Skips the current run on Rubinius using Minitest::Assertions#skip +def rubinius_skip(message = '') + skip message if RUBY_ENGINE == 'rbx' +end + +# Skips the current run on JRuby using Minitest::Assertions#skip +def jruby_skip(message = '') + skip message if defined?(JRUBY_VERSION) +end + +require 'mocha/setup' # FIXME: stop using mocha + +# FIXME: we have tests that depend on run order, we should fix that and +# remove this method call. +require 'active_support/test_case' +ActiveSupport::TestCase.my_tests_are_order_dependent! diff --git a/activesupport/test/autoloading_fixtures/html/some_class.rb b/activesupport/test/autoloading_fixtures/html/some_class.rb new file mode 100644 index 0000000000..b43d15d891 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/html/some_class.rb @@ -0,0 +1,4 @@ +module HTML + class SomeClass + end +end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index ae6eaa4b60..5945605f7b 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -3,6 +3,42 @@ require 'abstract_unit' require 'active_support/cache' require 'dependencies_test_helpers' +module ActiveSupport + module Cache + module Strategy + module LocalCache + class MiddlewareTest < ActiveSupport::TestCase + def test_local_cache_cleared_on_close + key = "super awesome key" + assert_nil LocalCacheRegistry.cache_for key + middleware = Middleware.new('<3', key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), 'should have a cache' + [200, {}, []] + }) + _, _, body = middleware.call({}) + assert LocalCacheRegistry.cache_for(key), 'should still have a cache' + body.each { } + assert LocalCacheRegistry.cache_for(key), 'should still have a cache' + body.close + assert_nil LocalCacheRegistry.cache_for(key) + end + + def test_local_cache_cleared_on_exception + key = "super awesome key" + assert_nil LocalCacheRegistry.cache_for key + middleware = Middleware.new('<3', key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), 'should have a cache' + raise + }) + assert_raises(RuntimeError) { middleware.call({}) } + assert_nil LocalCacheRegistry.cache_for(key) + end + end + end + end + end +end + class CacheKeyTest < ActiveSupport::TestCase def test_entry_legacy_optional_ivars legacy = Class.new(ActiveSupport::Cache::Entry) do @@ -24,36 +60,25 @@ class CacheKeyTest < ActiveSupport::TestCase end def test_expand_cache_key_with_rails_cache_id - begin - ENV['RAILS_CACHE_ID'] = 'c99' + with_env('RAILS_CACHE_ID' => 'c99') do assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key([:foo]) assert_equal 'c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar]) assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key(:foo, :nm) assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key([:foo], :nm) assert_equal 'nm/c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) - ensure - ENV['RAILS_CACHE_ID'] = nil end end def test_expand_cache_key_with_rails_app_version - begin - ENV['RAILS_APP_VERSION'] = 'rails3' + with_env('RAILS_APP_VERSION' => 'rails3') do assert_equal 'rails3/foo', ActiveSupport::Cache.expand_cache_key(:foo) - ensure - ENV['RAILS_APP_VERSION'] = nil end end def test_expand_cache_key_rails_cache_id_should_win_over_rails_app_version - begin - ENV['RAILS_CACHE_ID'] = 'c99' - ENV['RAILS_APP_VERSION'] = 'rails3' + with_env('RAILS_CACHE_ID' => 'c99', 'RAILS_APP_VERSION' => 'rails3') do assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) - ensure - ENV['RAILS_CACHE_ID'] = nil - ENV['RAILS_APP_VERSION'] = nil end end @@ -88,6 +113,16 @@ class CacheKeyTest < ActiveSupport::TestCase def test_expand_cache_key_of_array_like_object assert_equal 'foo/bar/baz', ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) end + + private + + def with_env(kv) + old_values = {} + kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } + yield + ensure + old_values.each { |key, value| ENV[key] = value} + end end class CacheStoreSettingTest < ActiveSupport::TestCase @@ -110,12 +145,12 @@ class CacheStoreSettingTest < ActiveSupport::TestCase assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) end - def test_mem_cache_fragment_cache_store_with_given_mem_cache_like_object + def test_mem_cache_fragment_cache_store_with_not_dalli_client Dalli::Client.expects(:new).never memcache = Object.new - def memcache.get() true end - store = ActiveSupport::Cache.lookup_store :mem_cache_store, memcache - assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) + assert_raises(ArgumentError) do + ActiveSupport::Cache.lookup_store :mem_cache_store, memcache + end end def test_mem_cache_fragment_cache_store_with_multiple_servers @@ -261,20 +296,21 @@ module CacheStoreBehavior @cache.write('foo', 'bar') @cache.write('fud', 'biz') - values = @cache.fetch_multi('foo', 'fu', 'fud') {|value| value * 2 } + values = @cache.fetch_multi('foo', 'fu', 'fud') { |value| value * 2 } - assert_equal(["bar", "fufu", "biz"], values) - assert_equal("fufu", @cache.read('fu')) + assert_equal({ 'foo' => 'bar', 'fu' => 'fufu', 'fud' => 'biz' }, values) + assert_equal('fufu', @cache.read('fu')) end def test_multi_with_objects - foo = stub(:title => "FOO!", :cache_key => "foo") - bar = stub(:cache_key => "bar") + foo = stub(:title => 'FOO!', :cache_key => 'foo') + bar = stub(:cache_key => 'bar') + + @cache.write('bar', 'BAM!') - @cache.write('bar', "BAM!") + values = @cache.fetch_multi(foo, bar) { |object| object.title } - values = @cache.fetch_multi(foo, bar) {|object| object.title } - assert_equal(["FOO!", "BAM!"], values) + assert_equal({ foo => 'FOO!', bar => 'BAM!' }, values) end def test_read_and_write_compressed_small_data @@ -327,8 +363,8 @@ module CacheStoreBehavior def test_exist @cache.write('foo', 'bar') - assert @cache.exist?('foo') - assert !@cache.exist?('bar') + assert_equal true, @cache.exist?('foo') + assert_equal false, @cache.exist?('bar') end def test_nil_exist @@ -577,6 +613,7 @@ module LocalCacheBehavior result = @cache.write('foo', 'bar') assert_equal 'bar', @cache.read('foo') # make sure 'foo' was written assert result + [200, {}, []] } app = @cache.middleware.new(app) app.call({}) @@ -654,6 +691,11 @@ class FileStoreTest < ActiveSupport::TestCase assert File.exist?(filepath) end + def test_long_keys + @cache.write("a"*10000, 1) + assert_equal 1, @cache.read("a"*10000) + end + def test_key_transformation key = @cache.send(:key_file_path, "views/index?id=1") assert_equal "views/index?id=1", @cache.send(:file_path_key, key) @@ -709,12 +751,31 @@ class FileStoreTest < ActiveSupport::TestCase @cache.send(:read_entry, "winston", {}) assert @buffer.string.present? end + + def test_cleanup_removes_all_expired_entries + time = Time.now + @cache.write('foo', 'bar', expires_in: 10) + @cache.write('baz', 'qux') + @cache.write('quux', 'corge', expires_in: 20) + Time.stubs(:now).returns(time + 15) + @cache.cleanup + assert_not @cache.exist?('foo') + assert @cache.exist?('baz') + assert @cache.exist?('quux') + end + + def test_write_with_unless_exist + assert_equal true, @cache.write(1, "aaaaaaaaaa") + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) + @cache.write(1, nil) + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) + end end class MemoryStoreTest < ActiveSupport::TestCase def setup - @record_size = ActiveSupport::Cache::Entry.new("aaaaaaaaaa").size - @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10) + @record_size = ActiveSupport::Cache.lookup_store(:memory_store).send(:cached_size, 1, ActiveSupport::Cache::Entry.new("aaaaaaaaaa")) + @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10 + 1) end include CacheStoreBehavior @@ -764,6 +825,30 @@ class MemoryStoreTest < ActiveSupport::TestCase assert !@cache.exist?(1), "no entry" end + def test_prune_size_on_write_based_on_key_length + @cache.write(1, "aaaaaaaaaa") && sleep(0.001) + @cache.write(2, "bbbbbbbbbb") && sleep(0.001) + @cache.write(3, "cccccccccc") && sleep(0.001) + @cache.write(4, "dddddddddd") && sleep(0.001) + @cache.write(5, "eeeeeeeeee") && sleep(0.001) + @cache.write(6, "ffffffffff") && sleep(0.001) + @cache.write(7, "gggggggggg") && sleep(0.001) + @cache.write(8, "hhhhhhhhhh") && sleep(0.001) + @cache.write(9, "iiiiiiiiii") && sleep(0.001) + long_key = '*' * 2 * @record_size + @cache.write(long_key, "llllllllll") + assert @cache.exist?(long_key) + assert @cache.exist?(9) + assert @cache.exist?(8) + assert @cache.exist?(7) + assert @cache.exist?(6) + assert !@cache.exist?(5), "no entry" + assert !@cache.exist?(4), "no entry" + assert !@cache.exist?(3), "no entry" + assert !@cache.exist?(2), "no entry" + assert !@cache.exist?(1), "no entry" + end + def test_pruning_is_capped_at_a_max_time def @cache.delete_entry (*args) sleep(0.01) @@ -854,8 +939,8 @@ class MemCacheStoreTest < ActiveSupport::TestCase def test_read_should_return_a_different_object_id_each_time_it_is_called @cache.write('foo', 'bar') - assert_not_equal @cache.read('foo').object_id, @cache.read('foo').object_id value = @cache.read('foo') + assert_not_equal value.object_id, @cache.read('foo').object_id value << 'bingo' assert_not_equal value, @cache.read('foo') end diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index f8e2ce22fa..32c2dfdfc0 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,27 +1,6 @@ require 'abstract_unit' module CallbacksTest - class Phone - include ActiveSupport::Callbacks - define_callbacks :save - - set_callback :save, :before, :before_save1 - set_callback :save, :after, :after_save1 - - def before_save1; self.history << :before; end - def after_save1; self.history << :after; end - - def save - run_callbacks :save do - raise 'boom' - end - end - - def history - @history ||= [] - end - end - class Record include ActiveSupport::Callbacks diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index dd67a45cf6..05580352a9 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -34,6 +34,11 @@ class BacktraceCleanerSilencerTest < ActiveSupport::TestCase [ "/other/class.rb" ], @bc.clean([ "/mongrel/class.rb", "/other/class.rb", "/mongrel/stuff.rb" ]) end + + test "backtrace cleaner should allow removing silencer" do + @bc.remove_silencers! + assert_equal ["/mongrel/stuff.rb"], @bc.clean(["/mongrel/stuff.rb"]) + end end class BacktraceCleanerMultipleSilencersTest < ActiveSupport::TestCase diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 8e2c298fc6..60bd8a06aa 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -5,7 +5,7 @@ class ConcernTest < ActiveSupport::TestCase module Baz extend ActiveSupport::Concern - module ClassMethods + class_methods do def baz "baz" end @@ -33,6 +33,12 @@ class ConcernTest < ActiveSupport::TestCase include Baz + module ClassMethods + def baz + "bar's baz + " + super + end + end + def bar "bar" end @@ -56,10 +62,6 @@ class ConcernTest < ActiveSupport::TestCase @klass.send(:include, Baz) assert_equal "baz", @klass.new.baz assert @klass.included_modules.include?(ConcernTest::Baz) - - @klass.send(:include, Baz) - assert_equal "baz", @klass.new.baz - assert @klass.included_modules.include?(ConcernTest::Baz) end def test_class_methods_are_extended @@ -68,12 +70,6 @@ class ConcernTest < ActiveSupport::TestCase assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; self.included_modules; end)[0] end - def test_instance_methods_are_included - @klass.send(:include, Baz) - assert_equal "baz", @klass.new.baz - assert @klass.included_modules.include?(ConcernTest::Baz) - end - def test_included_block_is_ran @klass.send(:include, Baz) assert_equal true, @klass.included_ran @@ -83,7 +79,7 @@ class ConcernTest < ActiveSupport::TestCase @klass.send(:include, Bar) assert_equal "bar", @klass.new.bar assert_equal "bar+baz", @klass.new.baz - assert_equal "baz", @klass.baz + assert_equal "bar's baz + baz", @klass.baz assert @klass.included_modules.include?(ConcernTest::Bar) end diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb index d00273a028..ef847fc557 100644 --- a/activesupport/test/configurable_test.rb +++ b/activesupport/test/configurable_test.rb @@ -95,6 +95,20 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase config_accessor "invalid attribute name" end end + + assert_raises NameError do + Class.new do + include ActiveSupport::Configurable + config_accessor "invalid\nattribute" + end + end + + assert_raises NameError do + Class.new do + include ActiveSupport::Configurable + config_accessor "invalid\n" + end + end end def assert_method_defined(object, method) diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index bbeb710a0c..366e4e5ef0 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,3 +1,5 @@ +require 'dependencies_test_helpers' + module Ace module Base class Case @@ -23,17 +25,30 @@ class Object end module ConstantizeTestCases + include DependenciesTestHelpers + def run_constantize_tests_on assert_equal Ace::Base::Case, yield("Ace::Base::Case") assert_equal Ace::Base::Case, yield("::Ace::Base::Case") assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") + assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Fase::Dice") assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") + assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") assert_equal Ace::Gas::Case::Dice, yield("Ace::Gas::Case::Dice") + assert_equal Ace::Base::Case::Dice, yield("Ace::Gas::Case::Dice") + assert_equal Case::Dice, yield("Case::Dice") + assert_equal AddtlGlobalConstants::Case::Dice, yield("Case::Dice") + assert_equal Object::AddtlGlobalConstants::Case::Dice, yield("Case::Dice") + assert_equal Case::Dice, yield("Object::Case::Dice") + assert_equal AddtlGlobalConstants::Case::Dice, yield("Object::Case::Dice") + assert_equal Object::AddtlGlobalConstants::Case::Dice, yield("Case::Dice") + assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") + assert_raises(NameError) { yield("UnknownClass") } assert_raises(NameError) { yield("UnknownClass::Ace") } assert_raises(NameError) { yield("UnknownClass::Ace::Base") } @@ -45,6 +60,19 @@ module ConstantizeTestCases assert_raises(NameError) { yield("Ace::Gas::ConstantizeTestCases") } assert_raises(NameError) { yield("") } assert_raises(NameError) { yield("::") } + assert_raises(NameError) { yield("Ace::gas") } + + assert_raises(NameError) do + with_autoloading_fixtures do + yield("RaisesNameError") + end + end + + assert_raises(NoMethodError) do + with_autoloading_fixtures do + yield("RaisesNoMethodError") + end + end end def run_safe_constantize_tests_on @@ -71,5 +99,18 @@ module ConstantizeTestCases assert_nil yield("Ace::Gas::Base") assert_nil yield("Ace::Gas::ConstantizeTestCases") assert_nil yield("#<Class:0x7b8b718b>::Nested_1") + assert_nil yield("Ace::gas") + + assert_raises(NameError) do + with_autoloading_fixtures do + yield("RaisesNameError") + end + end + + assert_raises(NoMethodError) do + with_autoloading_fixtures do + yield("RaisesNoMethodError") + end + end end end diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb new file mode 100644 index 0000000000..f14f64421d --- /dev/null +++ b/activesupport/test/core_ext/array/access_test.rb @@ -0,0 +1,30 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' + +class AccessTest < ActiveSupport::TestCase + def test_from + assert_equal %w( a b c d ), %w( a b c d ).from(0) + assert_equal %w( c d ), %w( a b c d ).from(2) + assert_equal %w(), %w( a b c d ).from(10) + assert_equal %w( d e ), %w( a b c d e ).from(-2) + assert_equal %w(), %w( a b c d e ).from(-10) + end + + def test_to + assert_equal %w( a ), %w( a b c d ).to(0) + assert_equal %w( a b c ), %w( a b c d ).to(2) + assert_equal %w( a b c d ), %w( a b c d ).to(10) + assert_equal %w( a b c ), %w( a b c d ).to(-2) + assert_equal %w(), %w( a b c ).to(-10) + end + + def test_specific_accessor + array = (1..42).to_a + + assert_equal array[1], array.second + assert_equal array[2], array.third + assert_equal array[3], array.fourth + assert_equal array[4], array.fifth + assert_equal array[41], array.forty_two + end +end diff --git a/activesupport/test/core_ext/array/conversions_test.rb b/activesupport/test/core_ext/array/conversions_test.rb new file mode 100644 index 0000000000..577b889410 --- /dev/null +++ b/activesupport/test/core_ext/array/conversions_test.rb @@ -0,0 +1,197 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' +require 'active_support/core_ext/big_decimal' +require 'active_support/core_ext/hash' +require 'active_support/core_ext/string' + +class ToSentenceTest < ActiveSupport::TestCase + def test_plain_array_to_sentence + assert_equal "", [].to_sentence + assert_equal "one", ['one'].to_sentence + assert_equal "one and two", ['one', 'two'].to_sentence + assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence + end + + def test_to_sentence_with_words_connector + assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' ') + assert_equal "one & two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' & ') + assert_equal "onetwo, and three", ['one', 'two', 'three'].to_sentence(words_connector: nil) + end + + def test_to_sentence_with_last_word_connector + assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(last_word_connector: ', and also ') + assert_equal "one, twothree", ['one', 'two', 'three'].to_sentence(last_word_connector: nil) + assert_equal "one, two three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' ') + assert_equal "one, two and three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' and ') + end + + def test_two_elements + assert_equal "one and two", ['one', 'two'].to_sentence + assert_equal "one two", ['one', 'two'].to_sentence(two_words_connector: ' ') + end + + def test_one_element + assert_equal "one", ['one'].to_sentence + end + + def test_one_element_not_same_object + elements = ["one"] + assert_not_equal elements[0].object_id, elements.to_sentence.object_id + end + + def test_one_non_string_element + assert_equal '1', [1].to_sentence + end + + def test_does_not_modify_given_hash + options = { words_connector: ' ' } + assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(options) + assert_equal({ words_connector: ' ' }, options) + end + + def test_with_blank_elements + assert_equal ", one, , two, and three", [nil, 'one', '', 'two', 'three'].to_sentence + end + + def test_with_invalid_options + exception = assert_raise ArgumentError do + ['one', 'two'].to_sentence(passing: 'invalid option') + end + + assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale" + end +end + +class ToSTest < ActiveSupport::TestCase + class TestDB + @@counter = 0 + def id + @@counter += 1 + end + end + + def test_to_s_db + collection = [TestDB.new, TestDB.new, TestDB.new] + + assert_equal "null", [].to_s(:db) + assert_equal "1,2,3", collection.to_s(:db) + end +end + +class ToXmlTest < ActiveSupport::TestCase + def test_to_xml_with_hash_elements + xml = [ + { name: "David", age: 26, age_in_millis: 820497600000 }, + { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + ].to_xml(skip_instruct: true, indent: 0) + + assert_equal '<objects type="array"><object>', xml.first(30) + assert xml.include?(%(<age type="integer">26</age>)), xml + assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml + assert xml.include?(%(<name>David</name>)), xml + assert xml.include?(%(<age type="integer">31</age>)), xml + assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml + assert xml.include?(%(<name>Jason</name>)), xml + end + + def test_to_xml_with_non_hash_elements + xml = [1, 2, 3].to_xml(skip_instruct: true, indent: 0) + + assert_equal '<fixnums type="array"><fixnum', xml.first(29) + assert xml.include?(%(<fixnum type="integer">2</fixnum>)), xml + end + + def test_to_xml_with_non_hash_different_type_elements + xml = [1, 2.0, '3'].to_xml(skip_instruct: true, indent: 0) + + assert_equal '<objects type="array"><object', xml.first(29) + assert xml.include?(%(<object type="integer">1</object>)), xml + assert xml.include?(%(<object type="float">2.0</object>)), xml + assert xml.include?(%(object>3</object>)), xml + end + + def test_to_xml_with_dedicated_name + xml = [ + { name: "David", age: 26, age_in_millis: 820497600000 }, { name: "Jason", age: 31 } + ].to_xml(skip_instruct: true, indent: 0, root: "people") + + assert_equal '<people type="array"><person>', xml.first(29) + end + + def test_to_xml_with_options + xml = [ + { name: "David", street_address: "Paulina" }, { name: "Jason", street_address: "Evergreen" } + ].to_xml(skip_instruct: true, skip_types: true, indent: 0) + + assert_equal "<objects><object>", xml.first(17) + assert xml.include?(%(<street-address>Paulina</street-address>)) + assert xml.include?(%(<name>David</name>)) + assert xml.include?(%(<street-address>Evergreen</street-address>)) + assert xml.include?(%(<name>Jason</name>)) + end + + def test_to_xml_with_indent_set + xml = [ + { name: "David", street_address: "Paulina" }, { name: "Jason", street_address: "Evergreen" } + ].to_xml(skip_instruct: true, skip_types: true, indent: 4) + + assert_equal "<objects>\n <object>", xml.first(22) + assert xml.include?(%(\n <street-address>Paulina</street-address>)) + assert xml.include?(%(\n <name>David</name>)) + assert xml.include?(%(\n <street-address>Evergreen</street-address>)) + assert xml.include?(%(\n <name>Jason</name>)) + end + + def test_to_xml_with_dasherize_false + xml = [ + { name: "David", street_address: "Paulina" }, { name: "Jason", street_address: "Evergreen" } + ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: false) + + assert_equal "<objects><object>", xml.first(17) + assert xml.include?(%(<street_address>Paulina</street_address>)) + assert xml.include?(%(<street_address>Evergreen</street_address>)) + end + + def test_to_xml_with_dasherize_true + xml = [ + { name: "David", street_address: "Paulina" }, { name: "Jason", street_address: "Evergreen" } + ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: true) + + assert_equal "<objects><object>", xml.first(17) + assert xml.include?(%(<street-address>Paulina</street-address>)) + assert xml.include?(%(<street-address>Evergreen</street-address>)) + end + + def test_to_xml_with_instruct + xml = [ + { name: "David", age: 26, age_in_millis: 820497600000 }, + { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + ].to_xml(skip_instruct: false, indent: 0) + + assert_match(/^<\?xml [^>]*/, xml) + assert_equal 0, xml.rindex(/<\?xml /) + end + + def test_to_xml_with_block + xml = [ + { name: "David", age: 26, age_in_millis: 820497600000 }, + { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + ].to_xml(skip_instruct: true, indent: 0) do |builder| + builder.count 2 + end + + assert xml.include?(%(<count>2</count>)), xml + end + + def test_to_xml_with_empty + xml = [].to_xml + assert_match(/type="array"\/>/, xml) + end + + def test_to_xml_dups_options + options = { skip_instruct: true } + [].to_xml(options) + # :builder, etc, shouldn't be added to options + assert_equal({ skip_instruct: true }, options) + end +end diff --git a/activesupport/test/core_ext/array/extract_options_test.rb b/activesupport/test/core_ext/array/extract_options_test.rb new file mode 100644 index 0000000000..0481a507cf --- /dev/null +++ b/activesupport/test/core_ext/array/extract_options_test.rb @@ -0,0 +1,45 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' +require 'active_support/core_ext/hash' + +class ExtractOptionsTest < ActiveSupport::TestCase + class HashSubclass < Hash + end + + class ExtractableHashSubclass < Hash + def extractable_options? + true + end + end + + def test_extract_options + assert_equal({}, [].extract_options!) + assert_equal({}, [1].extract_options!) + assert_equal({ a: :b }, [{ a: :b }].extract_options!) + assert_equal({ a: :b }, [1, { a: :b }].extract_options!) + end + + def test_extract_options_doesnt_extract_hash_subclasses + hash = HashSubclass.new + hash[:foo] = 1 + array = [hash] + options = array.extract_options! + assert_equal({}, options) + assert_equal([hash], array) + end + + def test_extract_options_extracts_extractable_subclass + hash = ExtractableHashSubclass.new + hash[:foo] = 1 + array = [hash] + options = array.extract_options! + assert_equal({ foo: 1 }, options) + assert_equal([], array) + end + + def test_extract_options_extracts_hash_with_indifferent_access + array = [{ foo: 1 }.with_indifferent_access] + options = array.extract_options! + assert_equal(1, options[:foo]) + end +end diff --git a/activesupport/test/core_ext/array/grouping_test.rb b/activesupport/test/core_ext/array/grouping_test.rb new file mode 100644 index 0000000000..2eb0f05141 --- /dev/null +++ b/activesupport/test/core_ext/array/grouping_test.rb @@ -0,0 +1,126 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' + +class GroupingTest < ActiveSupport::TestCase + def setup + Fixnum.send :private, :/ # test we avoid Integer#/ (redefined by mathn) + end + + def teardown + Fixnum.send :public, :/ + end + + def test_in_groups_of_with_perfect_fit + groups = [] + ('a'..'i').to_a.in_groups_of(3) do |group| + groups << group + end + + assert_equal [%w(a b c), %w(d e f), %w(g h i)], groups + assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3) + end + + def test_in_groups_of_with_padding + groups = [] + ('a'..'g').to_a.in_groups_of(3) do |group| + groups << group + end + + assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups + end + + def test_in_groups_of_pads_with_specified_values + groups = [] + + ('a'..'g').to_a.in_groups_of(3, 'foo') do |group| + groups << group + end + + assert_equal [%w(a b c), %w(d e f), %w(g foo foo)], groups + end + + def test_in_groups_of_without_padding + groups = [] + + ('a'..'g').to_a.in_groups_of(3, false) do |group| + groups << group + end + + assert_equal [%w(a b c), %w(d e f), %w(g)], groups + end + + def test_in_groups_returned_array_size + array = (1..7).to_a + + 1.upto(array.size + 1) do |number| + assert_equal number, array.in_groups(number).size + end + end + + def test_in_groups_with_empty_array + assert_equal [[], [], []], [].in_groups(3) + end + + def test_in_groups_with_block + array = (1..9).to_a + groups = [] + + array.in_groups(3) do |group| + groups << group + end + + assert_equal array.in_groups(3), groups + end + + def test_in_groups_with_perfect_fit + assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + (1..9).to_a.in_groups(3) + end + + def test_in_groups_with_padding + array = (1..7).to_a + + assert_equal [[1, 2, 3], [4, 5, nil], [6, 7, nil]], + array.in_groups(3) + assert_equal [[1, 2, 3], [4, 5, 'foo'], [6, 7, 'foo']], + array.in_groups(3, 'foo') + end + + def test_in_groups_without_padding + assert_equal [[1, 2, 3], [4, 5], [6, 7]], + (1..7).to_a.in_groups(3, false) + end + + def test_in_groups_invalid_argument + assert_raises(ArgumentError) { [].in_groups_of(0) } + assert_raises(ArgumentError) { [].in_groups_of(-1) } + assert_raises(ArgumentError) { [].in_groups_of(nil) } + end +end + +class SplitTest < ActiveSupport::TestCase + def test_split_with_empty_array + assert_equal [[]], [].split(0) + end + + def test_split_with_argument + a = [1, 2, 3, 4, 5] + assert_equal [[1, 2], [4, 5]], a.split(3) + assert_equal [[1, 2, 3, 4, 5]], a.split(0) + assert_equal [1, 2, 3, 4, 5], a + end + + def test_split_with_block + a = (1..10).to_a + assert_equal [[1, 2], [4, 5], [7, 8], [10]], a.split { |i| i % 3 == 0 } + assert_equal [1, 2, 3, 4, 5, 6, 7, 8, 9 ,10], a + end + + def test_split_with_edge_values + a = [1, 2, 3, 4, 5] + assert_equal [[], [2, 3, 4, 5]], a.split(1) + assert_equal [[1, 2, 3, 4], []], a.split(5) + assert_equal [[], [2, 3, 4], []], a.split { |i| i == 1 || i == 5 } + assert_equal [1, 2, 3, 4, 5], a + end +end diff --git a/activesupport/test/core_ext/array/prepend_append_test.rb b/activesupport/test/core_ext/array/prepend_append_test.rb new file mode 100644 index 0000000000..762aa69b2b --- /dev/null +++ b/activesupport/test/core_ext/array/prepend_append_test.rb @@ -0,0 +1,12 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' + +class PrependAppendTest < ActiveSupport::TestCase + def test_append + assert_equal [1, 2], [1].append(2) + end + + def test_prepend + assert_equal [2, 1], [1].prepend(2) + end +end diff --git a/activesupport/test/core_ext/array/wrap_test.rb b/activesupport/test/core_ext/array/wrap_test.rb new file mode 100644 index 0000000000..baf426506f --- /dev/null +++ b/activesupport/test/core_ext/array/wrap_test.rb @@ -0,0 +1,77 @@ +require 'abstract_unit' +require 'active_support/core_ext/array' + +class WrapTest < ActiveSupport::TestCase + class FakeCollection + def to_ary + ["foo", "bar"] + end + end + + class Proxy + def initialize(target) @target = target end + def method_missing(*a) @target.send(*a) end + end + + class DoubtfulToAry + def to_ary + :not_an_array + end + end + + class NilToAry + def to_ary + nil + end + end + + def test_array + ary = %w(foo bar) + assert_same ary, Array.wrap(ary) + end + + def test_nil + assert_equal [], Array.wrap(nil) + end + + def test_object + o = Object.new + assert_equal [o], Array.wrap(o) + end + + def test_string + assert_equal ["foo"], Array.wrap("foo") + end + + def test_string_with_newline + assert_equal ["foo\nbar"], Array.wrap("foo\nbar") + end + + def test_object_with_to_ary + assert_equal ["foo", "bar"], Array.wrap(FakeCollection.new) + end + + def test_proxy_object + p = Proxy.new(Object.new) + assert_equal [p], Array.wrap(p) + end + + def test_proxy_to_object_with_to_ary + p = Proxy.new(FakeCollection.new) + assert_equal [p], Array.wrap(p) + end + + def test_struct + o = Struct.new(:foo).new(123) + assert_equal [o], Array.wrap(o) + end + + def test_wrap_returns_wrapped_if_to_ary_returns_nil + o = NilToAry.new + assert_equal [o], Array.wrap(o) + end + + def test_wrap_does_not_complain_if_to_ary_does_not_return_an_array + assert_equal DoubtfulToAry.new.to_ary, Array.wrap(DoubtfulToAry.new) + end +end diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb deleted file mode 100644 index 384064d81f..0000000000 --- a/activesupport/test/core_ext/array_ext_test.rb +++ /dev/null @@ -1,475 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/big_decimal' -require 'active_support/core_ext/object/conversions' - -require 'active_support/core_ext' # FIXME: pulling in all to_xml extensions -require 'active_support/hash_with_indifferent_access' - -class ArrayExtAccessTests < ActiveSupport::TestCase - def test_from - assert_equal %w( a b c d ), %w( a b c d ).from(0) - assert_equal %w( c d ), %w( a b c d ).from(2) - assert_equal %w(), %w( a b c d ).from(10) - end - - def test_to - assert_equal %w( a ), %w( a b c d ).to(0) - assert_equal %w( a b c ), %w( a b c d ).to(2) - assert_equal %w( a b c d ), %w( a b c d ).to(10) - end - - def test_second_through_tenth - array = (1..42).to_a - - assert_equal array[1], array.second - assert_equal array[2], array.third - assert_equal array[3], array.fourth - assert_equal array[4], array.fifth - assert_equal array[41], array.forty_two - end -end - -class ArrayExtToParamTests < ActiveSupport::TestCase - class ToParam < String - def to_param - "#{self}1" - end - end - - def test_string_array - assert_equal '', %w().to_param - assert_equal 'hello/world', %w(hello world).to_param - assert_equal 'hello/10', %w(hello 10).to_param - end - - def test_number_array - assert_equal '10/20', [10, 20].to_param - end - - def test_to_param_array - assert_equal 'custom1/param1', [ToParam.new('custom'), ToParam.new('param')].to_param - end -end - -class ArrayExtToSentenceTests < ActiveSupport::TestCase - def test_plain_array_to_sentence - assert_equal "", [].to_sentence - assert_equal "one", ['one'].to_sentence - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence - end - - def test_to_sentence_with_words_connector - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(:words_connector => ' ') - assert_equal "one & two, and three", ['one', 'two', 'three'].to_sentence(:words_connector => ' & ') - assert_equal "onetwo, and three", ['one', 'two', 'three'].to_sentence(:words_connector => nil) - end - - def test_to_sentence_with_last_word_connector - assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(:last_word_connector => ', and also ') - assert_equal "one, twothree", ['one', 'two', 'three'].to_sentence(:last_word_connector => nil) - assert_equal "one, two three", ['one', 'two', 'three'].to_sentence(:last_word_connector => ' ') - assert_equal "one, two and three", ['one', 'two', 'three'].to_sentence(:last_word_connector => ' and ') - end - - def test_two_elements - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one two", ['one', 'two'].to_sentence(:two_words_connector => ' ') - end - - def test_one_element - assert_equal "one", ['one'].to_sentence - end - - def test_one_element_not_same_object - elements = ["one"] - assert_not_equal elements[0].object_id, elements.to_sentence.object_id - end - - def test_one_non_string_element - assert_equal '1', [1].to_sentence - end - - def test_does_not_modify_given_hash - options = { words_connector: ' ' } - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(options) - assert_equal({ words_connector: ' ' }, options) - end - - def test_with_blank_elements - assert_equal ", one, , two, and three", [nil, 'one', '', 'two', 'three'].to_sentence - end -end - -class ArrayExtToSTests < ActiveSupport::TestCase - def test_to_s_db - collection = [ - Class.new { def id() 1 end }.new, - Class.new { def id() 2 end }.new, - Class.new { def id() 3 end }.new - ] - - assert_equal "null", [].to_s(:db) - assert_equal "1,2,3", collection.to_s(:db) - end -end - -class ArrayExtGroupingTests < ActiveSupport::TestCase - def setup - Fixnum.send :private, :/ # test we avoid Integer#/ (redefined by mathn) - end - - def teardown - Fixnum.send :public, :/ - end - - def test_in_groups_of_with_perfect_fit - groups = [] - ('a'..'i').to_a.in_groups_of(3) do |group| - groups << group - end - - assert_equal [%w(a b c), %w(d e f), %w(g h i)], groups - assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3) - end - - def test_in_groups_of_with_padding - groups = [] - ('a'..'g').to_a.in_groups_of(3) do |group| - groups << group - end - - assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups - end - - def test_in_groups_of_pads_with_specified_values - groups = [] - - ('a'..'g').to_a.in_groups_of(3, 'foo') do |group| - groups << group - end - - assert_equal [%w(a b c), %w(d e f), ['g', 'foo', 'foo']], groups - end - - def test_in_groups_of_without_padding - groups = [] - - ('a'..'g').to_a.in_groups_of(3, false) do |group| - groups << group - end - - assert_equal [%w(a b c), %w(d e f), ['g']], groups - end - - def test_in_groups_returned_array_size - array = (1..7).to_a - - 1.upto(array.size + 1) do |number| - assert_equal number, array.in_groups(number).size - end - end - - def test_in_groups_with_empty_array - assert_equal [[], [], []], [].in_groups(3) - end - - def test_in_groups_with_block - array = (1..9).to_a - groups = [] - - array.in_groups(3) do |group| - groups << group - end - - assert_equal array.in_groups(3), groups - end - - def test_in_groups_with_perfect_fit - assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - (1..9).to_a.in_groups(3) - end - - def test_in_groups_with_padding - array = (1..7).to_a - - assert_equal [[1, 2, 3], [4, 5, nil], [6, 7, nil]], - array.in_groups(3) - assert_equal [[1, 2, 3], [4, 5, 'foo'], [6, 7, 'foo']], - array.in_groups(3, 'foo') - end - - def test_in_groups_without_padding - assert_equal [[1, 2, 3], [4, 5], [6, 7]], - (1..7).to_a.in_groups(3, false) - end -end - -class ArraySplitTests < ActiveSupport::TestCase - def test_split_with_empty_array - assert_equal [[]], [].split(0) - end - - def test_split_with_argument - assert_equal [[1, 2], [4, 5]], [1, 2, 3, 4, 5].split(3) - assert_equal [[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5].split(0) - end - - def test_split_with_block - assert_equal [[1, 2], [4, 5], [7, 8], [10]], (1..10).to_a.split { |i| i % 3 == 0 } - end - - def test_split_with_edge_values - assert_equal [[], [2, 3, 4, 5]], [1, 2, 3, 4, 5].split(1) - assert_equal [[1, 2, 3, 4], []], [1, 2, 3, 4, 5].split(5) - assert_equal [[], [2, 3, 4], []], [1, 2, 3, 4, 5].split { |i| i == 1 || i == 5 } - end -end - -class ArrayToXmlTests < ActiveSupport::TestCase - def test_to_xml - xml = [ - { :name => "David", :age => 26, :age_in_millis => 820497600000 }, - { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') } - ].to_xml(:skip_instruct => true, :indent => 0) - - assert_equal '<objects type="array"><object>', xml.first(30) - assert xml.include?(%(<age type="integer">26</age>)), xml - assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml - assert xml.include?(%(<name>David</name>)), xml - assert xml.include?(%(<age type="integer">31</age>)), xml - assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml - assert xml.include?(%(<name>Jason</name>)), xml - end - - def test_to_xml_with_dedicated_name - xml = [ - { :name => "David", :age => 26, :age_in_millis => 820497600000 }, { :name => "Jason", :age => 31 } - ].to_xml(:skip_instruct => true, :indent => 0, :root => "people") - - assert_equal '<people type="array"><person>', xml.first(29) - end - - def test_to_xml_with_options - xml = [ - { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" } - ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0) - - assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) - assert xml.include?(%(<name>Jason</name>)) - end - - def test_to_xml_with_dasherize_false - xml = [ - { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" } - ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0, :dasherize => false) - - assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street_address>Paulina</street_address>)) - assert xml.include?(%(<street_address>Evergreen</street_address>)) - end - - def test_to_xml_with_dasherize_true - xml = [ - { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" } - ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0, :dasherize => true) - - assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) - end - - def test_to_with_instruct - xml = [ - { :name => "David", :age => 26, :age_in_millis => 820497600000 }, - { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') } - ].to_xml(:skip_instruct => false, :indent => 0) - - assert_match(/^<\?xml [^>]*/, xml) - assert_equal 0, xml.rindex(/<\?xml /) - end - - def test_to_xml_with_block - xml = [ - { :name => "David", :age => 26, :age_in_millis => 820497600000 }, - { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') } - ].to_xml(:skip_instruct => true, :indent => 0) do |builder| - builder.count 2 - end - - assert xml.include?(%(<count>2</count>)), xml - end - - def test_to_xml_with_empty - xml = [].to_xml - assert_match(/type="array"\/>/, xml) - end - - def test_to_xml_dups_options - options = {:skip_instruct => true} - [].to_xml(options) - # :builder, etc, shouldn't be added to options - assert_equal({:skip_instruct => true}, options) - end -end - -class ArrayExtractOptionsTests < ActiveSupport::TestCase - class HashSubclass < Hash - end - - class ExtractableHashSubclass < Hash - def extractable_options? - true - end - end - - def test_extract_options - assert_equal({}, [].extract_options!) - assert_equal({}, [1].extract_options!) - assert_equal({:a=>:b}, [{:a=>:b}].extract_options!) - assert_equal({:a=>:b}, [1, {:a=>:b}].extract_options!) - end - - def test_extract_options_doesnt_extract_hash_subclasses - hash = HashSubclass.new - hash[:foo] = 1 - array = [hash] - options = array.extract_options! - assert_equal({}, options) - assert_equal [hash], array - end - - def test_extract_options_extracts_extractable_subclass - hash = ExtractableHashSubclass.new - hash[:foo] = 1 - array = [hash] - options = array.extract_options! - assert_equal({:foo => 1}, options) - assert_equal [], array - end - - def test_extract_options_extracts_hwia - hash = [{:foo => 1}.with_indifferent_access] - options = hash.extract_options! - assert_equal 1, options[:foo] - end -end - -class ArrayUniqByTests < ActiveSupport::TestCase - def test_uniq_by - ActiveSupport::Deprecation.silence do - assert_equal [1,2], [1,2,3,4].uniq_by { |i| i.odd? } - assert_equal [1,2], [1,2,3,4].uniq_by(&:even?) - assert_equal((-5..0).to_a, (-5..5).to_a.uniq_by{ |i| i**2 }) - end - end - - def test_uniq_by! - a = [1,2,3,4] - ActiveSupport::Deprecation.silence do - a.uniq_by! { |i| i.odd? } - end - assert_equal [1,2], a - - a = [1,2,3,4] - ActiveSupport::Deprecation.silence do - a.uniq_by! { |i| i.even? } - end - assert_equal [1,2], a - - a = (-5..5).to_a - ActiveSupport::Deprecation.silence do - a.uniq_by! { |i| i**2 } - end - assert_equal((-5..0).to_a, a) - end -end - -class ArrayWrapperTests < ActiveSupport::TestCase - class FakeCollection - def to_ary - ["foo", "bar"] - end - end - - class Proxy - def initialize(target) @target = target end - def method_missing(*a) @target.send(*a) end - end - - class DoubtfulToAry - def to_ary - :not_an_array - end - end - - class NilToAry - def to_ary - nil - end - end - - def test_array - ary = %w(foo bar) - assert_same ary, Array.wrap(ary) - end - - def test_nil - assert_equal [], Array.wrap(nil) - end - - def test_object - o = Object.new - assert_equal [o], Array.wrap(o) - end - - def test_string - assert_equal ["foo"], Array.wrap("foo") - end - - def test_string_with_newline - assert_equal ["foo\nbar"], Array.wrap("foo\nbar") - end - - def test_object_with_to_ary - assert_equal ["foo", "bar"], Array.wrap(FakeCollection.new) - end - - def test_proxy_object - p = Proxy.new(Object.new) - assert_equal [p], Array.wrap(p) - end - - def test_proxy_to_object_with_to_ary - p = Proxy.new(FakeCollection.new) - assert_equal [p], Array.wrap(p) - end - - def test_struct - o = Struct.new(:foo).new(123) - assert_equal [o], Array.wrap(o) - end - - def test_wrap_returns_wrapped_if_to_ary_returns_nil - o = NilToAry.new - assert_equal [o], Array.wrap(o) - end - - def test_wrap_does_not_complain_if_to_ary_does_not_return_an_array - assert_equal DoubtfulToAry.new.to_ary, Array.wrap(DoubtfulToAry.new) - end -end - -class ArrayPrependAppendTest < ActiveSupport::TestCase - def test_append - assert_equal [1, 2], [1].append(2) - end - - def test_prepend - assert_equal [2, 1], [1].prepend(2) - end -end diff --git a/activesupport/test/core_ext/big_decimal/yaml_conversions_test.rb b/activesupport/test/core_ext/big_decimal/yaml_conversions_test.rb new file mode 100644 index 0000000000..e634679d20 --- /dev/null +++ b/activesupport/test/core_ext/big_decimal/yaml_conversions_test.rb @@ -0,0 +1,11 @@ +require 'abstract_unit' + +class BigDecimalYamlConversionsTest < ActiveSupport::TestCase + def test_to_yaml + assert_deprecated { require 'active_support/core_ext/big_decimal/yaml_conversions' } + assert_match("--- 100000.30020320320000000000000000000000000000001\n", BigDecimal.new('100000.30020320320000000000000000000000000000001').to_yaml) + assert_match("--- .Inf\n", BigDecimal.new('Infinity').to_yaml) + assert_match("--- .NaN\n", BigDecimal.new('NaN').to_yaml) + assert_match("--- -.Inf\n", BigDecimal.new('-Infinity').to_yaml) + end +end diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb index a5987044b9..423a3f2e9d 100644 --- a/activesupport/test/core_ext/bigdecimal_test.rb +++ b/activesupport/test/core_ext/bigdecimal_test.rb @@ -1,20 +1,7 @@ require 'abstract_unit' -require 'bigdecimal' require 'active_support/core_ext/big_decimal' class BigDecimalTest < ActiveSupport::TestCase - def test_to_yaml - assert_match("--- 100000.30020320320000000000000000000000000000001\n", BigDecimal.new('100000.30020320320000000000000000000000000000001').to_yaml) - assert_match("--- .Inf\n", BigDecimal.new('Infinity').to_yaml) - assert_match("--- .NaN\n", BigDecimal.new('NaN').to_yaml) - assert_match("--- -.Inf\n", BigDecimal.new('-Infinity').to_yaml) - end - - def test_to_d - bd = BigDecimal.new '10' - assert_equal bd, bd.to_d - end - def test_to_s bd = BigDecimal.new '0.01' assert_equal '0.01', bd.to_s diff --git a/activesupport/test/core_ext/class/attribute_accessor_test.rb b/activesupport/test/core_ext/class/attribute_accessor_test.rb deleted file mode 100644 index 0d5f39a72b..0000000000 --- a/activesupport/test/core_ext/class/attribute_accessor_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/class/attribute_accessors' - -class ClassAttributeAccessorTest < ActiveSupport::TestCase - def setup - @class = Class.new do - cattr_accessor :foo - cattr_accessor :bar, :instance_writer => false - cattr_reader :shaq, :instance_reader => false - cattr_accessor :camp, :instance_accessor => false - end - @object = @class.new - end - - def test_should_use_mattr_default - assert_nil @class.foo - assert_nil @object.foo - end - - def test_should_set_mattr_value - @class.foo = :test - assert_equal :test, @object.foo - - @object.foo = :test2 - assert_equal :test2, @class.foo - end - - def test_should_not_create_instance_writer - assert_respond_to @class, :foo - assert_respond_to @class, :foo= - assert_respond_to @object, :bar - assert !@object.respond_to?(:bar=) - end - - def test_should_not_create_instance_reader - assert_respond_to @class, :shaq - assert !@object.respond_to?(:shaq) - end - - def test_should_not_create_instance_accessors - assert_respond_to @class, :camp - assert !@object.respond_to?(:camp) - assert !@object.respond_to?(:camp=) - end - - def test_should_raise_name_error_if_attribute_name_is_invalid - exception = assert_raises NameError do - Class.new do - cattr_reader "1nvalid" - end - end - assert_equal "invalid class attribute name: 1nvalid", exception.message - - exception = assert_raises NameError do - Class.new do - cattr_writer "1nvalid" - end - end - assert_equal "invalid class attribute name: 1nvalid", exception.message - end -end diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb index 148f82946c..447b1d10ad 100644 --- a/activesupport/test/core_ext/class/delegating_attributes_test.rb +++ b/activesupport/test/core_ext/class/delegating_attributes_test.rb @@ -6,14 +6,18 @@ module DelegatingFixtures end class Child < Parent - superclass_delegating_accessor :some_attribute + ActiveSupport::Deprecation.silence do + superclass_delegating_accessor :some_attribute + end end class Mokopuna < Child end class PercysMom - superclass_delegating_accessor :superpower + ActiveSupport::Deprecation.silence do + superclass_delegating_accessor :superpower + end end class Percy < PercysMom @@ -29,7 +33,10 @@ class DelegatingAttributesTest < ActiveSupport::TestCase end def test_simple_accessor_declaration - single_class.superclass_delegating_accessor :both + assert_deprecated do + single_class.superclass_delegating_accessor :both + end + # Class should have accessor and mutator # the instance should have an accessor only assert_respond_to single_class, :both @@ -39,14 +46,23 @@ class DelegatingAttributesTest < ActiveSupport::TestCase end def test_simple_accessor_declaration_with_instance_reader_false - single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false + _instance_methods = single_class.public_instance_methods + + assert_deprecated do + single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false + end + assert_respond_to single_class, :no_instance_reader assert_respond_to single_class, :no_instance_reader= - assert !single_class.public_instance_methods.map(&:to_s).include?("no_instance_reader") + assert !_instance_methods.include?(:no_instance_reader) + assert !_instance_methods.include?(:no_instance_reader?) + assert !_instance_methods.include?(:_no_instance_reader) end def test_working_with_simple_attributes - single_class.superclass_delegating_accessor :both + assert_deprecated do + single_class.superclass_delegating_accessor :both + end single_class.both = "HMMM" @@ -62,7 +78,11 @@ class DelegatingAttributesTest < ActiveSupport::TestCase def test_child_class_delegates_to_parent_but_can_be_overridden parent = Class.new - parent.superclass_delegating_accessor :both + + assert_deprecated do + parent.superclass_delegating_accessor :both + end + child = Class.new(parent) parent.both = "1" assert_equal "1", child.both @@ -94,4 +114,9 @@ class DelegatingAttributesTest < ActiveSupport::TestCase Child.some_attribute=nil end + def test_deprecation_warning + assert_deprecated(/superclass_delegating_accessor is deprecated/) do + single_class.superclass_delegating_accessor :test_attribute + end + end end diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index aa5e4461fd..e89be25b53 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'active_support/time' require 'core_ext/date_and_time_behavior' +require 'time_zone_test_helpers' class DateExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,*args) @@ -8,6 +9,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end include DateAndTimeBehavior + include TimeZoneTestHelpers def test_yesterday_in_calendar_reform assert_equal Date.new(1582,10,4), Date.new(1582,10,15).yesterday @@ -25,6 +27,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal "February 21st, 2005", date.to_s(:long_ordinal) assert_equal "2005-02-21", date.to_s(:db) assert_equal "21 Feb 2005", date.to_s(:rfc822) + assert_equal "2005-02-21", date.to_s(:iso8601) end def test_readable_inspect @@ -247,6 +250,10 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.local(2005,2,21,0,0,0), Date.new(2005,2,21).beginning_of_day end + def test_middle_of_day + assert_equal Time.local(2005,2,21,12,0,0), Date.new(2005,2,21).middle_of_day + end + def test_beginning_of_day_when_zone_is_set zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] with_env_tz 'UTC' do @@ -271,6 +278,23 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end end + def test_all_week + assert_equal Date.new(2011,6,6)..Date.new(2011,6,12), Date.new(2011,6,7).all_week + assert_equal Date.new(2011,6,5)..Date.new(2011,6,11), Date.new(2011,6,7).all_week(:sunday) + end + + def test_all_month + assert_equal Date.new(2011,6,1)..Date.new(2011,6,30), Date.new(2011,6,7).all_month + end + + def test_all_quarter + assert_equal Date.new(2011,4,1)..Date.new(2011,6,30), Date.new(2011,6,7).all_quarter + end + + def test_all_year + assert_equal Date.new(2011,1,1)..Date.new(2011,12,31), Date.new(2011,6,7).all_year + end + def test_xmlschema with_env_tz 'US/Eastern' do assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema) @@ -327,22 +351,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase Date.new(2005,2,28).advance(options) assert_equal({ :years => 3, :months => 11, :days => 2 }, options) end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end - - def with_tz_default(tz = nil) - old_tz = Time.zone - Time.zone = tz - yield - ensure - Time.zone = old_tz - end end class DateExtBehaviorTest < ActiveSupport::TestCase @@ -363,10 +371,3 @@ class DateExtBehaviorTest < ActiveSupport::TestCase end end -class DateExtConversionsTest < ActiveSupport::TestCase - def test_to_time_in_current_zone_is_deprecated - assert_deprecated(/to_time_in_current_zone/) do - Date.new(2012,6,7).to_time_in_current_zone - end - end -end diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 571344b728..74319ecd09 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'active_support/time' require 'core_ext/date_and_time_behavior' +require 'time_zone_test_helpers' class DateTimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,*args) @@ -8,6 +9,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end include DateAndTimeBehavior + include TimeZoneTestHelpers def test_to_s datetime = DateTime.new(2005, 2, 21, 14, 30, 0, 0) @@ -18,6 +20,12 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal "Mon, 21 Feb 2005 14:30:00 +0000", datetime.to_s(:rfc822) assert_equal "February 21st, 2005 14:30", datetime.to_s(:long_ordinal) assert_match(/^2005-02-21T14:30:00(Z|\+00:00)$/, datetime.to_s) + + with_env_tz "US/Central" do + assert_equal "2009-02-05T14:30:05-06:00", DateTime.civil(2009, 2, 5, 14, 30, 5, Rational(-21600, 86400)).to_s(:iso8601) + assert_equal "2008-06-09T04:05:01-05:00", DateTime.civil(2008, 6, 9, 4, 5, 1, Rational(-18000, 86400)).to_s(:iso8601) + assert_equal "2009-02-05T14:30:05+00:00", DateTime.civil(2009, 2, 5, 14, 30, 5).to_s(:iso8601) + end end def test_readable_inspect @@ -76,6 +84,10 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2005,2,4,0,0,0), DateTime.civil(2005,2,4,10,10,10).beginning_of_day end + def test_middle_of_day + assert_equal DateTime.civil(2005,2,4,12,0,0), DateTime.civil(2005,2,4,10,10,10).middle_of_day + end + def test_end_of_day assert_equal DateTime.civil(2005,2,4,23,59,59), DateTime.civil(2005,2,4,10,10,10).end_of_day end @@ -152,6 +164,12 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) end + def test_advance_partial_days + assert_equal DateTime.civil(2012,9,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5) + assert_equal DateTime.civil(2012,9,28,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 0.5) + assert_equal DateTime.civil(2012,10,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5, :months => 1) + end + def test_advanced_processes_first_the_date_deltas_and_then_the_time_deltas # If the time deltas were processed first, the following datetimes would be advanced to 2010/04/01 instead. assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59, 59).advance(:months => 1, :seconds => 1) @@ -320,6 +338,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase def test_to_f assert_equal 946684800.0, DateTime.civil(2000).to_f assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f + assert_equal 946684800.5, DateTime.civil(1999,12,31,19,0,0.5,Rational(-5,24)).to_f end def test_to_i @@ -336,12 +355,4 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal 0, DateTime.civil(2000).nsec assert_equal 500000000, DateTime.civil(2000, 1, 1, 0, 0, Rational(1,2)).nsec end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end end diff --git a/activesupport/test/core_ext/digest/uuid_test.rb b/activesupport/test/core_ext/digest/uuid_test.rb new file mode 100644 index 0000000000..08e0a1d6e1 --- /dev/null +++ b/activesupport/test/core_ext/digest/uuid_test.rb @@ -0,0 +1,24 @@ +require 'abstract_unit' +require 'active_support/core_ext/digest/uuid' + +class DigestUUIDExt < ActiveSupport::TestCase + def test_v3_uuids + assert_equal "3d813cbb-47fb-32ba-91df-831e1593ac29", Digest::UUID.uuid_v3(Digest::UUID::DNS_NAMESPACE, "www.widgets.com") + assert_equal "86df55fb-428e-3843-8583-ba3c05f290bc", Digest::UUID.uuid_v3(Digest::UUID::URL_NAMESPACE, "http://www.widgets.com") + assert_equal "8c29ab0e-a2dc-3482-b5eb-20cb2e2387a1", Digest::UUID.uuid_v3(Digest::UUID::OID_NAMESPACE, "1.2.3") + assert_equal "ee49149d-53a4-304a-890b-468229f6afc3", Digest::UUID.uuid_v3(Digest::UUID::X500_NAMESPACE, "cn=John Doe, ou=People, o=Acme, Inc., c=US") + end + + def test_v5_uuids + assert_equal "21f7f8de-8051-5b89-8680-0195ef798b6a", Digest::UUID.uuid_v5(Digest::UUID::DNS_NAMESPACE, "www.widgets.com") + assert_equal "4e570fd8-186d-5a74-90f0-4d28e34673a1", Digest::UUID.uuid_v5(Digest::UUID::URL_NAMESPACE, "http://www.widgets.com") + assert_equal "42d5e23b-3a02-5135-85c6-52d1102f1f00", Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, "1.2.3") + assert_equal "fd5b2ddf-bcfe-58b6-90d6-db50f74db527", Digest::UUID.uuid_v5(Digest::UUID::X500_NAMESPACE, "cn=John Doe, ou=People, o=Acme, Inc., c=US") + end + + def test_invalid_hash_class + assert_raise ArgumentError do + Digest::UUID.uuid_from_hash(Digest::SHA2, Digest::UUID::OID_NAMESPACE, '1.2.3') + end + end +end diff --git a/activesupport/test/core_ext/duplicable_test.rb b/activesupport/test/core_ext/duplicable_test.rb deleted file mode 100644 index e0566e012c..0000000000 --- a/activesupport/test/core_ext/duplicable_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'abstract_unit' -require 'bigdecimal' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/numeric/time' - -class DuplicableTest < ActiveSupport::TestCase - RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds] - YES = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] - NO = [] - - begin - bd = BigDecimal.new('4.56') - YES << bd.dup - rescue TypeError - RAISE_DUP << bd - end - - - def test_duplicable - (RAISE_DUP + NO).each do |v| - assert !v.duplicable? - end - - YES.each do |v| - assert v.duplicable?, "#{v.class} should be duplicable" - end - - (YES + NO).each do |v| - assert_nothing_raised { v.dup } - end - - RAISE_DUP.each do |v| - assert_raises(TypeError, v.class.name) do - v.dup - end - end - end -end diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 5e3987265b..a89202f518 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -2,8 +2,11 @@ require 'abstract_unit' require 'active_support/inflector' require 'active_support/time' require 'active_support/json' +require 'time_zone_test_helpers' class DurationTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + def test_is_a d = 1.day assert d.is_a?(ActiveSupport::Duration) @@ -17,6 +20,12 @@ class DurationTest < ActiveSupport::TestCase assert !d.is_a?(k) end + def test_instance_of + assert 1.minute.instance_of?(Fixnum) + assert 2.days.instance_of?(ActiveSupport::Duration) + assert !3.second.instance_of?(Numeric) + end + def test_threequals assert ActiveSupport::Duration === 1.day assert !(ActiveSupport::Duration === 1.day.to_i) @@ -27,9 +36,20 @@ class DurationTest < ActiveSupport::TestCase def test_equals assert 1.day == 1.day assert 1.day == 1.day.to_i + assert 1.day.to_i == 1.day assert !(1.day == 'foo') end + def test_eql + rubinius_skip "Rubinius' #eql? definition relies on #instance_of? " \ + "which behaves oddly for the sake of backward-compatibility." + + assert 1.minute.eql?(1.minute) + assert 2.days.eql?(48.hours) + assert !1.second.eql?(1) + assert !1.eql?(1.second) + end + def test_inspect assert_equal '0 seconds', 0.seconds.inspect assert_equal '1 month', 1.month.inspect @@ -37,6 +57,8 @@ class DurationTest < ActiveSupport::TestCase assert_equal '6 months and -2 days', (6.months - 2.days).inspect assert_equal '10 seconds', 10.seconds.inspect assert_equal '10 years, 2 months, and 1 day', (10.years + 2.months + 1.day).inspect + assert_equal '10 years, 2 months, and 1 day', (10.years + 1.month + 1.day + 1.month).inspect + assert_equal '10 years, 2 months, and 1 day', (1.day + 10.years + 2.months).inspect assert_equal '7 days', 1.week.inspect assert_equal '14 days', 1.fortnight.inspect end @@ -50,12 +72,10 @@ class DurationTest < ActiveSupport::TestCase end def test_argument_error - 1.second.ago('') - flunk("no exception was raised") - rescue ArgumentError => e + e = assert_raise ArgumentError do + 1.second.ago('') + end assert_equal 'expected a time or date, got ""', e.message, "ensure ArgumentError is not being raised by dependencies.rb" - rescue Exception => e - flunk("ArgumentError should be raised, but we got #{e.class} instead") end def test_fractional_weeks @@ -68,6 +88,19 @@ class DurationTest < ActiveSupport::TestCase assert_equal 86400 * 1.7, 1.7.days end + def test_since_and_ago + t = Time.local(2000) + assert t + 1, 1.second.since(t) + assert t - 1, 1.second.ago(t) + end + + def test_since_and_ago_without_argument + now = Time.now + assert 1.second.since >= now + 1 + now = Time.now + assert 1.second.ago >= now - 1 + end + def test_since_and_ago_with_fractional_days t = Time.local(2000) # since @@ -93,10 +126,10 @@ class DurationTest < ActiveSupport::TestCase with_env_tz 'US/Eastern' do Time.stubs(:now).returns Time.local(2000) # since - assert_equal false, 5.seconds.since.is_a?(ActiveSupport::TimeWithZone) + assert_not_instance_of ActiveSupport::TimeWithZone, 5.seconds.since assert_equal Time.local(2000,1,1,0,0,5), 5.seconds.since # ago - assert_equal false, 5.seconds.ago.is_a?(ActiveSupport::TimeWithZone) + assert_not_instance_of ActiveSupport::TimeWithZone, 5.seconds.ago assert_equal Time.local(1999,12,31,23,59,55), 5.seconds.ago end end @@ -106,11 +139,11 @@ class DurationTest < ActiveSupport::TestCase with_env_tz 'US/Eastern' do Time.stubs(:now).returns Time.local(2000) # since - assert_equal true, 5.seconds.since.is_a?(ActiveSupport::TimeWithZone) + assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.since assert_equal Time.utc(2000,1,1,0,0,5), 5.seconds.since.time assert_equal 'Eastern Time (US & Canada)', 5.seconds.since.time_zone.name # ago - assert_equal true, 5.seconds.ago.is_a?(ActiveSupport::TimeWithZone) + assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.ago assert_equal Time.utc(1999,12,31,23,59,55), 5.seconds.ago.time assert_equal 'Eastern Time (US & Canada)', 5.seconds.ago.time_zone.name end @@ -138,15 +171,16 @@ class DurationTest < ActiveSupport::TestCase assert_equal counter, 60 end + def test_as_json + assert_equal 172800, 2.days.as_json + end + def test_to_json assert_equal '172800', 2.days.to_json end - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end + def test_case_when + cased = case 1.day when 1.day then "ok" end + assert_equal cased, "ok" + end end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 6781e3c20e..6fcf6e8743 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -8,7 +8,6 @@ class SummablePayment < Payment end class EnumerableTests < ActiveSupport::TestCase - Enumerator = [].each.class class GenericEnumerable include Enumerable @@ -21,26 +20,6 @@ class EnumerableTests < ActiveSupport::TestCase end end - def test_group_by - names = %w(marcel sam david jeremy) - klass = Struct.new(:name) - objects = (1..50).map do - klass.new names.sample - end - - enum = GenericEnumerable.new(objects) - grouped = enum.group_by { |object| object.name } - - grouped.each do |name, group| - assert group.all? { |person| person.name == name } - end - - assert_equal objects.uniq.map(&:name), grouped.keys - assert({}.merge(grouped), "Could not convert ActiveSupport::OrderedHash into Hash") - assert_equal Enumerator, enum.group_by.class - assert_equal grouped, enum.group_by.each(&:name) - end - def test_sums enum = GenericEnumerable.new([5, 15, 10]) assert_equal 30, enum.sum @@ -94,6 +73,10 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) }, payments.index_by { |p| p.price }) assert_equal Enumerator, payments.index_by.class + if Enumerator.method_defined? :size + assert_equal nil, payments.index_by.size + assert_equal 42, (1..42).index_by.size + end assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) }, payments.index_by.each { |p| p.price }) end diff --git a/activesupport/test/core_ext/hash/transform_keys_test.rb b/activesupport/test/core_ext/hash/transform_keys_test.rb new file mode 100644 index 0000000000..a7e12117f3 --- /dev/null +++ b/activesupport/test/core_ext/hash/transform_keys_test.rb @@ -0,0 +1,32 @@ +require 'abstract_unit' +require 'active_support/core_ext/hash/keys' + +class TransformKeysTest < ActiveSupport::TestCase + test "transform_keys returns a new hash with the keys computed from the block" do + original = { a: 'a', b: 'b' } + mapped = original.transform_keys { |k| "#{k}!".to_sym } + + assert_equal({ a: 'a', b: 'b' }, original) + assert_equal({ a!: 'a', b!: 'b' }, mapped) + end + + test "transform_keys! modifies the keys of the original" do + original = { a: 'a', b: 'b' } + mapped = original.transform_keys! { |k| "#{k}!".to_sym } + + assert_equal({ a!: 'a', b!: 'b' }, original) + assert_same original, mapped + end + + test "transform_keys returns an Enumerator if no block is given" do + original = { a: 'a', b: 'b' } + enumerator = original.transform_keys + assert_equal Enumerator, enumerator.class + end + + test "transform_keys is chainable with Enumerable methods" do + original = { a: 'a', b: 'b' } + mapped = original.transform_keys.with_index { |k, i| [k, i].join.to_sym } + assert_equal({ a0: 'a', b1: 'b' }, mapped) + end +end diff --git a/activesupport/test/core_ext/hash/transform_values_test.rb b/activesupport/test/core_ext/hash/transform_values_test.rb new file mode 100644 index 0000000000..45ed11fef7 --- /dev/null +++ b/activesupport/test/core_ext/hash/transform_values_test.rb @@ -0,0 +1,61 @@ +require 'abstract_unit' +require 'active_support/core_ext/hash/indifferent_access' +require 'active_support/core_ext/hash/transform_values' + +class TransformValuesTest < ActiveSupport::TestCase + test "transform_values returns a new hash with the values computed from the block" do + original = { a: 'a', b: 'b' } + mapped = original.transform_values { |v| v + '!' } + + assert_equal({ a: 'a', b: 'b' }, original) + assert_equal({ a: 'a!', b: 'b!' }, mapped) + end + + test "transform_values! modifies the values of the original" do + original = { a: 'a', b: 'b' } + mapped = original.transform_values! { |v| v + '!' } + + assert_equal({ a: 'a!', b: 'b!' }, original) + assert_same original, mapped + end + + test "indifferent access is still indifferent after mapping values" do + original = { a: 'a', b: 'b' }.with_indifferent_access + mapped = original.transform_values { |v| v + '!' } + + assert_equal 'a!', mapped[:a] + assert_equal 'a!', mapped['a'] + end + + # This is to be consistent with the behavior of Ruby's built in methods + # (e.g. #select, #reject) as of 2.2 + test "default values do not persist during mapping" do + original = Hash.new('foo') + original[:a] = 'a' + mapped = original.transform_values { |v| v + '!' } + + assert_equal 'a!', mapped[:a] + assert_nil mapped[:b] + end + + test "default procs do not persist after mapping" do + original = Hash.new { 'foo' } + original[:a] = 'a' + mapped = original.transform_values { |v| v + '!' } + + assert_equal 'a!', mapped[:a] + assert_nil mapped[:b] + end + + test "transform_values returns an Enumerator if no block is given" do + original = { a: 'a', b: 'b' } + enumerator = original.transform_values + assert_equal Enumerator, enumerator.class + end + + test "transform_values is chainable with Enumerable methods" do + original = { a: 'a', b: 'b' } + mapped = original.transform_values.with_index { |v, i| [v, i].join } + assert_equal({ a: 'a0', b: 'b1' }, mapped) + end +end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index c6d7ab618c..5e9fdfd872 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -23,6 +23,16 @@ class HashExtTest < ActiveSupport::TestCase end end + class HashByConversion + def initialize(hash) + @hash = hash + end + + def to_hash + @hash + end + end + def setup @strings = { 'a' => 1, 'b' => 2 } @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } } @@ -36,6 +46,10 @@ class HashExtTest < ActiveSupport::TestCase @nested_illegal_symbols = { [] => { [] => 3} } @upcase_strings = { 'A' => 1, 'B' => 2 } @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } } + @string_array_of_hashes = { 'a' => [ { 'b' => 2 }, { 'c' => 3 }, 4 ] } + @symbol_array_of_hashes = { :a => [ { :b => 2 }, { :c => 3 }, 4 ] } + @mixed_array_of_hashes = { :a => [ { :b => 2 }, { 'c' => 3 }, 4 ] } + @upcase_array_of_hashes = { 'A' => [ { 'B' => 2 }, { 'C' => 3 }, 4 ] } end def test_methods @@ -54,6 +68,10 @@ class HashExtTest < ActiveSupport::TestCase assert_respond_to h, :deep_stringify_keys! assert_respond_to h, :to_options assert_respond_to h, :to_options! + assert_respond_to h, :compact + assert_respond_to h, :compact! + assert_respond_to h, :except + assert_respond_to h, :except! end def test_transform_keys @@ -72,6 +90,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } end def test_deep_transform_keys_not_mutates @@ -97,6 +118,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } end def test_deep_transform_keys_with_bang_mutates @@ -122,6 +146,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys + assert_equal @symbol_array_of_hashes, @string_array_of_hashes.deep_symbolize_keys + assert_equal @symbol_array_of_hashes, @symbol_array_of_hashes.deep_symbolize_keys + assert_equal @symbol_array_of_hashes, @mixed_array_of_hashes.deep_symbolize_keys end def test_deep_symbolize_keys_not_mutates @@ -147,6 +174,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_symbols, @nested_symbols.deep_dup.deep_symbolize_keys! assert_equal @nested_symbols, @nested_strings.deep_dup.deep_symbolize_keys! assert_equal @nested_symbols, @nested_mixed.deep_dup.deep_symbolize_keys! + assert_equal @symbol_array_of_hashes, @string_array_of_hashes.deep_dup.deep_symbolize_keys! + assert_equal @symbol_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_symbolize_keys! + assert_equal @symbol_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_symbolize_keys! end def test_deep_symbolize_keys_with_bang_mutates @@ -192,6 +222,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_strings, @nested_symbols.deep_stringify_keys assert_equal @nested_strings, @nested_strings.deep_stringify_keys assert_equal @nested_strings, @nested_mixed.deep_stringify_keys + assert_equal @string_array_of_hashes, @string_array_of_hashes.deep_stringify_keys + assert_equal @string_array_of_hashes, @symbol_array_of_hashes.deep_stringify_keys + assert_equal @string_array_of_hashes, @mixed_array_of_hashes.deep_stringify_keys end def test_deep_stringify_keys_not_mutates @@ -217,6 +250,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_strings, @nested_symbols.deep_dup.deep_stringify_keys! assert_equal @nested_strings, @nested_strings.deep_dup.deep_stringify_keys! assert_equal @nested_strings, @nested_mixed.deep_dup.deep_stringify_keys! + assert_equal @string_array_of_hashes, @string_array_of_hashes.deep_dup.deep_stringify_keys! + assert_equal @string_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_stringify_keys! + assert_equal @string_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_stringify_keys! end def test_deep_stringify_keys_with_bang_mutates @@ -409,6 +445,12 @@ class HashExtTest < ActiveSupport::TestCase assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 } end + def test_update_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + hash.update HashByConversion.new({ :a => 1 }) + assert_equal hash['a'], 1 + end + def test_indifferent_merging hash = HashWithIndifferentAccess.new hash[:a] = 'failure' @@ -428,6 +470,12 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 2, hash['b'] end + def test_merge_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + merged = hash.merge HashByConversion.new({ :a => 1 }) + assert_equal merged['a'], 1 + end + def test_indifferent_replace hash = HashWithIndifferentAccess.new hash[:a] = 42 @@ -440,6 +488,18 @@ class HashExtTest < ActiveSupport::TestCase assert_same hash, replaced end + def test_replace_with_to_hash_conversion + hash = HashWithIndifferentAccess.new + hash[:a] = 42 + + replaced = hash.replace(HashByConversion.new(b: 12)) + + assert hash.key?('b') + assert !hash.key?(:a) + assert_equal 12, hash[:b] + assert_same hash, replaced + end + def test_indifferent_merging_with_block hash = HashWithIndifferentAccess.new hash[:a] = 1 @@ -487,6 +547,12 @@ class HashExtTest < ActiveSupport::TestCase assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end + def test_indifferent_select_returns_a_hash_when_unchanged + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| true} + + assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash + end + def test_indifferent_select_bang indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) indifferent_strings.select! {|k,v| v == 1} @@ -520,6 +586,8 @@ class HashExtTest < ActiveSupport::TestCase roundtrip = mixed_with_default.with_indifferent_access.to_hash assert_equal @strings, roundtrip assert_equal '1234', roundtrip.default + + # Ensure nested hashes are not HashWithIndiffereneAccess new_to_hash = @nested_mixed.with_indifferent_access.to_hash assert_not new_to_hash.instance_of?(HashWithIndifferentAccess) assert_not new_to_hash["a"].instance_of?(HashWithIndifferentAccess) @@ -593,7 +661,15 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 1, h['first'] end - def test_indifferent_subhashes + def test_to_options_on_indifferent_preserves_works_as_hash_with_dup + h = HashWithIndifferentAccess.new({ a: { b: 'b' } }) + dup = h.dup + + dup[:a][:c] = 'c' + assert_equal 'c', h[:a][:c] + end + + def test_indifferent_sub_hashes h = {'user' => {'id' => 5}}.with_indifferent_access ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} @@ -617,11 +693,31 @@ class HashExtTest < ActiveSupport::TestCase { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) end + # not all valid keys are required to be present + assert_nothing_raised do + { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny, :sunny ]) + { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny, :sunny) + end - assert_raise(ArgumentError, "Unknown key: failore") do + exception = assert_raise ArgumentError do { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) + end + assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message + + exception = assert_raise ArgumentError do { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) end + assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message + + exception = assert_raise ArgumentError do + { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure ]) + end + assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message + + exception = assert_raise ArgumentError do + { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure) + end + assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message end def test_assorted_keys_not_stringified @@ -650,6 +746,16 @@ class HashExtTest < ActiveSupport::TestCase assert_equal expected, hash_1 end + def test_deep_merge_with_falsey_values + hash_1 = { e: false } + hash_2 = { e: 'e' } + expected = { e: [:e, false, 'e'] } + assert_equal(expected, hash_1.deep_merge(hash_2) { |k, o, n| [k, o, n] }) + + hash_1.deep_merge!(hash_2) { |k, o, n| [k, o, n] } + assert_equal expected, hash_1 + end + def test_deep_merge_on_indifferent_access hash_1 = HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } }) hash_2 = HashWithIndifferentAccess.new({ :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }) @@ -701,12 +807,6 @@ class HashExtTest < ActiveSupport::TestCase assert_equal expected, merged end - def test_diff - assert_deprecated do - assert_equal({ :a => 2 }, { :a => 2, :b => 5 }.diff({ :a => 1, :b => 5 })) - end - end - def test_slice original = { :a => 'x', :b => 'y', :c => 10 } expected = { :a => 'x', :b => 'y' } @@ -781,6 +881,24 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 'bender', slice['login'] end + def test_slice_bang_does_not_override_default + hash = Hash.new(0) + hash.update(a: 1, b: 2) + + hash.slice!(:a) + + assert_equal 0, hash[:c] + end + + def test_slice_bang_does_not_override_default_proc + hash = Hash.new { |h, k| h[k] = [] } + hash.update(a: 1, b: 2) + + hash.slice!(:a) + + assert_equal [], hash[:c] + end + def test_extract original = {:a => 1, :b => 2, :c => 3, :d => 4} expected = {:a => 1, :b => 2} @@ -828,13 +946,19 @@ class HashExtTest < ActiveSupport::TestCase def test_except_with_more_than_one_argument original = { :a => 'x', :b => 'y', :c => 10 } expected = { :a => 'x' } + assert_equal expected, original.except(:b, :c) + + assert_equal expected, original.except!(:b, :c) + assert_equal expected, original end def test_except_with_original_frozen original = { :a => 'x', :b => 'y' } original.freeze assert_nothing_raised { original.except(:a) } + + assert_raise(RuntimeError) { original.except!(:a) } end def test_except_with_mocha_expectation_on_original @@ -842,6 +966,38 @@ class HashExtTest < ActiveSupport::TestCase original.expects(:delete).never original.except(:a) end + + def test_compact + hash_contain_nil_value = @symbols.merge(z: nil) + hash_with_only_nil_values = { a: nil, b: nil } + + h = hash_contain_nil_value.dup + assert_equal(@symbols, h.compact) + assert_equal(hash_contain_nil_value, h) + + h = hash_with_only_nil_values.dup + assert_equal({}, h.compact) + assert_equal(hash_with_only_nil_values, h) + end + + def test_compact! + hash_contain_nil_value = @symbols.merge(z: nil) + hash_with_only_nil_values = { a: nil, b: nil } + + h = hash_contain_nil_value.dup + assert_equal(@symbols, h.compact!) + assert_equal(@symbols, h) + + h = hash_with_only_nil_values.dup + assert_equal({}, h.compact!) + assert_equal({}, h) + end + + def test_new_with_to_hash_conversion + hash = HashWithIndifferentAccess.new(HashByConversion.new(a: 1)) + assert hash.key?('a') + assert_equal 1, hash[:a] + end end class IWriteMyOwnXML @@ -1346,12 +1502,32 @@ class HashToXmlTest < ActiveSupport::TestCase end end + def test_from_xml_array_one + expected = { 'numbers' => { 'type' => 'Array', 'value' => '1' }} + assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value></numbers>') + end + + def test_from_xml_array_many + expected = { 'numbers' => { 'type' => 'Array', 'value' => [ '1', '2' ] }} + assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value><value>2</value></numbers>') + end + def test_from_trusted_xml_allows_symbol_and_yaml_types expected = { 'product' => { 'name' => :value }} assert_equal expected, Hash.from_trusted_xml('<product><name type="symbol">value</name></product>') assert_equal expected, Hash.from_trusted_xml('<product><name type="yaml">:value</name></product>') end + def test_should_use_default_proc_for_unknown_key + hash_wia = HashWithIndifferentAccess.new { 1 + 2 } + assert_equal 3, hash_wia[:new_key] + end + + def test_should_use_default_proc_if_no_key_is_supplied + hash_wia = HashWithIndifferentAccess.new { 1 + 2 } + assert_equal 3, hash_wia.default + end + def test_should_use_default_value_for_unknown_key hash_wia = HashWithIndifferentAccess.new(3) assert_equal 3, hash_wia[:new_key] @@ -1379,6 +1555,17 @@ class HashToXmlTest < ActiveSupport::TestCase assert_equal 3, hash_wia.default end + def test_should_copy_the_default_proc_when_converting_to_hash_with_indifferent_access + hash = Hash.new do + 2 + 1 + end + assert_equal 3, hash[:foo] + + hash_wia = hash.with_indifferent_access + assert_equal 3, hash_wia[:foo] + assert_equal 3, hash_wia[:bar] + end + # The XML builder seems to fail miserably when trying to tag something # with the same name as a Kernel method (throw, test, loop, select ...) def test_kernel_method_names_to_xml diff --git a/activesupport/test/core_ext/kernel/concern_test.rb b/activesupport/test/core_ext/kernel/concern_test.rb new file mode 100644 index 0000000000..478a00d2d2 --- /dev/null +++ b/activesupport/test/core_ext/kernel/concern_test.rb @@ -0,0 +1,13 @@ +require 'abstract_unit' +require 'active_support/core_ext/kernel/concern' + +class KernelConcernTest < ActiveSupport::TestCase + def test_may_be_defined_at_toplevel + mod = ::TOPLEVEL_BINDING.eval 'concern(:ToplevelConcern) { }' + assert_equal mod, ::ToplevelConcern + assert_kind_of ActiveSupport::Concern, ::ToplevelConcern + assert_not Object.ancestors.include?(::ToplevelConcern), mod.ancestors.inspect + ensure + Object.send :remove_const, :ToplevelConcern + end +end diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb index b8951de402..a87af0007c 100644 --- a/activesupport/test/core_ext/kernel_test.rb +++ b/activesupport/test/core_ext/kernel_test.rb @@ -30,19 +30,29 @@ class KernelTest < ActiveSupport::TestCase end - def test_silence_stderr - old_stderr_position = STDERR.tell - silence_stderr { STDERR.puts 'hello world' } - assert_equal old_stderr_position, STDERR.tell + def test_silence_stream + old_stream_position = STDOUT.tell + silence_stream(STDOUT) { STDOUT.puts 'hello world' } + assert_equal old_stream_position, STDOUT.tell rescue Errno::ESPIPE - # Skip if we can't STDERR.tell + # Skip if we can't stream.tell + end + + def test_silence_stream_closes_file_descriptors + stream = StringIO.new + dup_stream = StringIO.new + stream.stubs(:dup).returns(dup_stream) + dup_stream.expects(:close) + silence_stream(stream) { stream.puts 'hello world' } end def test_quietly old_stdout_position, old_stderr_position = STDOUT.tell, STDERR.tell - quietly do - puts 'see me, feel me' - STDERR.puts 'touch me, heal me' + assert_deprecated do + quietly do + puts 'see me, feel me' + STDERR.puts 'touch me, heal me' + end end assert_equal old_stdout_position, STDOUT.tell assert_equal old_stderr_position, STDERR.tell @@ -50,10 +60,6 @@ class KernelTest < ActiveSupport::TestCase # Skip if we can't STDERR.tell end - def test_silence_stderr_with_return_value - assert_equal 1, silence_stderr { 1 } - end - def test_class_eval o = Object.new class << o; @x = 1; end @@ -61,10 +67,18 @@ class KernelTest < ActiveSupport::TestCase end def test_capture - assert_equal 'STDERR', capture(:stderr) { $stderr.print 'STDERR' } - assert_equal 'STDOUT', capture(:stdout) { print 'STDOUT' } - assert_equal "STDERR\n", capture(:stderr) { system('echo STDERR 1>&2') } - assert_equal "STDOUT\n", capture(:stdout) { system('echo STDOUT') } + assert_deprecated do + assert_equal 'STDERR', capture(:stderr) { $stderr.print 'STDERR' } + end + assert_deprecated do + assert_equal 'STDOUT', capture(:stdout) { print 'STDOUT' } + end + assert_deprecated do + assert_equal "STDERR\n", capture(:stderr) { system('echo STDERR 1>&2') } + end + assert_deprecated do + assert_equal "STDOUT\n", capture(:stdout) { system('echo STDOUT') } + end end end @@ -121,4 +135,4 @@ class KernelDebuggerTest < ActiveSupport::TestCase ensure Object.send(:remove_const, :Rails) end -end +end if RUBY_VERSION < '2.0.0' diff --git a/activesupport/test/core_ext/load_error_test.rb b/activesupport/test/core_ext/load_error_test.rb index 31863d0aca..5f804c749b 100644 --- a/activesupport/test/core_ext/load_error_test.rb +++ b/activesupport/test/core_ext/load_error_test.rb @@ -14,6 +14,15 @@ class TestMissingSourceFile < ActiveSupport::TestCase assert_equal 'nor/this/one.rb', e.path end end + + def test_is_missing + begin load 'nor_does_this_one' + rescue MissingSourceFile => e + assert e.is_missing?('nor_does_this_one') + assert e.is_missing?('nor_does_this_one.rb') + assert_not e.is_missing?('some_other_file') + end + end end class TestLoadError < ActiveSupport::TestCase @@ -29,4 +38,4 @@ class TestLoadError < ActiveSupport::TestCase assert_equal 'nor/this/one.rb', e.path end end -end
\ No newline at end of file +end diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index a577f90bdd..48f3cc579f 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -8,6 +8,11 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase mattr_accessor :bar, :instance_writer => false mattr_reader :shaq, :instance_reader => false mattr_accessor :camp, :instance_accessor => false + + cattr_accessor(:defa) { 'default_accessor_value' } + cattr_reader(:defr) { 'default_reader_value' } + cattr_writer(:defw) { 'default_writer_value' } + cattr_accessor(:quux) { :quux } end @class = Class.new @class.instance_eval { include m } @@ -27,6 +32,11 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase assert_equal :test2, @module.foo end + def test_cattr_accessor_default_value + assert_equal :quux, @module.quux + assert_equal :quux, @object.quux + end + def test_should_not_create_instance_writer assert_respond_to @module, :foo assert_respond_to @module, :foo= @@ -46,16 +56,24 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase end def test_should_raise_name_error_if_attribute_name_is_invalid - assert_raises NameError do + exception = assert_raises NameError do Class.new do - mattr_reader "invalid attribute name" + cattr_reader "1nvalid" end end + assert_equal "invalid attribute name: 1nvalid", exception.message - assert_raises NameError do + exception = assert_raises NameError do Class.new do - mattr_writer "invalid attribute name" + cattr_writer "1nvalid" end end + assert_equal "invalid attribute name: 1nvalid", exception.message + end + + def test_should_use_default_value_if_block_passed + assert_equal 'default_accessor_value', @module.defa + assert_equal 'default_reader_value', @module.defr + assert_equal 'default_writer_value', @module.class_variable_get('@@defw') end end diff --git a/activesupport/test/core_ext/module/concerning_test.rb b/activesupport/test/core_ext/module/concerning_test.rb new file mode 100644 index 0000000000..07d860b71c --- /dev/null +++ b/activesupport/test/core_ext/module/concerning_test.rb @@ -0,0 +1,65 @@ +require 'abstract_unit' +require 'active_support/core_ext/module/concerning' + +class ModuleConcerningTest < ActiveSupport::TestCase + def test_concerning_declares_a_concern_and_includes_it_immediately + klass = Class.new { concerning(:Foo) { } } + assert klass.ancestors.include?(klass::Foo), klass.ancestors.inspect + end +end + +class ModuleConcernTest < ActiveSupport::TestCase + def test_concern_creates_a_module_extended_with_active_support_concern + klass = Class.new do + concern :Baz do + included { @foo = 1 } + def should_be_public; end + end + end + + # Declares a concern but doesn't include it + assert klass.const_defined?(:Baz, false) + assert !ModuleConcernTest.const_defined?(:Baz) + assert_kind_of ActiveSupport::Concern, klass::Baz + assert !klass.ancestors.include?(klass::Baz), klass.ancestors.inspect + + # Public method visibility by default + assert klass::Baz.public_instance_methods.map(&:to_s).include?('should_be_public') + + # Calls included hook + assert_equal 1, Class.new { include klass::Baz }.instance_variable_get('@foo') + end + + class Foo + concerning :Bar do + module ClassMethods + def will_be_orphaned; end + end + + const_set :ClassMethods, Module.new { + def hacked_on; end + } + + # Doesn't overwrite existing ClassMethods module. + class_methods do + def nicer_dsl; end + end + + # Doesn't overwrite previous class_methods definitions. + class_methods do + def doesnt_clobber; end + end + end + end + + def test_using_class_methods_blocks_instead_of_ClassMethods_module + assert !Foo.respond_to?(:will_be_orphaned) + assert Foo.respond_to?(:hacked_on) + assert Foo.respond_to?(:nicer_dsl) + assert Foo.respond_to?(:doesnt_clobber) + + # Orphan in Foo::ClassMethods, not Bar::ClassMethods. + assert Foo.const_defined?(:ClassMethods) + assert Foo::ClassMethods.method_defined?(:will_be_orphaned) + end +end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 8872611fb1..380f5ad42b 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -12,12 +12,6 @@ class Ab Constant3 = "Goodbye World" end -module Xy - class Bc - include One - end -end - module Yz module Zy class Cd @@ -66,6 +60,23 @@ Tester = Struct.new(:client) do delegate :name, :to => :client, :prefix => false end +Product = Struct.new(:name) do + delegate :name, :to => :manufacturer, :prefix => true + delegate :name, :to => :type, :prefix => true + + def manufacturer + @manufacturer ||= begin + nil.unknown_method + end + end + + def type + @type ||= begin + :thing_without_same_method_name_as_delegated.name + end + end +end + class ParameterSet delegate :[], :[]=, :to => :@params @@ -207,7 +218,7 @@ class ModuleTest < ActiveSupport::TestCase def test_delegation_without_allow_nil_and_nil_value david = Someone.new("David") - assert_raise(RuntimeError) { david.street } + assert_raise(Module::DelegationError) { david.street } end def test_delegation_to_method_that_exists_on_nil @@ -234,6 +245,16 @@ class ModuleTest < ActiveSupport::TestCase end end + def test_delegation_line_number + _, line = Someone.instance_method(:foo).source_location + assert_equal Someone::FAILED_DELEGATE_LINE, line + end + + def test_delegate_line_with_nil + _, line = Someone.instance_method(:bar).source_location + assert_equal Someone::FAILED_DELEGATE_LINE_2, line + end + def test_delegation_exception_backtrace someone = Someone.new("foo", "bar") someone.foo @@ -264,6 +285,16 @@ class ModuleTest < ActiveSupport::TestCase assert_equal [3], se.ints end + def test_delegation_doesnt_mask_nested_no_method_error_on_nil_receiver + product = Product.new('Widget') + + # Nested NoMethodError is a different name from the delegation + assert_raise(NoMethodError) { product.manufacturer_name } + + # Nested NoMethodError is the same name as the delegation + assert_raise(NoMethodError) { product.type_name } + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent @@ -278,12 +309,6 @@ class ModuleTest < ActiveSupport::TestCase def test_local_constants assert_equal %w(Constant1 Constant3), Ab.local_constants.sort.map(&:to_s) end - - def test_local_constant_names - ActiveSupport::Deprecation.silence do - assert_equal %w(Constant1 Constant3), Ab.local_constant_names.sort.map(&:to_s) - end - end end module BarMethodAliaser diff --git a/activesupport/test/core_ext/name_error_test.rb b/activesupport/test/core_ext/name_error_test.rb index 03ce09f22a..7525f80cf0 100644 --- a/activesupport/test/core_ext/name_error_test.rb +++ b/activesupport/test/core_ext/name_error_test.rb @@ -3,18 +3,18 @@ require 'active_support/core_ext/name_error' class NameErrorTest < ActiveSupport::TestCase def test_name_error_should_set_missing_name - SomeNameThatNobodyWillUse____Really ? 1 : 0 - flunk "?!?!" - rescue NameError => exc + exc = assert_raise NameError do + SomeNameThatNobodyWillUse____Really ? 1 : 0 + end assert_equal "NameErrorTest::SomeNameThatNobodyWillUse____Really", exc.missing_name assert exc.missing_name?(:SomeNameThatNobodyWillUse____Really) assert exc.missing_name?("NameErrorTest::SomeNameThatNobodyWillUse____Really") end def test_missing_method_should_ignore_missing_name - some_method_that_does_not_exist - flunk "?!?!" - rescue NameError => exc + exc = assert_raise NameError do + some_method_that_does_not_exist + end assert !exc.missing_name?(:Foo) assert_nil exc.missing_name end diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 1da72eb17d..b82448458d 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -22,23 +22,6 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase end end - def test_intervals - @seconds.values.each do |seconds| - assert_equal seconds.since(@now), @now + seconds - assert_equal seconds.until(@now), @now - seconds - end - end - - # Test intervals based from Time.now - def test_now - @seconds.values.each do |seconds| - now = Time.now - assert seconds.ago >= now - seconds - now = Time.now - assert seconds.from_now >= now + seconds - end - end - def test_irregular_durations assert_equal @now.advance(:days => 3000), 3000.days.since(@now) assert_equal @now.advance(:months => 1), 1.month.since(@now) @@ -78,54 +61,16 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase end def test_duration_after_conversion_is_no_longer_accurate - assert_equal 30.days.to_i.since(@now), 1.month.to_i.since(@now) - assert_equal 365.25.days.to_f.since(@now), 1.year.to_f.since(@now) - assert_equal 30.days.to_i.since(@dtnow), 1.month.to_i.since(@dtnow) - assert_equal 365.25.days.to_f.since(@dtnow), 1.year.to_f.since(@dtnow) + assert_equal 30.days.to_i.seconds.since(@now), 1.month.to_i.seconds.since(@now) + assert_equal 365.25.days.to_f.seconds.since(@now), 1.year.to_f.seconds.since(@now) + assert_equal 30.days.to_i.seconds.since(@dtnow), 1.month.to_i.seconds.since(@dtnow) + assert_equal 365.25.days.to_f.seconds.since(@dtnow), 1.year.to_f.seconds.since(@dtnow) end def test_add_one_year_to_leap_day assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10) + 1.year assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10) + 1.year end - - def test_since_and_ago_anchored_to_time_now_when_time_zone_is_not_set - Time.zone = nil - with_env_tz 'US/Eastern' do - Time.stubs(:now).returns Time.local(2000) - # since - assert_equal false, 5.since.is_a?(ActiveSupport::TimeWithZone) - assert_equal Time.local(2000,1,1,0,0,5), 5.since - # ago - assert_equal false, 5.ago.is_a?(ActiveSupport::TimeWithZone) - assert_equal Time.local(1999,12,31,23,59,55), 5.ago - end - end - - def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do - Time.stubs(:now).returns Time.local(2000) - # since - assert_equal true, 5.since.is_a?(ActiveSupport::TimeWithZone) - assert_equal Time.utc(2000,1,1,0,0,5), 5.since.time - assert_equal 'Eastern Time (US & Canada)', 5.since.time_zone.name - # ago - assert_equal true, 5.ago.is_a?(ActiveSupport::TimeWithZone) - assert_equal Time.utc(1999,12,31,23,59,55), 5.ago.time - assert_equal 'Eastern Time (US & Canada)', 5.ago.time_zone.name - end - ensure - Time.zone = nil - end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end end class NumericExtDateTest < ActiveSupport::TestCase @@ -440,4 +385,8 @@ class NumericExtFormattingTest < ActiveSupport::TestCase assert_equal BigDecimal, BigDecimal("1000010").class assert_equal '1 Million', BigDecimal("1000010").to_s(:human) end + + def test_in_milliseconds + assert_equal 10_000, 10.seconds.in_milliseconds + end end diff --git a/activesupport/test/core_ext/object/acts_like_test.rb b/activesupport/test/core_ext/object/acts_like_test.rb new file mode 100644 index 0000000000..e68b1d23cb --- /dev/null +++ b/activesupport/test/core_ext/object/acts_like_test.rb @@ -0,0 +1,33 @@ +require 'abstract_unit' +require 'active_support/core_ext/object' + +class ObjectTests < ActiveSupport::TestCase + 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 +end diff --git a/activesupport/test/core_ext/blank_test.rb b/activesupport/test/core_ext/object/blank_test.rb index a68c074777..246bc7fa61 100644 --- a/activesupport/test/core_ext/blank_test.rb +++ b/activesupport/test/core_ext/object/blank_test.rb @@ -4,17 +4,29 @@ require 'abstract_unit' require 'active_support/core_ext/object/blank' class BlankTest < ActiveSupport::TestCase - BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', [], {} ] + class EmptyTrue + def empty? + 0 + end + end + + class EmptyFalse + def empty? + nil + end + end + + BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', "\u00a0", [], {} ] NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ] def test_blank - BLANK.each { |v| assert v.blank?, "#{v.inspect} should be blank" } - NOT.each { |v| assert !v.blank?, "#{v.inspect} should not be blank" } + BLANK.each { |v| assert_equal true, v.blank?, "#{v.inspect} should be blank" } + NOT.each { |v| assert_equal false, v.blank?, "#{v.inspect} should not be blank" } end def test_present - BLANK.each { |v| assert !v.present?, "#{v.inspect} should not be present" } - NOT.each { |v| assert v.present?, "#{v.inspect} should be present" } + BLANK.each { |v| assert_equal false, v.present?, "#{v.inspect} should not be present" } + NOT.each { |v| assert_equal true, v.present?, "#{v.inspect} should be present" } end def test_presence diff --git a/activesupport/test/core_ext/deep_dup_test.rb b/activesupport/test/core_ext/object/deep_dup_test.rb index 91d558dbb5..91d558dbb5 100644 --- a/activesupport/test/core_ext/deep_dup_test.rb +++ b/activesupport/test/core_ext/object/deep_dup_test.rb diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb new file mode 100644 index 0000000000..34679cb362 --- /dev/null +++ b/activesupport/test/core_ext/object/duplicable_test.rb @@ -0,0 +1,31 @@ +require 'abstract_unit' +require 'bigdecimal' +require 'active_support/core_ext/object/duplicable' +require 'active_support/core_ext/numeric/time' + +class DuplicableTest < ActiveSupport::TestCase + RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds, method(:puts)] + ALLOW_DUP = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] + + # Needed to support Ruby 1.9.x, as it doesn't allow dup on BigDecimal, instead + # raises TypeError exception. Checking here on the runtime whether BigDecimal + # will allow dup or not. + begin + bd = BigDecimal.new('4.56') + ALLOW_DUP << bd.dup + rescue TypeError + RAISE_DUP << bd + end + + def test_duplicable + RAISE_DUP.each do |v| + assert !v.duplicable? + assert_raises(TypeError, v.class.name) { v.dup } + end + + ALLOW_DUP.each do |v| + assert v.duplicable?, "#{ v.class } should be duplicable" + assert_nothing_raised { v.dup } + end + end +end diff --git a/activesupport/test/core_ext/object/inclusion_test.rb b/activesupport/test/core_ext/object/inclusion_test.rb index 478706eeae..32d512eca3 100644 --- a/activesupport/test/core_ext/object/inclusion_test.rb +++ b/activesupport/test/core_ext/object/inclusion_test.rb @@ -37,14 +37,23 @@ class InTest < ActiveSupport::TestCase end class C < B end + class D + end def test_in_module assert A.in?(B) assert A.in?(C) assert !A.in?(A) + assert !A.in?(D) end def test_no_method_catching assert_raise(ArgumentError) { 1.in?(1) } end + + def test_presence_in + assert_equal "stuff", "stuff".presence_in(%w( lots of stuff )) + assert_nil "stuff".presence_in(%w( lots of crap )) + assert_raise(ArgumentError) { 1.presence_in(1) } + end end diff --git a/activesupport/test/core_ext/object/instance_variables_test.rb b/activesupport/test/core_ext/object/instance_variables_test.rb new file mode 100644 index 0000000000..9f4c5dc4f1 --- /dev/null +++ b/activesupport/test/core_ext/object/instance_variables_test.rb @@ -0,0 +1,31 @@ +require 'abstract_unit' +require 'active_support/core_ext/object' + +class ObjectInstanceVariableTest < ActiveSupport::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_instance_values + assert_equal({'bar' => 'bar', 'baz' => 'baz'}, @source.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 diff --git a/activesupport/test/core_ext/object/itself_test.rb b/activesupport/test/core_ext/object/itself_test.rb new file mode 100644 index 0000000000..65db0ddf40 --- /dev/null +++ b/activesupport/test/core_ext/object/itself_test.rb @@ -0,0 +1,9 @@ +require 'abstract_unit' +require 'active_support/core_ext/object' + +class Object::ItselfTest < ActiveSupport::TestCase + test 'itself returns self' do + object = 'fun' + assert_equal object, object.itself + end +end diff --git a/activesupport/test/core_ext/object/json_cherry_pick_test.rb b/activesupport/test/core_ext/object/json_cherry_pick_test.rb new file mode 100644 index 0000000000..2f7ea3a497 --- /dev/null +++ b/activesupport/test/core_ext/object/json_cherry_pick_test.rb @@ -0,0 +1,42 @@ +require 'abstract_unit' + +# These test cases were added to test that cherry-picking the json extensions +# works correctly, primarily for dependencies problems reported in #16131. They +# need to be executed in isolation to reproduce the scenario correctly, because +# other test cases might have already loaded additional dependencies. + +class JsonCherryPickTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def test_time_as_json + require_or_skip 'active_support/core_ext/object/json' + + expected = Time.new(2004, 7, 25) + actual = Time.parse(expected.as_json) + + assert_equal expected, actual + end + + def test_date_as_json + require_or_skip 'active_support/core_ext/object/json' + + expected = Date.new(2004, 7, 25) + actual = Date.parse(expected.as_json) + + assert_equal expected, actual + end + + def test_datetime_as_json + require_or_skip 'active_support/core_ext/object/json' + + expected = DateTime.new(2004, 7, 25) + actual = DateTime.parse(expected.as_json) + + assert_equal expected, actual + end + + private + def require_or_skip(file) + require(file) || skip("'#{file}' was already loaded") + end +end diff --git a/activesupport/test/core_ext/object/to_param_test.rb b/activesupport/test/core_ext/object/to_param_test.rb index bd7c6c422a..30a7557dc2 100644 --- a/activesupport/test/core_ext/object/to_param_test.rb +++ b/activesupport/test/core_ext/object/to_param_test.rb @@ -2,6 +2,12 @@ require 'abstract_unit' require 'active_support/core_ext/object/to_param' class ToParamTest < ActiveSupport::TestCase + class CustomString < String + def to_param + "custom-#{ self }" + end + end + def test_object foo = Object.new def foo.to_s; 'foo' end @@ -16,4 +22,16 @@ class ToParamTest < ActiveSupport::TestCase assert_equal true, true.to_param assert_equal false, false.to_param end + + def test_array + # Empty Array + assert_equal '', [].to_param + + array = [1, 2, 3, 4] + assert_equal "1/2/3/4", array.to_param + + # Array of different objects + array = [1, '3', { a: 1, b: 2 }, nil, true, false, CustomString.new('object')] + assert_equal "1/3/a=1&b=2//true/false/custom-object", array.to_param + end end diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index 92f996f9a4..09cab3ed35 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -46,6 +46,35 @@ class ToQueryTest < ActiveSupport::TestCase :person => {:id => [20, 10]} end + def test_empty_array + assert_equal "person%5B%5D=", [].to_query('person') + end + + def test_nested_empty_hash + assert_equal '', + {}.to_query + assert_query_equal 'a=1&b%5Bc%5D=3', + { a: 1, b: { c: 3, d: {} } } + assert_query_equal '', + { a: {b: {c: {}}} } + assert_query_equal 'b%5Bc%5D=false&b%5Be%5D=&b%5Bf%5D=&p=12', + { p: 12, b: { c: false, e: nil, f: '' } } + assert_query_equal 'b%5Bc%5D=3&b%5Bf%5D=', + { b: { c: 3, k: {}, f: '' } } + assert_query_equal 'b=3', + {a: [], b: 3} + end + + def test_hash_with_namespace + hash = { name: 'Nakshay', nationality: 'Indian' } + assert_equal "user%5Bname%5D=Nakshay&user%5Bnationality%5D=Indian", hash.to_query('user') + end + + def test_hash_sorted_lexicographically + hash = { type: 'human', name: 'Nakshay' } + assert_equal "name=Nakshay&type=human", hash.to_query + end + private def assert_query_equal(expected, actual) assert_equal expected.split('&'), actual.to_query.split('&') diff --git a/activesupport/test/core_ext/object/try_test.rb b/activesupport/test/core_ext/object/try_test.rb new file mode 100644 index 0000000000..225c20fa36 --- /dev/null +++ b/activesupport/test/core_ext/object/try_test.rb @@ -0,0 +1,95 @@ +require 'abstract_unit' +require 'active_support/core_ext/object' + +class ObjectTryTest < ActiveSupport::TestCase + def setup + @string = "Hello" + end + + def test_nonexisting_method + method = :undefined_method + assert !@string.respond_to?(method) + assert_nil @string.try(method) + end + + def test_nonexisting_method_with_arguments + method = :undefined_method + assert !@string.respond_to?(method) + assert_nil @string.try(method, 'llo', 'y') + end + + def test_nonexisting_method_bang + method = :undefined_method + assert !@string.respond_to?(method) + assert_raise(NoMethodError) { @string.try!(method) } + end + + def test_nonexisting_method_with_arguments_bang + method = :undefined_method + assert !@string.respond_to?(method) + assert_raise(NoMethodError) { @string.try!(method, 'llo', 'y') } + end + + def test_try_only_block_bang + assert_equal @string.reverse, @string.try! { |s| s.reverse } + 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 + + def test_try_only_block + assert_equal @string.reverse, @string.try { |s| s.reverse } + end + + def test_try_only_block_nil + ran = false + nil.try { ran = true } + assert_equal false, ran + end + + def test_try_with_instance_eval_block + assert_equal @string.reverse, @string.try { reverse } + end + + def test_try_with_private_method_bang + klass = Class.new do + private + + def private_method + 'private method' + end + end + + assert_raise(NoMethodError) { klass.new.try!(:private_method) } + end + + def test_try_with_private_method + klass = Class.new do + private + + def private_method + 'private method' + end + end + + assert_nil klass.new.try(:private_method) + end +end diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb deleted file mode 100644 index 8d748791e3..0000000000 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ /dev/null @@ -1,181 +0,0 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/object' -require 'active_support/core_ext/class/subclasses' - -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 - -class ObjectTests < ActiveSupport::TestCase - 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 -end - -class ObjectInstanceVariableTest < ActiveSupport::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_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 < ActiveSupport::TestCase - def setup - @string = "Hello" - end - - def test_nonexisting_method - method = :undefined_method - assert !@string.respond_to?(method) - assert_nil @string.try(method) - end - - def test_nonexisting_method_with_arguments - method = :undefined_method - assert !@string.respond_to?(method) - assert_nil @string.try(method, 'llo', 'y') - end - - def test_nonexisting_method_bang - method = :undefined_method - assert !@string.respond_to?(method) - assert_raise(NoMethodError) { @string.try!(method) } - end - - def test_nonexisting_method_with_arguments_bang - method = :undefined_method - assert !@string.respond_to?(method) - assert_raise(NoMethodError) { @string.try!(method, 'llo', 'y') } - end - - def test_try_only_block_bang - assert_equal @string.reverse, @string.try! { |s| s.reverse } - 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 - - def test_try_only_block - assert_equal @string.reverse, @string.try { |s| s.reverse } - end - - def test_try_only_block_nil - ran = false - nil.try { ran = true } - assert_equal false, ran - end - - def test_try_with_private_method_bang - klass = Class.new do - private - - def private_method - 'private method' - end - end - - assert_raise(NoMethodError) { klass.new.try!(:private_method) } - end - - def test_try_with_private_method - klass = Class.new do - private - - def private_method - 'private method' - end - end - - assert_nil klass.new.try(:private_method) - end -end diff --git a/activesupport/test/core_ext/proc_test.rb b/activesupport/test/core_ext/proc_test.rb deleted file mode 100644 index c4d5592196..0000000000 --- a/activesupport/test/core_ext/proc_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/proc' - -class ProcTests < ActiveSupport::TestCase - def test_bind_returns_method_with_changed_self - assert_deprecated do - block = Proc.new { self } - assert_equal self, block.call - bound_block = block.bind("hello") - assert_not_equal block, bound_block - assert_equal "hello", bound_block.call - end - end -end diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index 2f8723a074..98c4ec6b5e 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -12,10 +12,11 @@ class RangeTest < ActiveSupport::TestCase date_range = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30) assert_equal "BETWEEN '2005-12-10 15:30:00' AND '2005-12-10 17:30:00'", date_range.to_s(:db) end - + def test_date_range assert_instance_of Range, DateTime.new..DateTime.new assert_instance_of Range, DateTime::Infinity.new..DateTime::Infinity.new + assert_instance_of Range, DateTime.new..DateTime::Infinity.new end def test_overlaps_last_inclusive @@ -42,7 +43,7 @@ class RangeTest < ActiveSupport::TestCase assert((1...10).include?(1...10)) end - def test_should_include_other_with_exlusive_end + def test_should_include_other_with_exclusive_end assert((1..10).include?(1...10)) end @@ -90,4 +91,35 @@ class RangeTest < ActiveSupport::TestCase time_range_2 = Time.utc(2005, 12, 10, 17, 31)..Time.utc(2005, 12, 10, 18, 00) assert !time_range_1.overlaps?(time_range_2) end + + def test_each_on_time_with_zone + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + assert_raises TypeError do + ((twz - 1.hour)..twz).each {} + end + end + + def test_step_on_time_with_zone + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + assert_raises TypeError do + ((twz - 1.hour)..twz).step(1) {} + end + end + + def test_include_on_time_with_zone + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + assert_raises TypeError do + ((twz - 1.hour)..twz).include?(twz) + end + end + + def test_date_time_with_each + datetime = DateTime.now + assert ((datetime - 1.hour)..datetime).each {} + end + + def test_date_time_with_step + datetime = DateTime.now + assert ((datetime - 1.hour)..datetime).step(1) {} + end end diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 8f0ebc13ea..18b4727c3b 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -10,17 +10,12 @@ require 'active_support/time' require 'active_support/core_ext/string/strip' require 'active_support/core_ext/string/output_safety' require 'active_support/core_ext/string/indent' - -module Ace - module Base - class Case - end - end -end +require 'time_zone_test_helpers' class StringInflectionsTest < ActiveSupport::TestCase include InflectorTestCases include ConstantizeTestCases + include TimeZoneTestHelpers def test_strip_heredoc_on_an_empty_string assert_equal '', ''.strip_heredoc @@ -65,6 +60,11 @@ class StringInflectionsTest < ActiveSupport::TestCase assert_equal("blargles", "blargle".pluralize(2)) end + test 'pluralize with count = 1 still returns new string' do + name = "Kuldeep" + assert_not_same name.pluralize(1), name + end + def test_singularize SingularToPlural.each do |singular, plural| assert_equal(singular, plural.singularize) @@ -162,59 +162,19 @@ class StringInflectionsTest < ActiveSupport::TestCase end end - def test_ord - assert_equal 97, 'a'.ord - assert_equal 97, 'abc'.ord + def test_humanize_without_capitalize + UnderscoreToHumanWithoutCapitalize.each do |underscore, human| + assert_equal(human, underscore.humanize(capitalize: false)) + end end - def test_access - s = "hello" - assert_equal "h", s.at(0) - - assert_equal "llo", s.from(2) - assert_equal "hel", s.to(2) - - assert_equal "h", s.first - assert_equal "he", s.first(2) - assert_equal "", s.first(0) - - assert_equal "o", s.last - assert_equal "llo", s.last(3) - assert_equal "hello", s.last(10) - assert_equal "", s.last(0) - - assert_equal 'x', 'x'.first - assert_equal 'x', 'x'.first(4) - - assert_equal 'x', 'x'.last - assert_equal 'x', 'x'.last(4) + def test_humanize_with_html_escape + assert_equal 'Hello', ERB::Util.html_escape("hello").humanize end - def test_access_returns_a_real_string - hash = {} - hash["h"] = true - hash["hello123".at(0)] = true - assert_equal %w(h), hash.keys - - hash = {} - hash["llo"] = true - hash["hello".from(2)] = true - assert_equal %w(llo), hash.keys - - hash = {} - hash["hel"] = true - hash["hello".to(2)] = true - assert_equal %w(hel), hash.keys - - hash = {} - hash["hello"] = true - hash["123hello".last(5)] = true - assert_equal %w(hello), hash.keys - - hash = {} - hash["hello"] = true - hash["hello123".first(5)] = true - assert_equal %w(hello), hash.keys + def test_ord + assert_equal 97, 'a'.ord + assert_equal 97, 'abc'.ord end def test_starts_ends_with_alias @@ -236,14 +196,14 @@ class StringInflectionsTest < ActiveSupport::TestCase "with tabs( ), newlines( ), unicode nextlines( ) and many spaces( )." # Make sure squish returns what we expect: - assert_equal original.squish, expected + assert_equal expected, original.squish # But doesn't modify the original string: - assert_not_equal original, expected + assert_not_equal expected, original # Make sure squish! returns what we expect: - assert_equal original.squish!, expected + assert_equal expected, original.squish! # And changes the original string: - assert_equal original, expected + assert_equal expected, original end def test_string_inquiry @@ -256,19 +216,40 @@ class StringInflectionsTest < ActiveSupport::TestCase assert_equal "Hello Wor...", "Hello World!!".truncate(12) end - def test_truncate_with_omission_and_seperator + def test_truncate_with_omission_and_separator assert_equal "Hello[...]", "Hello World!".truncate(10, :omission => "[...]") assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => ' ') assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => ' ') assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => ' ') end - def test_truncate_with_omission_and_regexp_seperator + def test_truncate_with_omission_and_regexp_separator assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => /\s/) assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => /\s/) assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => /\s/) end + def test_truncate_words + assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3) + assert_equal "Hello Big...", "Hello Big World!".truncate_words(2) + end + + def test_truncate_words_with_omission + assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3, :omission => "[...]") + assert_equal "Hello Big[...]", "Hello Big World!".truncate_words(2, :omission => "[...]") + end + + def test_truncate_words_with_separator + assert_equal "Hello<br>Big<br>World!...", "Hello<br>Big<br>World!<br>".truncate_words(3, :separator => '<br>') + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :separator => '<br>') + assert_equal "Hello\n<br>Big...", "Hello\n<br>Big<br>Wide<br>World!".truncate_words(2, :separator => '<br>') + end + + def test_truncate_words_with_separator_and_omission + assert_equal "Hello<br>Big<br>World![...]", "Hello<br>Big<br>World!<br>".truncate_words(3, :omission => "[...]", :separator => '<br>') + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :omission => "[...]", :separator => '<br>') + end + def test_truncate_multibyte assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".force_encoding(Encoding::UTF_8), "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding(Encoding::UTF_8).truncate(10) @@ -278,6 +259,11 @@ class StringInflectionsTest < ActiveSupport::TestCase assert !"Hello World!".truncate(12).html_safe? end + def test_remove + assert_equal "Summer", "Fast Summer".remove(/Fast /) + assert_equal "Summer", "Fast Summer".remove!(/Fast /) + end + def test_constantize run_constantize_tests_on do |string| string.constantize @@ -291,7 +277,108 @@ class StringInflectionsTest < ActiveSupport::TestCase end end +class StringAccessTest < ActiveSupport::TestCase + test "#at with Fixnum, returns a substring of one character at that position" do + assert_equal "h", "hello".at(0) + end + + test "#at with Range, returns a substring containing characters at offsets" do + assert_equal "lo", "hello".at(-2..-1) + end + + test "#at with Regex, returns the matching portion of the string" do + assert_equal "lo", "hello".at(/lo/) + assert_equal nil, "hello".at(/nonexisting/) + end + + test "#from with positive Fixnum, returns substring from the given position to the end" do + assert_equal "llo", "hello".from(2) + end + + test "#from with negative Fixnum, position is counted from the end" do + assert_equal "lo", "hello".from(-2) + end + + test "#to with positive Fixnum, substring from the beginning to the given position" do + assert_equal "hel", "hello".to(2) + end + + test "#to with negative Fixnum, position is counted from the end" do + assert_equal "hell", "hello".to(-2) + end + + test "#from and #to can be combined" do + assert_equal "hello", "hello".from(0).to(-1) + assert_equal "ell", "hello".from(1).to(-2) + end + + test "#first returns the first character" do + assert_equal "h", "hello".first + assert_equal 'x', 'x'.first + end + + test "#first with Fixnum, returns a substring from the beginning to position" do + assert_equal "he", "hello".first(2) + assert_equal "", "hello".first(0) + assert_equal "hello", "hello".first(10) + assert_equal 'x', 'x'.first(4) + end + + test "#first with Fixnum >= string length still returns a new string" do + string = "hello" + different_string = string.first(5) + assert_not_same different_string, string + end + + test "#last returns the last character" do + assert_equal "o", "hello".last + assert_equal 'x', 'x'.last + end + + test "#last with Fixnum, returns a substring from the end to position" do + assert_equal "llo", "hello".last(3) + assert_equal "hello", "hello".last(10) + assert_equal "", "hello".last(0) + assert_equal 'x', 'x'.last(4) + end + + test "#last with Fixnum >= string length still returns a new string" do + string = "hello" + different_string = string.last(5) + assert_not_same different_string, string + end + + test "access returns a real string" do + hash = {} + hash["h"] = true + hash["hello123".at(0)] = true + assert_equal %w(h), hash.keys + + hash = {} + hash["llo"] = true + hash["hello".from(2)] = true + assert_equal %w(llo), hash.keys + + hash = {} + hash["hel"] = true + hash["hello".to(2)] = true + assert_equal %w(hel), hash.keys + + hash = {} + hash["hello"] = true + hash["123hello".last(5)] = true + assert_equal %w(hello), hash.keys + + hash = {} + hash["hello"] = true + hash["hello123".first(5)] = true + assert_equal %w(hello), hash.keys + end +end + class StringConversionsTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + def test_string_to_time with_env_tz "Europe/Moscow" do assert_equal Time.utc(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time(:utc) @@ -461,14 +548,6 @@ class StringConversionsTest < ActiveSupport::TestCase assert_nil "".to_date assert_equal Date.new(Date.today.year, 2, 3), "Feb 3rd".to_date end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end end class StringBehaviourTest < ActiveSupport::TestCase @@ -563,6 +642,29 @@ class OutputSafetyTest < ActiveSupport::TestCase assert !@other_combination.html_safe? end + test "Prepending safe onto unsafe yields unsafe" do + @string.prepend "other".html_safe + assert !@string.html_safe? + assert_equal @string, "otherhello" + end + + test "Prepending unsafe onto safe yields escaped safe" do + other = "other".html_safe + other.prepend "<foo>" + assert other.html_safe? + assert_equal other, "<foo>other" + end + + test "Deprecated #prepend! method is still present" do + other = "other".html_safe + + assert_deprecated do + other.prepend! "<foo>" + end + + assert_equal other, "<foo>other" + end + test "Concatting safe onto unsafe yields unsafe" do @other_string = "other" @@ -651,12 +753,6 @@ class OutputSafetyTest < ActiveSupport::TestCase assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) end - test 'knows whether it is encoding aware' do - assert_deprecated do - assert 'ruby'.encoding_aware? - end - end - test "call to_param returns a normal string" do string = @string.html_safe assert string.html_safe? @@ -679,6 +775,14 @@ class OutputSafetyTest < ActiveSupport::TestCase string = "<b>hello</b>".html_safe assert_equal string, ERB::Util.html_escape(string) end + + test "ERB::Util.html_escape_once only escapes once" do + string = '1 < 2 & 3' + escaped_string = "1 < 2 & 3" + + assert_equal escaped_string, ERB::Util.html_escape_once(string) + assert_equal escaped_string, ERB::Util.html_escape_once(escaped_string) + end end class StringExcludeTest < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/thread_test.rb b/activesupport/test/core_ext/thread_test.rb index 230c1203ad..6a7c6e0604 100644 --- a/activesupport/test/core_ext/thread_test.rb +++ b/activesupport/test/core_ext/thread_test.rb @@ -63,15 +63,13 @@ class ThreadExt < ActiveSupport::TestCase end end - def test_thread_variable_security - t = Thread.new { sleep } - - assert_raises(SecurityError) do - Thread.new { $SAFE = 4; t.thread_variable_get(:foo) }.join - end - - assert_raises(SecurityError) do - Thread.new { $SAFE = 4; t.thread_variable_set(:foo, :baz) }.join + def test_thread_variable_frozen_after_set + t = Thread.new { }.join + t.thread_variable_set :foo, "bar" + t.freeze + assert_raises(RuntimeError) do + t.thread_variable_set(:baz, "qux") end end + end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index eefcdbb1b3..c8283cddc5 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'active_support/time' require 'core_ext/date_and_time_behavior' +require 'time_zone_test_helpers' class TimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,usec=0) @@ -8,6 +9,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end include DateAndTimeBehavior + include TimeZoneTestHelpers def test_seconds_since_midnight assert_equal 1,Time.local(2005,1,1,0,0,1).seconds_since_midnight @@ -117,6 +119,18 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end + def test_middle_of_day + assert_equal Time.local(2005,2,4,12,0,0), Time.local(2005,2,4,10,10,10).middle_of_day + with_env_tz 'US/Eastern' do + assert_equal Time.local(2006,4,2,12,0,0), Time.local(2006,4,2,10,10,10).middle_of_day, 'start DST' + assert_equal Time.local(2006,10,29,12,0,0), Time.local(2006,10,29,10,10,10).middle_of_day, 'ends DST' + end + with_env_tz 'NZ' do + assert_equal Time.local(2006,3,19,12,0,0), Time.local(2006,3,19,10,10,10).middle_of_day, 'ends DST' + assert_equal Time.local(2006,10,1,12,0,0), Time.local(2006,10,1,10,10,10).middle_of_day, 'start DST' + end + end + def test_beginning_of_hour assert_equal Time.local(2005,2,4,19,0,0), Time.local(2005,2,4,19,30,10).beginning_of_hour end @@ -464,6 +478,13 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal t, t.advance(:months => 0) end + def test_advance_gregorian_proleptic + assert_equal Time.local(1582,10,14,15,15,10), Time.local(1582,10,15,15,15,10).advance(:days => -1) + assert_equal Time.local(1582,10,15,15,15,10), Time.local(1582,10,14,15,15,10).advance(:days => 1) + assert_equal Time.local(1582,10,5,15,15,10), Time.local(1582,10,4,15,15,10).advance(:days => 1) + assert_equal Time.local(1582,10,4,15,15,10), Time.local(1582,10,5,15,15,10).advance(:days => -1) + end + def test_last_week with_env_tz 'US/Eastern' do assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).last_week @@ -509,6 +530,9 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase with_env_tz "US/Central" do assert_equal "Thu, 05 Feb 2009 14:30:05 -0600", Time.local(2009, 2, 5, 14, 30, 5).to_s(:rfc822) assert_equal "Mon, 09 Jun 2008 04:05:01 -0500", Time.local(2008, 6, 9, 4, 5, 1).to_s(:rfc822) + assert_equal "2009-02-05T14:30:05-06:00", Time.local(2009, 2, 5, 14, 30, 5).to_s(:iso8601) + assert_equal "2008-06-09T04:05:01-05:00", Time.local(2008, 6, 9, 4, 5, 1).to_s(:iso8601) + assert_equal "2009-02-05T14:30:05Z", Time.utc(2009, 2, 5, 14, 30, 5).to_s(:iso8601) end end @@ -578,58 +602,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal 29, Time.days_in_month(2) end - def test_time_with_datetime_fallback - ActiveSupport::Deprecation.silence do - assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30) - assert_equal Time.time_with_datetime_fallback(:local, 2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30) - assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0) - assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30) - assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0) - assert_equal Time.time_with_datetime_fallback(:utc, 2005), Time.utc(2005) - assert_equal Time.time_with_datetime_fallback(:utc, 2039), DateTime.civil(2039, 1, 1, 0, 0, 0, 0) - assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30, 1), Time.utc(2005, 2, 21, 17, 44, 30, 1) #with usec - # This won't overflow on 64bit linux - unless time_is_64bits? - assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1900, 2, 21, 17, 44, 30) - assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1), - DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0) - assert_equal ::Date::ITALY, Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).start # use Ruby's default start value - end - silence_warnings do - 0.upto(138) do |year| - [:utc, :local].each do |format| - assert_equal year, Time.time_with_datetime_fallback(format, year).year - end - end - end - end - end - - def test_utc_time - ActiveSupport::Deprecation.silence do - assert_equal Time.utc_time(2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30) - assert_equal Time.utc_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0) - assert_equal Time.utc_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, 0) - end - end - - def test_local_time - ActiveSupport::Deprecation.silence do - assert_equal Time.local_time(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30) - assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30) - - unless time_is_64bits? - assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1901, 2, 21, 17, 44, 30) - end - end - end - - def test_time_with_datetime_fallback_deprecations - assert_deprecated(/time_with_datetime_fallback/) { Time.time_with_datetime_fallback(:utc, 2012, 6, 7) } - assert_deprecated(/utc_time/) { Time.utc_time(2012, 6, 7) } - assert_deprecated(/local_time/) { Time.local_time(2012, 6, 7) } - end - def test_last_month_on_31st assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month end @@ -752,6 +724,21 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end + def test_at_with_datetime_returns_local_time + with_env_tz 'US/Eastern' do + dt = DateTime.civil(2000, 1, 1, 0, 0, 0, '+0') + assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(dt) + assert_equal 'EST', Time.at(dt).zone + assert_equal(-18000, Time.at(dt).utc_offset) + + # Daylight savings + dt = DateTime.civil(2000, 7, 1, 1, 0, 0, '+1') + assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(dt) + assert_equal 'EDT', Time.at(dt).zone + assert_equal(-14400, Time.at(dt).utc_offset) + end + end + def test_at_with_time_with_zone assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'])) @@ -763,6 +750,45 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end + def test_at_with_time_with_zone_returns_local_time + with_env_tz 'US/Eastern' do + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(twz) + assert_equal 'EST', Time.at(twz).zone + assert_equal(-18000, Time.at(twz).utc_offset) + + # Daylight savings + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(twz) + assert_equal 'EDT', Time.at(twz).zone + assert_equal(-14400, Time.at(twz).utc_offset) + end + end + + def test_at_with_time_microsecond_precision + assert_equal Time.at(Time.utc(2000, 1, 1, 0, 0, 0, 111)).to_f, Time.utc(2000, 1, 1, 0, 0, 0, 111).to_f + end + + def test_at_with_utc_time + with_env_tz 'US/Eastern' do + assert_equal Time.utc(2000), Time.at(Time.utc(2000)) + assert_equal 'UTC', Time.at(Time.utc(2000)).zone + assert_equal(0, Time.at(Time.utc(2000)).utc_offset) + end + end + + def test_at_with_local_time + with_env_tz 'US/Eastern' do + assert_equal Time.local(2000), Time.at(Time.local(2000)) + assert_equal 'EST', Time.at(Time.local(2000)).zone + assert_equal(-18000, Time.at(Time.local(2000)).utc_offset) + + assert_equal Time.local(2000, 7, 1), Time.at(Time.local(2000, 7, 1)) + assert_equal 'EDT', Time.at(Time.local(2000, 7, 1)).zone + assert_equal(-14400, Time.at(Time.local(2000, 7, 1)).utc_offset) + end + end + def test_eql? assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) ) @@ -823,18 +849,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_all_year assert_equal Time.local(2011,1,1,0,0,0)..Time.local(2011,12,31,23,59,59,Rational(999999999, 1000)), Time.local(2011,6,7,10,10,10).all_year end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end - - def time_is_64bits? - Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).is_a?(Time) - end end class TimeExtMarshalingTest < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index ddcfcc491f..3000da8da4 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1,8 +1,9 @@ require 'abstract_unit' require 'active_support/time' -require 'active_support/json' +require 'time_zone_test_helpers' class TimeWithZoneTest < ActiveSupport::TestCase + include TimeZoneTestHelpers def setup @utc = Time.utc(2000, 1, 1, 0) @@ -66,20 +67,6 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal 'EDT', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst end - def test_to_json_with_use_standard_json_time_format_config_set_to_false - old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, false - assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(@twz) - ensure - ActiveSupport.use_standard_json_time_format = old - end - - def test_to_json_with_use_standard_json_time_format_config_set_to_true - old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true - assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(@twz) - ensure - ActiveSupport.use_standard_json_time_format = old - end - def test_nsec local = Time.local(2011,6,7,23,59,59,Rational(999999999, 1000)) with_zone = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Hawaii"], local) @@ -126,6 +113,10 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "1999-12-31T19:00:00.001234-05:00", @twz.xmlschema(12) end + def test_xmlschema_with_nil_fractional_seconds + assert_equal "1999-12-31T19:00:00-05:00", @twz.xmlschema(nil) + end + def test_to_yaml assert_match(/^--- 2000-01-01 00:00:00(\.0+)?\s*Z\n/, @twz.to_yaml) end @@ -257,16 +248,31 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 1) end + def test_minus_with_time_precision + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + end + def test_minus_with_time_with_zone twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] ) twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) assert_equal 86_400.0, twz2 - twz1 end + def test_minus_with_time_with_zone_precision + twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0, Rational(1, 1000)), ActiveSupport::TimeZone['UTC'] ) + twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) + assert_equal 86_399.999999998, twz2 - twz1 + end + def test_minus_with_datetime assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) end + def test_minus_with_datetime_precision + assert_equal 86_399.999999999, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + end + def test_minus_with_wrapped_datetime assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1) assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) @@ -361,6 +367,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_acts_like_time + assert @twz.acts_like_time? assert @twz.acts_like?(:time) assert ActiveSupport::TimeWithZone.new(DateTime.civil(2000), @time_zone).acts_like?(:time) end @@ -506,6 +513,16 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(:sec => 30).inspect end + def test_change_at_dst_boundary + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) + assert_equal twz, twz.change(:min => 0) + end + + def test_round_at_dst_boundary + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) + assert_equal twz, twz.round + end + def test_advance assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(:years => 2).inspect @@ -796,23 +813,17 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "undefined method `this_method_does_not_exist' for Fri, 31 Dec 1999 19:00:00 EST -05:00:Time", e.message assert_no_match "rescue", e.backtrace.first end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end end class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + def setup - @t, @dt = Time.utc(2000), DateTime.civil(2000) + @t, @dt, @zone = Time.utc(2000), DateTime.civil(2000), Time.zone end def teardown - Time.zone = nil + Time.zone = @zone end def test_in_time_zone @@ -868,8 +879,6 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase def test_localtime Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal - ensure - Time.zone = nil end def test_use_zone @@ -908,6 +917,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_time_zone_getter_and_setter_with_zone_default_set + old_zone_default = Time.zone_default Time.zone_default = ActiveSupport::TimeZone['Alaska'] assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone Time.zone = ActiveSupport::TimeZone['Hawaii'] @@ -915,8 +925,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase Time.zone = nil assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone ensure - Time.zone = nil - Time.zone_default = nil + Time.zone_default = old_zone_default end def test_time_zone_setter_is_thread_safe @@ -988,28 +997,25 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase assert_equal 'Eastern Time (US & Canada)', Time.current.time_zone.name assert_equal Time.utc(2000), Time.current.time end - ensure - Time.zone = nil end - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + def test_time_in_time_zone_doesnt_affect_receiver + with_env_tz 'Europe/London' do + time = Time.local(2000, 7, 1) + time_with_zone = time.in_time_zone('Eastern Time (US & Canada)') + assert_equal Time.utc(2000, 6, 30, 23, 0, 0), time_with_zone + assert_not time.utc?, 'time expected to be local, but is UTC' end + end end class TimeWithZoneMethodsForDate < ActiveSupport::TestCase + include TimeZoneTestHelpers + def setup @d = Date.civil(2000) end - def teardown - Time.zone = nil - end - def test_in_time_zone with_tz_default 'Alaska' do assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone.inspect @@ -1042,28 +1048,17 @@ class TimeWithZoneMethodsForDate < ActiveSupport::TestCase assert_raise(ArgumentError) { @d.in_time_zone(-15.hours) } assert_raise(ArgumentError) { @d.in_time_zone(Object.new) } end - - protected - def with_tz_default(tz = nil) - old_tz = Time.zone - Time.zone = tz - yield - ensure - Time.zone = old_tz - end end class TimeWithZoneMethodsForString < ActiveSupport::TestCase + include TimeZoneTestHelpers + def setup @s = "Sat, 01 Jan 2000 00:00:00" @u = "Sat, 01 Jan 2000 00:00:00 UTC +00:00" @z = "Fri, 31 Dec 1999 19:00:00 EST -05:00" end - def teardown - Time.zone = nil - end - def test_in_time_zone with_tz_default 'Alaska' do assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone.inspect @@ -1118,13 +1113,4 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase assert_raise(ArgumentError) { @u.in_time_zone(Object.new) } assert_raise(ArgumentError) { @z.in_time_zone(Object.new) } end - - protected - def with_tz_default(tz = nil) - old_tz = Time.zone - Time.zone = tz - yield - ensure - Time.zone = old_tz - end end diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb index 03e388dd7a..43a5997ddd 100644 --- a/activesupport/test/core_ext/uri_ext_test.rb +++ b/activesupport/test/core_ext/uri_ext_test.rb @@ -7,7 +7,7 @@ class URIExtTest < ActiveSupport::TestCase def test_uri_decode_handle_multibyte str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. - parser = URI::Parser.new + parser = URI.parser assert_equal str, parser.unescape(parser.escape(str)) end end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 68b6cc6e8c..899bb75eae 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -35,19 +35,34 @@ class DependenciesTest < ActiveSupport::TestCase assert_equal expected.path, e.path 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 - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_two' - assert_equal 2, ActiveSupport::Dependencies.loaded.size + with_loading do + require_dependency 'dependencies/service_one' + require_dependency 'dependencies/service_two' + assert_equal 2, ActiveSupport::Dependencies.loaded.size + end ensure Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne) Object.send(:remove_const, :ServiceTwo) if Object.const_defined?(:ServiceTwo) end def test_tracking_identical_loaded_files - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_one' - assert_equal 1, ActiveSupport::Dependencies.loaded.size + with_loading do + require_dependency 'dependencies/service_one' + require_dependency 'dependencies/service_one' + assert_equal 1, ActiveSupport::Dependencies.loaded.size + end ensure Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne) end @@ -62,12 +77,11 @@ class DependenciesTest < ActiveSupport::TestCase $raises_exception_load_count = 0 5.times do |count| - begin + e = assert_raise Exception, 'should have loaded dependencies/raises_exception which raises an exception' do 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 + + assert_equal 'Loading me failed, so do not add to loaded or history.', e.message assert_equal count + 1, $raises_exception_load_count assert !ActiveSupport::Dependencies.loaded.include?(filename) @@ -355,26 +369,21 @@ class DependenciesTest < ActiveSupport::TestCase def test_non_existing_const_raises_name_error_with_fully_qualified_name with_autoloading_fixtures do - begin - A::DoesNotExist.nil? - flunk "No raise!!" - rescue NameError => e - assert_equal "uninitialized constant A::DoesNotExist", e.message - end - begin - A::B::DoesNotExist.nil? - flunk "No raise!!" - rescue NameError => e - assert_equal "uninitialized constant A::B::DoesNotExist", e.message - end + 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 end def test_smart_name_error_strings - Object.module_eval "ImaginaryObject" - flunk "No raise!!" - rescue NameError => e - assert e.message.include?("uninitialized constant ImaginaryObject") + e = assert_raise NameError do + Object.module_eval "ImaginaryObject" + end + assert_includes "uninitialized constant ImaginaryObject", e.message end def test_loadable_constants_for_path_should_handle_empty_autoloads @@ -519,29 +528,22 @@ class DependenciesTest < ActiveSupport::TestCase end end - def test_const_missing_should_not_double_load - $counting_loaded_times = 0 + def test_const_missing_in_anonymous_modules_loads_top_level_constants with_autoloading_fixtures do - require_dependency '././counting_loader' - assert_equal 1, $counting_loaded_times - assert_raise(NameError) { ActiveSupport::Dependencies.load_missing_constant Object, :CountingLoader } - assert_equal 1, $counting_loaded_times + # class_eval STRING pushes the class to the nesting of the eval'ed code. + klass = Class.new.class_eval "E" + assert_equal E, klass end end - def test_const_missing_within_anonymous_module - $counting_loaded_times = 0 - m = Module.new - m.module_eval "def a() CountingLoader; end" - extend m + def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object with_autoloading_fixtures do - kls = nil - assert_nothing_raised { kls = a } - assert_equal "CountingLoader", kls.name - assert_equal 1, $counting_loaded_times + require_dependency 'e' - assert_nothing_raised { kls = a } - assert_equal 1, $counting_loaded_times + mod = Module.new + e = assert_raise(NameError) { mod::E } + assert_equal 'E cannot be autoloaded from an anonymous class or module', e.message + assert_equal :E, e.name end end @@ -550,12 +552,10 @@ class DependenciesTest < ActiveSupport::TestCase c = ServiceOne ActiveSupport::Dependencies.clear assert ! defined?(ServiceOne) - begin + e = assert_raise ArgumentError do ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing) - flunk "Expected exception" - rescue ArgumentError => e - assert_match %r{ServiceOne has been removed from the module tree}i, e.message end + assert_match %r{ServiceOne has been removed from the module tree}i, e.message end end @@ -647,6 +647,14 @@ class DependenciesTest < ActiveSupport::TestCase Object.class_eval { remove_const :E } 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 + end + def test_unloadable with_autoloading_fixtures do Object.const_set :M, Module.new @@ -880,18 +888,18 @@ class DependenciesTest < ActiveSupport::TestCase 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 Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError) 2.times do - begin + e = assert_raise NameError do ::RaisesNameError::FooBarBaz.object_id - flunk 'should have raised NameError when autoloaded file referenced FooBarBaz' - rescue NameError => e - assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message end + assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!" end @@ -949,6 +957,18 @@ class DependenciesTest < ActiveSupport::TestCase Object.class_eval { remove_const :A if const_defined?(: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 + end + + def test_autoload_once_paths_should_behave_when_recursively_loading with_loading 'dependencies', 'autoloading_fixtures' do ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last] @@ -976,11 +996,4 @@ class DependenciesTest < ActiveSupport::TestCase ensure ActiveSupport::Dependencies.hook! end - -private - def remove_constants(*constants) - constants.each do |constant| - Object.send(:remove_const, constant) if Object.const_defined?(constant) - end - end end diff --git a/activesupport/test/deprecation/basic_object_test.rb b/activesupport/test/deprecation/basic_object_test.rb deleted file mode 100644 index 4b5bed9eb1..0000000000 --- a/activesupport/test/deprecation/basic_object_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'abstract_unit' -require 'active_support/deprecation' -require 'active_support/basic_object' - - -class BasicObjectTest < ActiveSupport::TestCase - test 'BasicObject warns about deprecation when inherited from' do - warn = 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.' - ActiveSupport::Deprecation.expects(:warn).with(warn).once - Class.new(ActiveSupport::BasicObject) - end -end
\ No newline at end of file diff --git a/activesupport/test/deprecation/buffered_logger_test.rb b/activesupport/test/deprecation/buffered_logger_test.rb deleted file mode 100644 index bf11a4732c..0000000000 --- a/activesupport/test/deprecation/buffered_logger_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'abstract_unit' -require 'active_support/buffered_logger' - -class BufferedLoggerTest < ActiveSupport::TestCase - - def test_can_be_subclassed - warn = 'ActiveSupport::BufferedLogger is deprecated! Use ActiveSupport::Logger instead.' - - ActiveSupport::Deprecation.expects(:warn).with(warn).once - - Class.new(ActiveSupport::BufferedLogger) - end - - def test_issues_deprecation_when_instantiated - warn = 'ActiveSupport::BufferedLogger is deprecated! Use ActiveSupport::Logger instead.' - - ActiveSupport::Deprecation.expects(:warn).with(warn).once - - ActiveSupport::BufferedLogger.new(STDOUT) - end - -end diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb index 9616e42f44..7aff56cbad 100644 --- a/activesupport/test/deprecation_test.rb +++ b/activesupport/test/deprecation_test.rb @@ -98,6 +98,19 @@ class DeprecationTest < ActiveSupport::TestCase assert_match(/foo=nil/, @b) end + def test_raise_behaviour + ActiveSupport::Deprecation.behavior = :raise + + message = 'Revise this deprecated stuff now!' + callstack = %w(foo bar baz) + + e = assert_raise ActiveSupport::DeprecationException do + ActiveSupport::Deprecation.behavior.first.call(message, callstack) + end + assert_equal message, e.message + assert_equal callstack, e.backtrace + end + def test_default_stderr_behavior ActiveSupport::Deprecation.behavior = :stderr behavior = ActiveSupport::Deprecation.behavior.first @@ -158,7 +171,7 @@ class DeprecationTest < ActiveSupport::TestCase ActiveSupport::Deprecation.warn 'abc' ActiveSupport::Deprecation.warn 'def' end - rescue MiniTest::Assertion + rescue Minitest::Assertion flunk 'assert_deprecated should match any warning in block, not just the last one' end @@ -342,4 +355,21 @@ class DeprecationTest < ActiveSupport::TestCase end deprecator end + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end end diff --git a/activesupport/test/descendants_tracker_without_autoloading_test.rb b/activesupport/test/descendants_tracker_without_autoloading_test.rb index 74669aaca1..00b449af51 100644 --- a/activesupport/test/descendants_tracker_without_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_without_autoloading_test.rb @@ -4,4 +4,14 @@ require 'descendants_tracker_test_cases' class DescendantsTrackerWithoutAutoloadingTest < ActiveSupport::TestCase include DescendantsTrackerTestCases + + # Regression test for #8422. https://github.com/rails/rails/issues/8442 + def test_clear_without_autoloaded_singleton_parent + mark_as_autoloaded do + parent_instance = Parent.new + parent_instance.singleton_class.descendants + ActiveSupport::DescendantsTracker.clear + assert !ActiveSupport::DescendantsTracker.class_variable_get(:@@direct_descendants).key?(parent_instance.singleton_class) + end + end end diff --git a/activesupport/test/empty_bool.rb b/activesupport/test/empty_bool.rb deleted file mode 100644 index 005b3523ef..0000000000 --- a/activesupport/test/empty_bool.rb +++ /dev/null @@ -1,7 +0,0 @@ -class EmptyTrue - def empty?() true; end -end - -class EmptyFalse - def empty?() false; end -end diff --git a/activesupport/test/fixtures/custom.rb b/activesupport/test/fixtures/custom.rb deleted file mode 100644 index 0eefce0c25..0000000000 --- a/activesupport/test/fixtures/custom.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Custom -end
\ No newline at end of file diff --git a/activesupport/test/i18n_test.rb b/activesupport/test/i18n_test.rb index 5ef59b6e6b..3faa15e7fd 100644 --- a/activesupport/test/i18n_test.rb +++ b/activesupport/test/i18n_test.rb @@ -99,7 +99,6 @@ class I18nTest < ActiveSupport::TestCase end def test_to_sentence_with_empty_i18n_store - I18n.backend.store_translations 'empty', {} assert_equal 'a, b, and c', %w[a b c].to_sentence(locale: 'empty') end end diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 22cb61ffd6..58fdea0972 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -70,15 +70,17 @@ class InflectorTest < ActiveSupport::TestCase def test_overwrite_previous_inflectors - assert_equal("series", ActiveSupport::Inflector.singularize("series")) - ActiveSupport::Inflector.inflections.singular "series", "serie" - assert_equal("serie", ActiveSupport::Inflector.singularize("series")) - ActiveSupport::Inflector.inflections.uncountable "series" # Return to normal + with_dup do + assert_equal("series", ActiveSupport::Inflector.singularize("series")) + ActiveSupport::Inflector.inflections.singular "series", "serie" + assert_equal("serie", ActiveSupport::Inflector.singularize("series")) + end end - MixtureToTitleCase.each do |before, titleized| - define_method "test_titleize_#{before}" do - assert_equal(titleized, ActiveSupport::Inflector.titleize(before)) + MixtureToTitleCase.each_with_index do |(before, titleized), index| + define_method "test_titleize_mixture_to_title_case_#{index}" do + assert_equal(titleized, ActiveSupport::Inflector.titleize(before), "mixture \ + to TitleCase failed for #{before}") end end @@ -198,6 +200,7 @@ class InflectorTest < ActiveSupport::TestCase def test_demodulize assert_equal "Account", ActiveSupport::Inflector.demodulize("MyApplication::Billing::Account") assert_equal "Account", ActiveSupport::Inflector.demodulize("Account") + assert_equal "Account", ActiveSupport::Inflector.demodulize("::Account") assert_equal "", ActiveSupport::Inflector.demodulize("") end @@ -229,25 +232,35 @@ class InflectorTest < ActiveSupport::TestCase end end +# FIXME: get following tests to pass on jruby, currently skipped +# +# Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes +# required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby +# causing our tests to error out. +# related bug http://jira.codehaus.org/browse/JRUBY-7194 def test_parameterize + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string)) end end def test_parameterize_and_normalize + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizedAndNormalized.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string)) end end def test_parameterize_with_custom_separator + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, '_')) end end def test_parameterize_with_multi_character_separator + jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, '__sep__')) end @@ -276,6 +289,12 @@ class InflectorTest < ActiveSupport::TestCase end end + def test_humanize_without_capitalize + UnderscoreToHumanWithoutCapitalize.each do |underscore, human| + assert_equal(human, ActiveSupport::Inflector.humanize(underscore, capitalize: false)) + end + end + def test_humanize_by_rule ActiveSupport::Inflector.inflections do |inflect| inflect.human(/_cnt$/i, '\1_count') @@ -419,33 +438,36 @@ class InflectorTest < ActiveSupport::TestCase end end - Irregularities.each do |irregularity| - singular, plural = *irregularity - ActiveSupport::Inflector.inflections do |inflect| - define_method("test_irregularity_between_#{singular}_and_#{plural}") do - inflect.irregular(singular, plural) - assert_equal singular, ActiveSupport::Inflector.singularize(plural) - assert_equal plural, ActiveSupport::Inflector.pluralize(singular) + Irregularities.each do |singular, plural| + define_method("test_irregularity_between_#{singular}_and_#{plural}") do + with_dup do + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal singular, ActiveSupport::Inflector.singularize(plural) + assert_equal plural, ActiveSupport::Inflector.pluralize(singular) + end end end end - Irregularities.each do |irregularity| - singular, plural = *irregularity - ActiveSupport::Inflector.inflections do |inflect| - define_method("test_pluralize_of_irregularity_#{plural}_should_be_the_same") do - inflect.irregular(singular, plural) - assert_equal plural, ActiveSupport::Inflector.pluralize(plural) + Irregularities.each do |singular, plural| + define_method("test_pluralize_of_irregularity_#{plural}_should_be_the_same") do + with_dup do + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal plural, ActiveSupport::Inflector.pluralize(plural) + end end end end - Irregularities.each do |irregularity| - singular, plural = *irregularity - ActiveSupport::Inflector.inflections do |inflect| - define_method("test_singularize_of_irregularity_#{singular}_should_be_the_same") do - inflect.irregular(singular, plural) - assert_equal singular, ActiveSupport::Inflector.singularize(singular) + Irregularities.each do |singular, plural| + define_method("test_singularize_of_irregularity_#{singular}_should_be_the_same") do + with_dup do + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular(singular, plural) + assert_equal singular, ActiveSupport::Inflector.singularize(singular) + end end end end @@ -476,10 +498,10 @@ class InflectorTest < ActiveSupport::TestCase end %w(plurals singulars uncountables humans acronyms).each do |scope| - ActiveSupport::Inflector.inflections do |inflect| - define_method("test_clear_inflections_with_#{scope}") do - with_dup do - # clear the inflections + define_method("test_clear_inflections_with_#{scope}") do + with_dup do + # clear the inflections + ActiveSupport::Inflector.inflections do |inflect| inflect.clear(scope) assert_equal [], inflect.send(scope) end @@ -487,6 +509,14 @@ class InflectorTest < ActiveSupport::TestCase end end + def test_inflections_with_uncountable_words + ActiveSupport::Inflector.inflections do |inflect| + inflect.uncountable "HTTP" + end + + assert_equal "HTTP", ActiveSupport::Inflector.pluralize("HTTP") + end + # Dups the singleton and yields, restoring the original inflections later. # Use this in tests what modify the state of the singleton. # @@ -494,9 +524,10 @@ class InflectorTest < ActiveSupport::TestCase # there are module functions that access ActiveSupport::Inflector.inflections, # so we need to replace the singleton itself. def with_dup - original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__) - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, original.dup) + original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup) + yield ensure - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, original) + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) end end diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index 7704300938..b556da0046 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -63,6 +63,7 @@ module InflectorTestCases "news" => "news", "series" => "series", + "miniseries" => "miniseries", "species" => "species", "quiz" => "quizzes", @@ -105,7 +106,6 @@ module InflectorTestCases "prize" => "prizes", "edge" => "edges", - "cow" => "kine", "database" => "databases", # regression tests against improper inflection regexes @@ -208,9 +208,17 @@ module InflectorTestCases } UnderscoreToHuman = { - "employee_salary" => "Employee salary", - "employee_id" => "Employee", - "underground" => "Underground" + 'employee_salary' => 'Employee salary', + 'employee_id' => 'Employee', + 'underground' => 'Underground', + '_id' => 'Id', + '_external_id' => 'External' + } + + UnderscoreToHumanWithoutCapitalize = { + "employee_salary" => "employee salary", + "employee_id" => "employee", + "underground" => "underground" } MixtureToTitleCase = { @@ -308,7 +316,7 @@ module InflectorTestCases 'child' => 'children', 'sex' => 'sexes', 'move' => 'moves', - 'cow' => 'kine', + 'cow' => 'kine', # Test inflections with different starting letters 'zombie' => 'zombies', 'genus' => 'genera' } diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index 34ed866848..80bf255080 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -4,6 +4,12 @@ require 'active_support/json' require 'active_support/time' class TestJSONDecoding < ActiveSupport::TestCase + class Foo + def self.json_create(object) + "Foo" + end + end + TESTS = { %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, @@ -52,30 +58,56 @@ class TestJSONDecoding < ActiveSupport::TestCase # tests escaping of "\n" char with Yaml backend %q({"a":"\n"}) => {"a"=>"\n"}, %q({"a":"\u000a"}) => {"a"=>"\n"}, - %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"} + %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}, + # prevent json unmarshalling + %q({"json_class":"TestJSONDecoding::Foo"}) => {"json_class"=>"TestJSONDecoding::Foo"}, + # json "fragments" - these are invalid JSON, but ActionPack relies on this + %q("a string") => "a string", + %q(1.1) => 1.1, + %q(1) => 1, + %q(-1) => -1, + %q(true) => true, + %q(false) => false, + %q(null) => nil } - TESTS.each do |json, expected| - test "json decodes #{json}" do - prev = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = true - silence_warnings do - assert_equal expected, ActiveSupport::JSON.decode(json) + TESTS.each_with_index do |(json, expected), index| + test "json decodes #{index}" do + with_parse_json_times(true) do + silence_warnings do + assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ + failed for #{json}" + end end - ActiveSupport.parse_json_times = prev end end test "json decodes time json with time parsing disabled" do - prev = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = false - expected = {"a" => "2007-01-01 01:12:34 Z"} - assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) - ActiveSupport.parse_json_times = prev + with_parse_json_times(false) do + expected = {"a" => "2007-01-01 01:12:34 Z"} + assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) + end end def test_failed_json_decoding + assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%(undefined)) } + assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({a: 1})) } assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%({: 1})) } + assert_raise(ActiveSupport::JSON.parse_error) { ActiveSupport::JSON.decode(%()) } + end + + def test_cannot_pass_unsupported_options + assert_raise(ArgumentError) { ActiveSupport::JSON.decode("", create_additions: true) } + end + + private + + def with_parse_json_times(value) + old_value = ActiveSupport.parse_json_times + ActiveSupport.parse_json_times = value + yield + ensure + ActiveSupport.parse_json_times = old_value end end diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index ed1326705c..ad358ad21d 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -1,9 +1,14 @@ # encoding: utf-8 +require 'securerandom' require 'abstract_unit' require 'active_support/core_ext/string/inflections' require 'active_support/json' +require 'active_support/time' +require 'time_zone_test_helpers' class TestJSONEncoding < ActiveSupport::TestCase + include TimeZoneTestHelpers + class Foo def initialize(a, b) @a, @b = a, b @@ -12,13 +17,17 @@ class TestJSONEncoding < ActiveSupport::TestCase class Hashlike def to_hash - { :a => 1 } + { :foo => "hello", :bar => "world" } end end class Custom - def as_json(options) - 'custom' + def initialize(serialized) + @serialized = serialized + end + + def as_json(options = nil) + @serialized end end @@ -31,6 +40,25 @@ class TestJSONEncoding < ActiveSupport::TestCase end end + class OptionsTest + def as_json(options = :default) + options + end + end + + class HashWithAsJson < Hash + attr_accessor :as_json_called + + def initialize(*) + super + end + + def as_json(options={}) + @as_json_called = true + super + end + end + TrueTests = [[ true, %(true) ]] FalseTests = [[ false, %(false) ]] NilTests = [[ nil, %(null) ]] @@ -42,11 +70,11 @@ class TestJSONEncoding < ActiveSupport::TestCase [ BigDecimal('0.0')/BigDecimal('0.0'), %(null) ], [ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]] - StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")], + StringTests = [[ 'this is the <string>', %("this is the \\u003cstring\\u003e")], [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], [ 'http://test.host/posts/1', %("http://test.host/posts/1")], - [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\342\200\250\342\200\251", - %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\\u2028\\u2029") ]] + [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\u2028\u2029", + %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\u2028\\u2029") ]] ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] @@ -60,8 +88,14 @@ class TestJSONEncoding < ActiveSupport::TestCase [ :"a b", %("a b") ]] ObjectTests = [[ Foo.new(1, 2), %({\"a\":1,\"b\":2}) ]] - HashlikeTests = [[ Hashlike.new, %({\"a\":1}) ]] - CustomTests = [[ Custom.new, '"custom"' ]] + HashlikeTests = [[ Hashlike.new, %({\"bar\":\"world\",\"foo\":\"hello\"}) ]] + CustomTests = [[ Custom.new("custom"), '"custom"' ], + [ Custom.new(nil), 'null' ], + [ Custom.new(:a), '"a"' ], + [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ], + [ Custom.new({ :foo => "hello", :bar => "world" }), '{"bar":"world","foo":"hello"}' ], + [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ], + [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]] RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']] @@ -70,8 +104,8 @@ class TestJSONEncoding < ActiveSupport::TestCase DateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] StandardDateTests = [[ Date.new(2005,2,1), %("2005-02-01") ]] - StandardTimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005-02-01T15:15:10Z") ]] - StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10+00:00") ]] + StandardTimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000Z") ]] + StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000+00:00") ]] StandardStringTests = [[ 'this is the <string>', %("this is the <string>")]] def sorted_json(json) @@ -96,6 +130,13 @@ class TestJSONEncoding < ActiveSupport::TestCase end end + def test_process_status + # There doesn't seem to be a good way to get a handle on a Process::Status object without actually + # creating a child process, hence this to populate $? + system("not_a_real_program_#{SecureRandom.hex}") + assert_equal %({"exitstatus":#{$?.exitstatus},"pid":#{$?.pid}}), ActiveSupport::JSON.encode($?) + end + def test_hash_encoding assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) @@ -135,22 +176,44 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal "𐒑", decoded_hash['string'] end + def test_reading_encode_big_decimal_as_string_option + assert_deprecated do + assert ActiveSupport.encode_big_decimal_as_string + end + end + + def test_setting_deprecated_encode_big_decimal_as_string_option + assert_raise(NotImplementedError) do + ActiveSupport.encode_big_decimal_as_string = true + end + + assert_raise(NotImplementedError) do + ActiveSupport.encode_big_decimal_as_string = false + end + end + def test_exception_raised_when_encoding_circular_reference_in_array a = [1] a << a - assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + assert_deprecated do + assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + end end def test_exception_raised_when_encoding_circular_reference_in_hash a = { :name => 'foo' } a[:next] = a - assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + assert_deprecated do + assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + end end def test_exception_raised_when_encoding_circular_reference_in_hash_inside_array a = { :name => 'foo', :sub => [] } a[:sub] << a - assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + assert_deprecated do + assert_raise(ActiveSupport::JSON::Encoding::CircularReferenceError) { ActiveSupport::JSON.encode(a) } + end end def test_hash_key_identifiers_are_always_quoted @@ -167,21 +230,17 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_time_to_json_includes_local_offset - prev = ActiveSupport.use_standard_json_time_format - ActiveSupport.use_standard_json_time_format = true - with_env_tz 'US/Eastern' do - assert_equal %("2005-02-01T15:15:10-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) + with_standard_json_time_format(true) do + with_env_tz 'US/Eastern' do + assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) + end end - ensure - ActiveSupport.use_standard_json_time_format = prev end def test_hash_with_time_to_json - prev = ActiveSupport.use_standard_json_time_format - ActiveSupport.use_standard_json_time_format = false - assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json - ensure - ActiveSupport.use_standard_json_time_format = prev + with_standard_json_time_format(false) do + assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json + end end def test_nested_hash_with_float @@ -196,6 +255,31 @@ class TestJSONEncoding < ActiveSupport::TestCase end end + def test_hash_like_with_options + h = Hashlike.new + json = h.to_json :only => [:foo] + + assert_equal({"foo"=>"hello"}, JSON.parse(json)) + end + + def test_object_to_json_with_options + obj = Object.new + obj.instance_variable_set :@foo, "hello" + obj.instance_variable_set :@bar, "world" + json = obj.to_json :only => ["foo"] + + assert_equal({"foo"=>"hello"}, JSON.parse(json)) + end + + def test_struct_to_json_with_options + struct = Struct.new(:foo, :bar).new + struct.foo = "hello" + struct.bar = "world" + json = struct.to_json :only => [:foo] + + assert_equal({"foo"=>"hello"}, JSON.parse(json)) + end + def test_hash_should_pass_encoding_options_to_children_in_as_json person = { :name => 'John', @@ -246,12 +330,39 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end - def test_enumerable_should_pass_encoding_options_to_children_in_as_json - people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + People = Class.new(BasicObject) do + include Enumerable + def initialize() + @people = [ + { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, + { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + ] + end + def each(*, &blk) + @people.each do |p| + yield p if blk + p + end.each + end + end + + def test_enumerable_should_generate_json_with_as_json + json = People.new.as_json :only => [:address, :city] + expected = [ + { 'address' => { 'city' => 'London' }}, + { 'address' => { 'city' => 'Paris' }} ] - json = people.each.as_json :only => [:address, :city] + + assert_equal(expected, json) + end + + def test_enumerable_should_generate_json_with_to_json + json = People.new.to_json :only => [:address, :city] + assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) + end + + def test_enumerable_should_pass_encoding_options_to_children_in_as_json + json = People.new.each.as_json :only => [:address, :city] expected = [ { 'address' => { 'city' => 'London' }}, { 'address' => { 'city' => 'Paris' }} @@ -261,23 +372,39 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_enumerable_should_pass_encoding_options_to_children_in_to_json - people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} - ] - json = people.each.to_json :only => [:address, :city] + json = People.new.each.to_json :only => [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end - def test_to_json_should_not_keep_options_around + def test_hash_to_json_should_not_keep_options_around f = CustomWithOptions.new f.foo = "hello" f.bar = "world" hash = {"foo" => f, "other_hash" => {"foo" => "other_foo", "test" => "other_test"}} assert_equal({"foo"=>{"foo"=>"hello","bar"=>"world"}, - "other_hash" => {"foo"=>"other_foo","test"=>"other_test"}}, JSON.parse(hash.to_json)) + "other_hash" => {"foo"=>"other_foo","test"=>"other_test"}}, ActiveSupport::JSON.decode(hash.to_json)) + end + + def test_array_to_json_should_not_keep_options_around + f = CustomWithOptions.new + f.foo = "hello" + f.bar = "world" + + array = [f, {"foo" => "other_foo", "test" => "other_test"}] + assert_equal([{"foo"=>"hello","bar"=>"world"}, + {"foo"=>"other_foo","test"=>"other_test"}], ActiveSupport::JSON.decode(array.to_json)) + end + + def test_hash_as_json_without_options + json = { foo: OptionsTest.new }.as_json + assert_equal({"foo" => :default}, json) + end + + def test_array_as_json_without_options + json = [ OptionsTest.new ].as_json + assert_equal([:default], json) end def test_struct_encoding @@ -302,24 +429,13 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal({"name" => "David", "sub" => { "name" => "David", - "date" => "2010-01-01" }}, JSON.parse(json_custom)) + "date" => "2010-01-01" }}, ActiveSupport::JSON.decode(json_custom)) assert_equal({"name" => "David", "email" => "sample@example.com"}, - JSON.parse(json_strings)) + ActiveSupport::JSON.decode(json_strings)) assert_equal({"name" => "David", "date" => "2010-01-01"}, - JSON.parse(json_string_and_date)) - end - - def test_opt_out_big_decimal_string_serialization - big_decimal = BigDecimal('2.5') - - begin - ActiveSupport.encode_big_decimal_as_string = false - assert_equal big_decimal.to_s, big_decimal.to_json - ensure - ActiveSupport.encode_big_decimal_as_string = true - end + ActiveSupport::JSON.decode(json_string_and_date)) end def test_nil_true_and_false_represented_as_themselves @@ -328,16 +444,104 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal false, false.as_json end + def test_json_gem_dump_by_passing_active_support_encoder + h = HashWithAsJson.new + h[:foo] = "hello" + h[:bar] = "world" + + assert_equal %({"foo":"hello","bar":"world"}), JSON.dump(h) + assert_nil h.as_json_called + end + + def test_json_gem_generate_by_passing_active_support_encoder + h = HashWithAsJson.new + h[:foo] = "hello" + h[:bar] = "world" + + assert_equal %({"foo":"hello","bar":"world"}), JSON.generate(h) + assert_nil h.as_json_called + end + + def test_json_gem_pretty_generate_by_passing_active_support_encoder + h = HashWithAsJson.new + h[:foo] = "hello" + h[:bar] = "world" + + assert_equal <<EXPECTED.chomp, JSON.pretty_generate(h) +{ + "foo": "hello", + "bar": "world" +} +EXPECTED + assert_nil h.as_json_called + end + + def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false + with_standard_json_time_format(false) do + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) + assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time) + end + end + + def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true + with_standard_json_time_format(true) do + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) + assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time) + end + end + + def test_twz_to_json_with_custom_time_precision + with_standard_json_time_format(true) do + with_time_precision(0) do + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) + assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time) + end + end + end + + def test_time_to_json_with_custom_time_precision + with_standard_json_time_format(true) do + with_time_precision(0) do + assert_equal "\"2000-01-01T00:00:00Z\"", ActiveSupport::JSON.encode(Time.utc(2000)) + end + end + end + + def test_datetime_to_json_with_custom_time_precision + with_standard_json_time_format(true) do + with_time_precision(0) do + assert_equal "\"2000-01-01T00:00:00+00:00\"", ActiveSupport::JSON.encode(DateTime.new(2000)) + end + end + end + + def test_twz_to_json_when_wrapping_a_date_time + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone) + assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time) + end + protected def object_keys(json_object) json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort end - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz + def with_standard_json_time_format(boolean = true) + old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, boolean + yield + ensure + ActiveSupport.use_standard_json_time_format = old + end + + def with_time_precision(value) + old_value = ActiveSupport::JSON::Encoding.time_precision + ActiveSupport::JSON::Encoding.time_precision = value yield ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + ActiveSupport::JSON::Encoding.time_precision = old_value end end diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb index 525082d313..f7e8e9a795 100644 --- a/activesupport/test/key_generator_test.rb +++ b/activesupport/test/key_generator_test.rb @@ -29,4 +29,34 @@ class KeyGeneratorTest < ActiveSupport::TestCase end end +class CachingKeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) + @caching_generator = ActiveSupport::CachingKeyGenerator.new(@generator) + end + + test "Generating a cached key for same salt and key size" do + derived_key = @caching_generator.generate_key("some_salt", 32) + cached_key = @caching_generator.generate_key("some_salt", 32) + + assert_equal derived_key, cached_key + assert_equal derived_key.object_id, cached_key.object_id + end + + test "Does not cache key for different salt" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_salt_key = @caching_generator.generate_key("other_salt", 32) + + assert_not_equal derived_key, different_salt_key + end + + test "Does not cache key for different length" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_length_key = @caching_generator.generate_key("some_salt", 64) + + assert_not_equal derived_key, different_length_key + end +end + end diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index 509c453b5c..b6c0a08b05 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -60,12 +60,23 @@ class MessageEncryptorTest < ActiveSupport::TestCase ActiveSupport.use_standard_json_time_format = true encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), SecureRandom.hex(64), :serializer => JSONSerializer.new) message = encryptor.encrypt_and_sign({ :foo => 123, 'bar' => Time.utc(2010) }) - exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, encryptor.decrypt_and_verify(message) ensure ActiveSupport.use_standard_json_time_format = prev end + def test_message_obeys_strict_encoding + bad_encoding_characters = "\n!@#" + message, iv = @encryptor.encrypt_and_sign("This is a very \n\nhumble string"+bad_encoding_characters) + + assert_not_decrypted("#{::Base64.encode64 message.to_s}--#{::Base64.encode64 iv.to_s}") + assert_not_verified("#{::Base64.encode64 message.to_s}--#{::Base64.encode64 iv.to_s}") + + assert_not_decrypted([iv, message] * bad_encoding_characters) + assert_not_verified([iv, message] * bad_encoding_characters) + end + private def assert_not_decrypted(value) @@ -81,7 +92,7 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def munge(base64_string) - bits = ::Base64.decode64(base64_string) + bits = ::Base64.strict_decode64(base64_string) bits.reverse! ::Base64.strict_encode64(bits) end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index a8633f7299..a5748d28ba 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -11,7 +11,7 @@ require 'active_support/time' require 'active_support/json' class MessageVerifierTest < ActiveSupport::TestCase - + class JSONSerializer def dump(value) ActiveSupport::JSON.encode(value) @@ -21,7 +21,7 @@ class MessageVerifierTest < ActiveSupport::TestCase ActiveSupport::JSON.decode(value) end end - + def setup @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!") @data = { :some => "data", :now => Time.local(2010) } @@ -43,18 +43,32 @@ class MessageVerifierTest < ActiveSupport::TestCase assert_not_verified("#{data}--#{hash.reverse}") assert_not_verified("purejunk") end - + def test_alternative_serialization_method prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", :serializer => JSONSerializer.new) message = verifier.generate({ :foo => 123, 'bar' => Time.utc(2010) }) - exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, verifier.verify(message) ensure ActiveSupport.use_standard_json_time_format = prev end - + + def test_raise_error_when_argument_class_is_not_loaded + # To generate the valid message below: + # + # AutoloadClass = Struct.new(:foo) + # valid_message = @verifier.generate(foo: AutoloadClass.new('foo')) + # + valid_message = "BAh7BjoIZm9vbzonTWVzc2FnZVZlcmlmaWVyVGVzdDo6QXV0b2xvYWRDbGFzcwY6CUBmb29JIghmb28GOgZFVA==--f3ef39a5241c365083770566dc7a9eb5d6ace914" + exception = assert_raise(ArgumentError, NameError) do + @verifier.verify(valid_message) + end + assert_includes ["uninitialized constant MessageVerifierTest::AutoloadClass", + "undefined class/module MessageVerifierTest::AutoloadClass"], exception.message + end + def assert_not_verified(message) assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do @verifier.verify(message) diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 2bf73291a2..feca013675 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -3,19 +3,12 @@ require 'abstract_unit' require 'multibyte_test_helpers' require 'active_support/core_ext/string/multibyte' -class String - def __method_for_multibyte_testing_with_integer_result; 1; end - def __method_for_multibyte_testing; 'result'; end - def __method_for_multibyte_testing!; 'result'; end - def __method_for_multibyte_testing_that_returns_nil!; end -end - class MultibyteCharsTest < ActiveSupport::TestCase include MultibyteTestHelpers def setup @proxy_class = ActiveSupport::Multibyte::Chars - @chars = @proxy_class.new UNICODE_STRING + @chars = @proxy_class.new UNICODE_STRING.dup end def test_wraps_the_original_string @@ -24,6 +17,8 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_allow_method_calls_to_string + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + assert_nothing_raised do @chars.__method_for_multibyte_testing end @@ -33,28 +28,35 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_calls_should_return_new_chars_instance + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing assert_not_equal @chars.object_id, @chars.__method_for_multibyte_testing.object_id end def test_forwarded_bang_method_calls_should_return_the_original_chars_instance_when_result_is_not_nil + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing!; 'result'; end } + assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing! assert_equal @chars.object_id, @chars.__method_for_multibyte_testing!.object_id end def test_forwarded_bang_method_calls_should_return_nil_when_result_is_nil + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing_that_returns_nil!; end } + assert_nil @chars.__method_for_multibyte_testing_that_returns_nil! end def test_methods_are_forwarded_to_wrapped_string_for_byte_strings - original_encoding = BYTE_STRING.encoding assert_equal BYTE_STRING.length, BYTE_STRING.mb_chars.length - ensure - BYTE_STRING.force_encoding(original_encoding) end def test_forwarded_method_with_non_string_result_should_be_returned_vertabim - assert_equal ''.__method_for_multibyte_testing_with_integer_result, @chars.__method_for_multibyte_testing_with_integer_result + str = '' + str.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } + + assert_equal str.__method_for_multibyte_testing_with_integer_result, @chars.__method_for_multibyte_testing_with_integer_result end def test_should_concatenate @@ -103,7 +105,6 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase @chars = UNICODE_STRING.dup.mb_chars # Ruby 1.9 only supports basic whitespace @whitespace = "\n\t " - @byte_order_mark = [65279].pack('U') end def test_split_should_return_an_array_of_chars_instances @@ -221,9 +222,9 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_include_raises_when_nil_is_passed - @chars.include?(nil) - flunk "Expected chars.include?(nil) to raise TypeError or NoMethodError" - rescue Exception + assert_raises TypeError, NoMethodError, "Expected chars.include?(nil) to raise TypeError or NoMethodError" do + @chars.include?(nil) + end end def test_index_should_return_character_offset diff --git a/activesupport/test/multibyte_conformance.rb b/activesupport/test/multibyte_conformance_test.rb index 2baf724da4..aba81b8248 100644 --- a/activesupport/test/multibyte_conformance.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -10,7 +10,6 @@ require 'tmpdir' class Downloader def self.download(from, to) unless File.exist?(to) - $stderr.puts "Downloading #{from} to #{to}" unless File.exist?(File.dirname(to)) system "mkdir -p #{File.dirname(to)}" end @@ -20,8 +19,9 @@ class Downloader target.write l end end - end - end + end + end + true end end @@ -31,11 +31,15 @@ class MultibyteConformanceTest < ActiveSupport::TestCase UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" UNIDATA_FILE = '/NormalizationTest.txt' CACHE_DIR = File.join(Dir.tmpdir, 'cache') + FileUtils.mkdir_p(CACHE_DIR) + RUN_P = begin + Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) + rescue + end def setup - FileUtils.mkdir_p(CACHE_DIR) - Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) @proxy = ActiveSupport::Multibyte::Chars + skip "Unable to download test data" unless RUN_P end def test_normalizations_C @@ -126,4 +130,4 @@ class MultibyteConformanceTest < ActiveSupport::TestCase def inspect_codepoints(str) str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') end -end
\ No newline at end of file +end diff --git a/activesupport/test/multibyte_proxy_test.rb b/activesupport/test/multibyte_proxy_test.rb new file mode 100644 index 0000000000..d8ffd7ca9c --- /dev/null +++ b/activesupport/test/multibyte_proxy_test.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 + +require 'abstract_unit' + +class MultibyteProxyText < ActiveSupport::TestCase + class AsciiOnlyEncoder + attr_reader :wrapped_string + alias to_s wrapped_string + + def initialize(string) + @wrapped_string = string.gsub(/[^\u0000-\u007F]/, '?') + end + end + + def with_custom_encoder(encoder) + original_proxy_class = ActiveSupport::Multibyte.proxy_class + + begin + ActiveSupport::Multibyte.proxy_class = encoder + + yield + ensure + ActiveSupport::Multibyte.proxy_class = original_proxy_class + end + end + + test "custom multibyte encoder" do + with_custom_encoder(AsciiOnlyEncoder) do + assert_equal "s?me string 123", "søme string 123".mb_chars.to_s + end + + assert_equal "søme string 123", "søme string 123".mb_chars.to_s + end +end diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index fdbe2f4350..90af2dadd4 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -1,9 +1,9 @@ # encoding: utf-8 module MultibyteTestHelpers - UNICODE_STRING = 'こにちわ' - ASCII_STRING = 'ohayo' - BYTE_STRING = "\270\236\010\210\245".force_encoding("ASCII-8BIT") + UNICODE_STRING = 'こにちわ'.freeze + ASCII_STRING = 'ohayo'.freeze + BYTE_STRING = "\270\236\010\210\245".force_encoding("ASCII-8BIT").freeze def chars(str) ActiveSupport::Multibyte::Chars.new(str) diff --git a/activesupport/test/number_helper_i18n_test.rb b/activesupport/test/number_helper_i18n_test.rb index 65aecece71..e6925e9083 100644 --- a/activesupport/test/number_helper_i18n_test.rb +++ b/activesupport/test/number_helper_i18n_test.rb @@ -43,6 +43,10 @@ module ActiveSupport :custom_units_for_number_to_human => {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} end + def teardown + I18n.backend.reload! + end + def test_number_to_i18n_currency assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) assert_equal("(&$ - 10.00)", number_to_currency(-10, :locale => 'ts')) @@ -50,8 +54,6 @@ module ActiveSupport end def test_number_to_currency_with_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal("$10.00", number_to_currency(10, :locale => 'empty')) assert_equal("-$10.00", number_to_currency(-10, :locale => 'empty')) end @@ -80,8 +82,6 @@ module ActiveSupport end def test_number_with_i18n_precision_and_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal("123456789.123", number_to_rounded(123456789.123456789, :locale => 'empty')) assert_equal("1.000", number_to_rounded(1.0000, :locale => 'empty')) end @@ -92,8 +92,6 @@ module ActiveSupport end def test_number_with_i18n_delimiter_and_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal("1,000,000.234", number_to_delimited(1000000.234, :locale => 'empty')) end @@ -107,8 +105,6 @@ module ActiveSupport end def test_number_to_i18n_percentage_and_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal("1.000%", number_to_percentage(1, :locale => 'empty')) assert_equal("1.243%", number_to_percentage(1.2434, :locale => 'empty')) assert_equal("12434.000%", number_to_percentage(12434, :locale => 'empty')) @@ -121,8 +117,6 @@ module ActiveSupport end def test_number_to_i18n_human_size_with_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal("2 KB", number_to_human_size(2048, :locale => 'empty')) assert_equal("42 Bytes", number_to_human_size(42, :locale => 'empty')) end @@ -142,8 +136,6 @@ module ActiveSupport end def test_number_to_human_with_empty_i18n_store - I18n.backend.store_translations 'empty', {} - assert_equal "2 Thousand", number_to_human(2000, :locale => 'empty') assert_equal "1.23 Billion", number_to_human(1234567890, :locale => 'empty') end diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 1fadef3637..50d84a9470 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'active_support/number_helper' +require 'active_support/core_ext/string/output_safety' module ActiveSupport module NumberHelper @@ -79,6 +80,9 @@ module ActiveSupport assert_equal("123.4%", number_helper.number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) assert_equal("1.000,000%", number_helper.number_to_percentage(1000, :delimiter => '.', :separator => ',')) assert_equal("1000.000 %", number_helper.number_to_percentage(1000, :format => "%n %")) + assert_equal("98a%", number_helper.number_to_percentage("98a")) + assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN)) + assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY)) end end @@ -94,6 +98,7 @@ module ActiveSupport assert_equal("123,456,789.78901", number_helper.number_to_delimited(123456789.78901)) assert_equal("0.78901", number_helper.number_to_delimited(0.78901)) assert_equal("123,456.78", number_helper.number_to_delimited("123456.78")) + assert_equal("123,456.78", number_helper.number_to_delimited("123456.78".html_safe)) end end @@ -102,7 +107,6 @@ module ActiveSupport assert_equal '12 345 678', number_helper.number_to_delimited(12345678, :delimiter => ' ') assert_equal '12,345,678-05', number_helper.number_to_delimited(12345678.05, :separator => '-') assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :separator => ',', :delimiter => '.') - assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :delimiter => '.', :separator => ',') end end @@ -124,6 +128,14 @@ module ActiveSupport assert_equal("10.00", number_helper.number_to_rounded(9.995, :precision => 2)) assert_equal("11.00", number_helper.number_to_rounded(10.995, :precision => 2)) assert_equal("0.00", number_helper.number_to_rounded(-0.001, :precision => 2)) + + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(111.2346, :precision => 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded('111.2346', :precision => 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(BigDecimal(111.2346, Float::DIG), :precision => 20)) + assert_equal("111.2346" + "0"*96, number_helper.number_to_rounded('111.2346', :precision => 100)) + assert_equal("111.2346", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 4)) + assert_equal('0.00', number_helper.number_to_rounded(Rational(0, 1), :precision => 2)) end end @@ -156,6 +168,15 @@ module ActiveSupport assert_equal "10.0", number_helper.number_to_rounded(9.995, :precision => 3, :significant => true) assert_equal "9.99", number_helper.number_to_rounded(9.994, :precision => 3, :significant => true) assert_equal "11.0", number_helper.number_to_rounded(10.995, :precision => 3, :significant => true) + + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775, :precision => 20, :significant => true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775.0, :precision => 20, :significant => true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(Rational(9775, 1), :precision => 20, :significant => true ) + assert_equal "97.750000000000000000", number_helper.number_to_rounded(Rational(9775, 100), :precision => 20, :significant => true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(BigDecimal(9775), :precision => 20, :significant => true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded("9775", :precision => 20, :significant => true ) + assert_equal "9775." + "0"*96, number_helper.number_to_rounded("9775", :precision => 100, :significant => true ) + assert_equal("97.7", number_helper.number_to_rounded(Rational(9772, 100), :precision => 3, :significant => true)) end end @@ -370,12 +391,6 @@ module ActiveSupport end end - def test_extending_or_including_number_helper_correctly_hides_private_methods - [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert !number_helper.respond_to?(:valid_float?) - assert number_helper.respond_to?(:valid_float?, true) - end - end end end end diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb index 9d139b61b8..4c0364e68b 100644 --- a/activesupport/test/option_merger_test.rb +++ b/activesupport/test/option_merger_test.rb @@ -79,6 +79,15 @@ class OptionMergerTest < ActiveSupport::TestCase assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new('', '').class end + def test_option_merger_implicit_receiver + @options.with_options foo: "bar" do + merge! fizz: "buzz" + end + + expected = { hello: "world", foo: "bar", fizz: "buzz" } + assert_equal expected, @options + end + private def method_with_options(options = {}) options diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index c3fe89de4b..460a61613e 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -1,6 +1,6 @@ require 'abstract_unit' require 'active_support/json' -require 'active_support/core_ext/object/to_json' +require 'active_support/core_ext/object/json' require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/array/extract_options' @@ -120,7 +120,9 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_select - assert_equal @keys, @ordered_hash.select { true }.map(&:first) + new_ordered_hash = @ordered_hash.select { true } + assert_equal @keys, new_ordered_hash.map(&:first) + assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash end def test_delete_if @@ -143,6 +145,7 @@ class OrderedHashTest < ActiveSupport::TestCase assert_equal copy, @ordered_hash assert !new_ordered_hash.keys.include?('pink') assert @ordered_hash.keys.include?('pink') + assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash end def test_clear diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 047b89be2a..efa9d5e61f 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -140,4 +140,29 @@ class SafeBufferTest < ActiveSupport::TestCase # should still be unsafe assert !y.html_safe?, "should not be safe" end + + test 'Should work with interpolation (array argument)' do + x = 'foo %s bar'.html_safe % ['qux'] + assert_equal 'foo qux bar', x + end + + test 'Should work with interpolation (hash argument)' do + x = 'foo %{x} bar'.html_safe % { x: 'qux' } + assert_equal 'foo qux bar', x + end + + test 'Should escape unsafe interpolated args' do + x = 'foo %{x} bar'.html_safe % { x: '<br/>' } + assert_equal 'foo <br/> bar', x + end + + test 'Should not escape safe interpolated args' do + x = 'foo %{x} bar'.html_safe % { x: '<br/>'.html_safe } + assert_equal 'foo <br/> bar', x + end + + test 'Should interpolate to a safe string' do + x = 'foo %{x} bar'.html_safe % { x: 'qux' } + assert x.html_safe?, 'should be safe' + end end diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb new file mode 100644 index 0000000000..a88d8d9eba --- /dev/null +++ b/activesupport/test/subscriber_test.rb @@ -0,0 +1,54 @@ +require 'abstract_unit' +require 'active_support/subscriber' + +class TestSubscriber < ActiveSupport::Subscriber + attach_to :doodle + + cattr_reader :events + + def self.clear + @@events = [] + end + + def open_party(event) + events << event + end + + private + + def private_party(event) + events << event + end +end + +# Monkey patch subscriber to test that only one subscriber per method is added. +class TestSubscriber + remove_method :open_party + def open_party(event) + events << event + end +end + +class SubscriberTest < ActiveSupport::TestCase + def setup + TestSubscriber.clear + end + + def test_attaches_subscribers + ActiveSupport::Notifications.instrument("open_party.doodle") + + assert_equal "open_party.doodle", TestSubscriber.events.first.name + end + + def test_attaches_only_one_subscriber + ActiveSupport::Notifications.instrument("open_party.doodle") + + assert_equal 1, TestSubscriber.events.size + end + + def test_does_not_attach_private_methods + ActiveSupport::Notifications.instrument("private_party.doodle") + + assert_equal [], TestSubscriber.events + end +end diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_case_test.rb index 68f9ec6c00..c93192f207 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_case_test.rb @@ -19,19 +19,37 @@ class AssertDifferenceTest < ActiveSupport::TestCase assert_equal true, assert_not(nil) assert_equal true, assert_not(false) - e = assert_raises(MiniTest::Assertion) { assert_not true } + e = assert_raises(Minitest::Assertion) { assert_not true } assert_equal 'Expected true to be nil or false', e.message - e = assert_raises(MiniTest::Assertion) { assert_not true, 'custom' } + e = assert_raises(Minitest::Assertion) { assert_not true, 'custom' } assert_equal 'custom', e.message end - def test_assert_no_difference + def test_assert_no_difference_pass assert_no_difference '@object.num' do # ... end end + def test_assert_no_difference_fail + error = assert_raises(Minitest::Assertion) do + assert_no_difference '@object.num' do + @object.increment + end + end + assert_equal "\"@object.num\" didn't change by 0.\nExpected: 0\n Actual: 1", error.message + end + + def test_assert_no_difference_with_message_fail + error = assert_raises(Minitest::Assertion) do + assert_no_difference '@object.num', 'Object Changed' do + @object.increment + end + end + assert_equal "Object Changed.\n\"@object.num\" didn't change by 0.\nExpected: 0\n Actual: 1", error.message + end + def test_assert_difference assert_difference '@object.num', +1 do @object.increment @@ -71,7 +89,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_array_of_expressions_identify_failure - assert_raises(MiniTest::Assertion) do + assert_raises(Minitest::Assertion) do assert_difference ['@object.num', '1 + 1'] do @object.increment end @@ -79,7 +97,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_array_of_expressions_identify_failure_when_message_provided - assert_raises(MiniTest::Assertion) do + assert_raises(Minitest::Assertion) do assert_difference ['@object.num', '1 + 1'], 1, 'something went wrong' do @object.increment end @@ -87,54 +105,6 @@ class AssertDifferenceTest < ActiveSupport::TestCase end end -class AssertBlankTest < ActiveSupport::TestCase - BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ] - NOT_BLANK = [ EmptyFalse.new, Object.new, true, 0, 1, 'x', [nil], { nil => 0 } ] - - def test_assert_blank_true - BLANK.each { |value| - assert_deprecated { assert_blank value } - } - end - - def test_assert_blank_false - NOT_BLANK.each { |v| - assert_deprecated { - begin - assert_blank v - fail 'should not get to here' - rescue Exception => e - assert_match(/is not blank/, e.message) - end - } - } - end -end - -class AssertPresentTest < ActiveSupport::TestCase - BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ] - NOT_BLANK = [ EmptyFalse.new, Object.new, true, 0, 1, 'x', [nil], { nil => 0 } ] - - def test_assert_present_true - NOT_BLANK.each { |v| - assert_deprecated { assert_present v } - } - end - - def test_assert_present_false - BLANK.each { |v| - assert_deprecated { - begin - assert_present v - fail 'should not get to here' - rescue Exception => e - assert_match(/is blank/, e.message) - end - } - } - end -end - class AlsoDoingNothingTest < ActiveSupport::TestCase end @@ -170,7 +140,6 @@ class SetupAndTeardownTest < ActiveSupport::TestCase end end - class SubclassSetupAndTeardownTest < SetupAndTeardownTest setup :bar teardown :bar @@ -191,7 +160,6 @@ class SubclassSetupAndTeardownTest < SetupAndTeardownTest end end - class TestCaseTaggedLoggingTest < ActiveSupport::TestCase def before_setup require 'stringio' diff --git a/activesupport/test/testing/constant_lookup_test.rb b/activesupport/test/testing/constant_lookup_test.rb index aca2951450..0f16419c8b 100644 --- a/activesupport/test/testing/constant_lookup_test.rb +++ b/activesupport/test/testing/constant_lookup_test.rb @@ -6,7 +6,6 @@ class Bar < Foo def index; end def self.index; end end -class Baz < Bar; end module FooBar; end class ConstantLookupTest < ActiveSupport::TestCase @@ -66,4 +65,12 @@ class ConstantLookupTest < ActiveSupport::TestCase } } end + + def test_does_not_swallow_exception_on_no_name_error_within_constant + assert_raises(NameError) do + with_autoloading_fixtures do + self.class.determine_constant_from_test_name('RaisesNameError') + end + end + end end diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb new file mode 100644 index 0000000000..065539671d --- /dev/null +++ b/activesupport/test/time_travel_test.rb @@ -0,0 +1,72 @@ +require 'abstract_unit' +require 'active_support/core_ext/date' +require 'active_support/core_ext/numeric/time' + +class TimeTravelTest < ActiveSupport::TestCase + setup do + Time.stubs now: Time.now + end + + teardown do + travel_back + end + + def test_time_helper_travel + expected_time = Time.now + 1.day + travel 1.day + + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_equal expected_time.to_date, Date.today + end + + def test_time_helper_travel_with_block + expected_time = Time.now + 1.day + + travel 1.day do + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_equal expected_time.to_date, Date.today + end + + assert_not_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_not_equal expected_time.to_date, Date.today + end + + def test_time_helper_travel_to + expected_time = Time.new(2004, 11, 24, 01, 04, 44) + travel_to expected_time + + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + end + + def test_time_helper_travel_to_with_block + expected_time = Time.new(2004, 11, 24, 01, 04, 44) + + travel_to expected_time do + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + end + + assert_not_equal expected_time, Time.now + assert_not_equal Date.new(2004, 11, 24), Date.today + end + + def test_time_helper_travel_back + expected_time = Time.new(2004, 11, 24, 01, 04, 44) + + travel_to expected_time + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + travel_back + + assert_not_equal expected_time, Time.now + assert_not_equal Date.new(2004, 11, 24), Date.today + end + + def test_travel_to_will_reset_the_usec_to_avoid_mysql_rouding + travel_to Time.utc(2014, 10, 10, 10, 10, 50, 999999) do + assert_equal 50, Time.now.sec + assert_equal 0, Time.now.usec + end + end +end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 84c3154e53..b7a89ed332 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -1,7 +1,10 @@ require 'abstract_unit' require 'active_support/time' +require 'time_zone_test_helpers' class TimeZoneTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + def test_utc_to_local zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500 @@ -89,14 +92,65 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_today - Time.stubs(:now).returns(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST + travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today - Time.stubs(:now).returns(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST + travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today - Time.stubs(:now).returns(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST + travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today - Time.stubs(:now).returns(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST + travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + travel_back + end + + def test_tomorrow + travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST + assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + travel_back + end + + def test_yesterday + travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST + assert_equal Date.new(1999, 12, 30), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + travel_back + end + + def test_travel_to_a_date + with_env_tz do + Time.use_zone('Hawaii') do + date = Date.new(2014, 2, 18) + time = date.midnight + + travel_to date do + assert_equal date, Date.current + assert_equal time, Time.current + end + end + end + end + + def test_travel_to_travels_back_and_reraises_if_the_block_raises + ts = Time.current - 1.second + + travel_to ts do + raise + end + + flunk # ensure travel_to re-raises + rescue + assert_not_equal ts, Time.current end def test_local @@ -203,6 +257,15 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal Time.utc(1999,12,31,19), twz.time end + def test_parse_with_day_omitted + with_env_tz 'US/Eastern' do + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + assert_equal Time.local(2000, 2, 1), zone.parse('Feb', Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 1), zone.parse('Feb 2005', Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 2), zone.parse('2 Feb 2005', Time.local(2000, 1, 1)) + end + end + def test_parse_should_not_black_out_system_timezone_dst_jump with_env_tz('EET') do zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] @@ -356,12 +419,4 @@ class TimeZoneTest < ActiveSupport::TestCase assert ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Hawaii"]) assert !ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Kuala Lumpur"]) end - - protected - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz - yield - ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') - end end diff --git a/activesupport/test/time_zone_test_helpers.rb b/activesupport/test/time_zone_test_helpers.rb new file mode 100644 index 0000000000..9632b89d09 --- /dev/null +++ b/activesupport/test/time_zone_test_helpers.rb @@ -0,0 +1,16 @@ +module TimeZoneTestHelpers + def with_tz_default(tz = nil) + old_tz = Time.zone + Time.zone = tz + yield + ensure + Time.zone = old_tz + end + + def with_env_tz(new_tz = 'US/Eastern') + old_tz, ENV['TZ'] = ENV['TZ'], new_tz + yield + ensure + old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + end +end diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb index ce91c443e1..6833ae68a7 100644 --- a/activesupport/test/transliterate_test.rb +++ b/activesupport/test/transliterate_test.rb @@ -3,7 +3,6 @@ require 'abstract_unit' require 'active_support/inflector/transliterate' class TransliterateTest < ActiveSupport::TestCase - def test_transliterate_should_not_change_ascii_chars (0..127).each do |byte| char = [byte].pack("U") @@ -12,7 +11,7 @@ class TransliterateTest < ActiveSupport::TestCase end def test_transliterate_should_approximate_ascii - # create string with range of Unicode"s western characters with + # create string with range of Unicode's western characters with # diacritics, excluding the division and multiplication signs which for # some reason or other are floating in the middle of all the letters. string = (0xC0..0x17E).to_a.reject {|c| [0xD7, 0xF7].include?(c)}.pack("U*") @@ -24,12 +23,13 @@ class TransliterateTest < ActiveSupport::TestCase def test_transliterate_should_work_with_custom_i18n_rules_and_uncomposed_utf8 char = [117, 776].pack("U*") # "ü" as ASCII "u" plus COMBINING DIAERESIS I18n.backend.store_translations(:de, :i18n => {:transliterate => {:rule => {"ü" => "ue"}}}) - I18n.locale = :de + default_locale, I18n.locale = I18n.locale, :de assert_equal "ue", ActiveSupport::Inflector.transliterate(char) + ensure + I18n.locale = default_locale end def test_transliterate_should_allow_a_custom_replacement_char assert_equal "a*b", ActiveSupport::Inflector.transliterate("a索b", "*") end - end diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index a025279e16..f49431cbbf 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -1,6 +1,9 @@ require 'abstract_unit' require 'active_support/xml_mini' require 'active_support/builder' +require 'active_support/core_ext/array' +require 'active_support/core_ext/hash' +require 'active_support/core_ext/big_decimal' module XmlMiniTest class RenameKeyTest < ActiveSupport::TestCase @@ -88,6 +91,61 @@ module XmlMiniTest assert_xml "<b>Howdy</b>" end + test "#to_tag should use the type value in the options hash" do + @xml.to_tag(:b, "blue", @options.merge(type: 'color')) + assert_xml( "<b type=\"color\">blue</b>" ) + end + + test "#to_tag accepts symbol types" do + @xml.to_tag(:b, :name, @options) + assert_xml( "<b type=\"symbol\">name</b>" ) + end + + test "#to_tag accepts boolean types" do + @xml.to_tag(:b, true, @options) + assert_xml( "<b type=\"boolean\">true</b>") + end + + test "#to_tag accepts float types" do + @xml.to_tag(:b, 3.14, @options) + assert_xml( "<b type=\"float\">3.14</b>") + end + + test "#to_tag accepts decimal types" do + @xml.to_tag(:b, ::BigDecimal.new("1.2"), @options) + assert_xml( "<b type=\"decimal\">1.2</b>") + end + + test "#to_tag accepts date types" do + @xml.to_tag(:b, Date.new(2001,2,3), @options) + assert_xml( "<b type=\"date\">2001-02-03</b>") + end + + test "#to_tag accepts datetime types" do + @xml.to_tag(:b, DateTime.new(2001,2,3,4,5,6,'+7'), @options) + assert_xml( "<b type=\"dateTime\">2001-02-03T04:05:06+07:00</b>") + end + + test "#to_tag accepts time types" do + @xml.to_tag(:b, Time.new(1993, 02, 24, 12, 0, 0, "+09:00"), @options) + assert_xml( "<b type=\"dateTime\">1993-02-24T12:00:00+09:00</b>") + end + + test "#to_tag accepts array types" do + @xml.to_tag(:b, ["first_name", "last_name"], @options) + assert_xml( "<b type=\"array\"><b>first_name</b><b>last_name</b></b>" ) + end + + test "#to_tag accepts hash types" do + @xml.to_tag(:b, { first_name: "Bob", last_name: "Marley" }, @options) + assert_xml( "<b><first-name>Bob</first-name><last-name>Marley</last-name></b>" ) + end + + test "#to_tag should not add type when skip types option is set" do + @xml.to_tag(:b, "Bob", @options.merge(skip_types: 1)) + assert_xml( "<b>Bob</b>" ) + end + test "#to_tag should dasherize the space when passed a string with spaces as a key" do @xml.to_tag("New York", 33, @options) assert_xml "<New---York type=\"integer\">33</New---York>" @@ -97,7 +155,6 @@ module XmlMiniTest @xml.to_tag(:"New York", 33, @options) assert_xml "<New---York type=\"integer\">33</New---York>" end - # TODO: test the remaining functions hidden in #to_tag. end class WithBackendTest < ActiveSupport::TestCase @@ -106,7 +163,11 @@ module XmlMiniTest module Nokogiri end setup do - @xml = ActiveSupport::XmlMini + @xml, @default_backend = ActiveSupport::XmlMini, ActiveSupport::XmlMini.backend + end + + teardown do + ActiveSupport::XmlMini.backend = @default_backend end test "#with_backend should switch backend and then switch back" do @@ -135,7 +196,11 @@ module XmlMiniTest module LibXML end setup do - @xml = ActiveSupport::XmlMini + @xml, @default_backend = ActiveSupport::XmlMini, ActiveSupport::XmlMini.backend + end + + teardown do + ActiveSupport::XmlMini.backend = @default_backend end test "#with_backend should be thread-safe" do @@ -161,4 +226,128 @@ module XmlMiniTest end end end + + class ParsingTest < ActiveSupport::TestCase + def setup + @parsing = ActiveSupport::XmlMini::PARSING + end + + def test_symbol + parser = @parsing['symbol'] + assert_equal :symbol, parser.call('symbol') + assert_equal :symbol, parser.call(:symbol) + assert_equal :'123', parser.call(123) + assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } + end + + def test_date + parser = @parsing['date'] + assert_equal Date.new(2013,11,12), parser.call("2013-11-12T0211Z") + assert_raises(TypeError) { parser.call(1384190018) } + assert_raises(ArgumentError) { parser.call("not really a date") } + end + + def test_datetime + parser = @parsing['datetime'] + assert_equal Time.new(2013,11,12,02,11,00,0), parser.call("2013-11-12T02:11:00Z") + assert_equal DateTime.new(2013,11,12), parser.call("2013-11-12T0211Z") + assert_equal DateTime.new(2013,11,12,02,11), parser.call("2013-11-12T02:11Z") + assert_equal DateTime.new(2013,11,12,02,11), parser.call("2013-11-12T11:11+9") + assert_raises(ArgumentError) { parser.call("1384190018") } + end + + def test_integer + parser = @parsing['integer'] + assert_equal 123, parser.call(123) + assert_equal 123, parser.call(123.003) + assert_equal 123, parser.call("123") + assert_equal 0, parser.call("") + assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } + end + + def test_float + parser = @parsing['float'] + assert_equal 123, parser.call("123") + assert_equal 123.003, parser.call("123.003") + assert_equal 123.0, parser.call("123,003") + assert_equal 0.0, parser.call("") + assert_equal 123, parser.call(123) + assert_equal 123.05, parser.call(123.05) + assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } + end + + def test_decimal + parser = @parsing['decimal'] + assert_equal 123, parser.call("123") + assert_equal 123.003, parser.call("123.003") + assert_equal 123.0, parser.call("123,003") + assert_equal 0.0, parser.call("") + assert_equal 123, parser.call(123) + assert_raises(ArgumentError) { parser.call(123.04) } + assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } + end + + def test_boolean + parser = @parsing['boolean'] + [1, true, "1"].each do |value| + assert parser.call(value) + end + + [0, false, "0"].each do |value| + assert_not parser.call(value) + end + end + + def test_string + parser = @parsing['string'] + assert_equal "123", parser.call(123) + assert_equal "123", parser.call("123") + assert_equal "[]", parser.call("[]") + assert_equal "[]", parser.call([]) + assert_equal "{}", parser.call({}) + assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } + end + + def test_yaml + yaml = <<YAML +product: + - sku : BL394D + quantity : 4 + description : Basketball +YAML + expected = { + "product"=> [ + {"sku"=>"BL394D", "quantity"=>4, "description"=>"Basketball"} + ] + } + parser = @parsing['yaml'] + assert_equal(expected, parser.call(yaml)) + assert_equal({1 => 'test'}, parser.call({1 => 'test'})) + assert_equal({"1 => 'test'"=>nil}, parser.call("{1 => 'test'}")) + end + + def test_base64Binary_and_binary + base64 = <<BASE64 +TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz +IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg +dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu +dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo +ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4= +BASE64 + expected_base64 = <<EXPECTED +Man is distinguished, not only by his reason, but by this singular passion from +other animals, which is a lust of the mind, that by a perseverance of delight +in the continued and indefatigable generation of knowledge, exceeds the short +vehemence of any carnal pleasure. +EXPECTED + + parser = @parsing['base64Binary'] + assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64) + parser.call("NON BASE64 INPUT") + + parser = @parsing['binary'] + assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64, 'encoding' => 'base64') + assert_equal "IGNORED INPUT", parser.call("IGNORED INPUT", {}) + end + end end |