diff options
Diffstat (limited to 'activesupport/test')
79 files changed, 1647 insertions, 673 deletions
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index f214898145..01e60abd99 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -29,17 +29,16 @@ I18n.enforce_available_locales = false class ActiveSupport::TestCase include ActiveSupport::Testing::MethodCallAssertions - # Skips the current run on Rubinius using Minitest::Assertions#skip - private def rubinius_skip(message = "") - skip message if RUBY_ENGINE == "rbx" - end - - # Skips the current run on JRuby using Minitest::Assertions#skip - private def jruby_skip(message = "") - skip message if defined?(JRUBY_VERSION) - end - - def frozen_error_class - Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError - end + private + # 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 end + +require_relative "../../tools/test_common" diff --git a/activesupport/test/autoloading_fixtures/module_folder/nested_with_require.rb b/activesupport/test/autoloading_fixtures/module_folder/nested_with_require.rb new file mode 100644 index 0000000000..f9d6e675d7 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/module_folder/nested_with_require.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "dependencies/module_folder/lib_class" + +module ModuleFolder + class NestedWithRequire + end +end diff --git a/activesupport/test/autoloading_fixtures/nested_with_require_parent.rb b/activesupport/test/autoloading_fixtures/nested_with_require_parent.rb new file mode 100644 index 0000000000..e8fb321077 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/nested_with_require_parent.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class NestedWithRequireParent + ModuleFolder::NestedWithRequire +end diff --git a/activesupport/test/autoloading_fixtures/raises_load_error.rb b/activesupport/test/autoloading_fixtures/raises_load_error.rb new file mode 100644 index 0000000000..f97be29b71 --- /dev/null +++ b/activesupport/test/autoloading_fixtures/raises_load_error.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +# raises a load error typical of the dynamic code that manually raises load errors +raise LoadError, "required gem not present kind of error" diff --git a/activesupport/test/benchmarkable_test.rb b/activesupport/test/benchmarkable_test.rb index cb7a69cccf..59a71d99be 100644 --- a/activesupport/test/benchmarkable_test.rb +++ b/activesupport/test/benchmarkable_test.rb @@ -59,13 +59,13 @@ class BenchmarkableTest < ActiveSupport::TestCase def test_within_level logger.level = ActiveSupport::Logger::DEBUG - benchmark("included_debug_run", level: :debug) {} + benchmark("included_debug_run", level: :debug) { } assert_last_logged "included_debug_run" end def test_outside_level logger.level = ActiveSupport::Logger::ERROR - benchmark("skipped_debug_run", level: :debug) {} + benchmark("skipped_debug_run", level: :debug) { } assert_no_match(/skipped_debug_run/, buffer.last) ensure logger.level = ActiveSupport::Logger::DEBUG diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb index 181113e70a..7dfa8a62bd 100644 --- a/activesupport/test/broadcast_logger_test.rb +++ b/activesupport/test/broadcast_logger_test.rb @@ -114,7 +114,17 @@ module ActiveSupport assert_equal [[::Logger::FATAL, "seen", nil]], log2.adds end + test "Including top constant LoggerSilence is deprecated" do + assert_deprecated("Please use `ActiveSupport::LoggerSilence`") do + Class.new(CustomLogger) do + include ::LoggerSilence + end + end + end + class CustomLogger + include ActiveSupport::LoggerSilence + attr_reader :adds, :closed, :chevrons attr_accessor :level, :progname, :formatter, :local_level @@ -166,7 +176,6 @@ module ActiveSupport end class FakeLogger < CustomLogger - include LoggerSilence end end end diff --git a/activesupport/test/cache/behaviors/cache_instrumentation_behavior.rb b/activesupport/test/cache/behaviors/cache_instrumentation_behavior.rb index 4e8ff60eb3..a4abdd37b9 100644 --- a/activesupport/test/cache/behaviors/cache_instrumentation_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_instrumentation_behavior.rb @@ -2,7 +2,7 @@ module CacheInstrumentationBehavior def test_fetch_multi_uses_write_multi_entries_store_provider_interface - assert_called_with(@cache, :write_multi_entries) do + assert_called(@cache, :write_multi_entries) do @cache.fetch_multi "a", "b", "c" do |key| key * 2 end diff --git a/activesupport/test/cache/behaviors/cache_store_behavior.rb b/activesupport/test/cache/behaviors/cache_store_behavior.rb index f9153ffe2a..a696760bb2 100644 --- a/activesupport/test/cache/behaviors/cache_store_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_store_behavior.rb @@ -52,6 +52,13 @@ module CacheStoreBehavior end end + def test_fetch_cache_miss_with_skip_nil + assert_not_called(@cache, :write) do + assert_nil @cache.fetch("foo", skip_nil: true) { nil } + assert_equal false, @cache.exist?("foo") + end + end + def test_fetch_with_forced_cache_miss_with_block @cache.write("foo", "bar") assert_equal "foo_bar", @cache.fetch("foo", force: true) { "foo_bar" } @@ -123,7 +130,7 @@ module CacheStoreBehavior assert_equal("fufu", @cache.read("fu")) end - def test_multi_with_objects + def test_fetch_multi_with_objects cache_struct = Struct.new(:cache_key, :title) foo = cache_struct.new("foo", "FOO!") bar = cache_struct.new("bar") @@ -135,13 +142,21 @@ module CacheStoreBehavior assert_equal({ foo => "FOO!", bar => "BAM!" }, values) end + def test_fetch_multi_returns_ordered_names + @cache.write("bam", "BAM") + + values = @cache.fetch_multi("foo", "bar", "bam") { |key| key.upcase } + + assert_equal(%w(foo bar bam), values.keys) + end + def test_fetch_multi_without_block assert_raises(ArgumentError) do @cache.fetch_multi("foo") end end - # Use strings that are guarenteed to compress well, so we can easily tell if + # Use strings that are guaranteed to compress well, so we can easily tell if # the compression kicked in or not. SMALL_STRING = "0" * 100 LARGE_STRING = "0" * 2.kilobytes @@ -283,6 +298,55 @@ module CacheStoreBehavior assert_equal "bar", @cache.read("fu/foo") end + InstanceTest = Struct.new(:name, :id) do + def cache_key + "#{name}/#{id}" + end + + def to_param + "hello" + end + end + + def test_array_with_single_instance_as_cache_key_uses_cache_key_method + test_instance_one = InstanceTest.new("test", 1) + test_instance_two = InstanceTest.new("test", 2) + + @cache.write([test_instance_one], "one") + @cache.write([test_instance_two], "two") + + assert_equal "one", @cache.read([test_instance_one]) + assert_equal "two", @cache.read([test_instance_two]) + end + + def test_array_with_multiple_instances_as_cache_key_uses_cache_key_method + test_instance_one = InstanceTest.new("test", 1) + test_instance_two = InstanceTest.new("test", 2) + test_instance_three = InstanceTest.new("test", 3) + + @cache.write([test_instance_one, test_instance_three], "one") + @cache.write([test_instance_two, test_instance_three], "two") + + assert_equal "one", @cache.read([test_instance_one, test_instance_three]) + assert_equal "two", @cache.read([test_instance_two, test_instance_three]) + end + + def test_format_of_expanded_key_for_single_instance + test_instance_one = InstanceTest.new("test", 1) + + expanded_key = @cache.send(:expanded_key, test_instance_one) + + assert_equal expanded_key, test_instance_one.cache_key + end + + def test_format_of_expanded_key_for_single_instance_in_array + test_instance_one = InstanceTest.new("test", 1) + + expanded_key = @cache.send(:expanded_key, [test_instance_one]) + + assert_equal expanded_key, test_instance_one.cache_key + end + def test_hash_as_cache_key @cache.write({ foo: 1, fu: 2 }, "bar") assert_equal "bar", @cache.read("foo=1/fu=2") @@ -312,7 +376,7 @@ module CacheStoreBehavior end def test_original_store_objects_should_not_be_immutable - bar = "bar".dup + bar = +"bar" @cache.write("foo", bar) assert_nothing_raised { bar.gsub!(/.*/, "baz") } end @@ -417,7 +481,7 @@ module CacheStoreBehavior @events << ActiveSupport::Notifications::Event.new(*args) end assert @cache.write(key, "1", raw: true) - assert @cache.fetch(key) {} + assert @cache.fetch(key) { } assert_equal 1, @events.length assert_equal "cache_read.active_support", @events[0].name assert_equal :fetch, @events[0].payload[:super_operation] @@ -431,7 +495,7 @@ module CacheStoreBehavior ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args| @events << ActiveSupport::Notifications::Event.new(*args) end - assert_not @cache.fetch("bad_key") {} + assert_not @cache.fetch("bad_key") { } assert_equal 3, @events.length assert_equal "cache_read.active_support", @events[0].name assert_equal "cache_generate.active_support", @events[1].name diff --git a/activesupport/test/cache/behaviors/connection_pool_behavior.rb b/activesupport/test/cache/behaviors/connection_pool_behavior.rb index 4d1901a173..aed04d07d4 100644 --- a/activesupport/test/cache/behaviors/connection_pool_behavior.rb +++ b/activesupport/test/cache/behaviors/connection_pool_behavior.rb @@ -7,24 +7,22 @@ module ConnectionPoolBehavior threads = [] emulating_latency do - begin - cache = ActiveSupport::Cache.lookup_store(store, { pool_size: 2, pool_timeout: 1 }.merge(store_options)) - cache.clear - - assert_raises Timeout::Error do - # One of the three threads will fail in 1 second because our pool size - # is only two. - 3.times do - threads << Thread.new do - cache.read("latency") - end + cache = ActiveSupport::Cache.lookup_store(*store, { pool_size: 2, pool_timeout: 1 }.merge(store_options)) + cache.clear + + assert_raises Timeout::Error do + # One of the three threads will fail in 1 second because our pool size + # is only two. + 3.times do + threads << Thread.new do + cache.read("latency") end - - threads.each(&:join) end - ensure - threads.each(&:kill) + + threads.each(&:join) end + ensure + threads.each(&:kill) end ensure Thread.report_on_exception = original_report_on_exception @@ -34,24 +32,22 @@ module ConnectionPoolBehavior threads = [] emulating_latency do - begin - cache = ActiveSupport::Cache.lookup_store(store, store_options) - cache.clear - - assert_nothing_raised do - # Default connection pool size is 5, assuming 10 will make sure that - # the connection pool isn't used at all. - 10.times do - threads << Thread.new do - cache.read("latency") - end + cache = ActiveSupport::Cache.lookup_store(*store, store_options) + cache.clear + + assert_nothing_raised do + # Default connection pool size is 5, assuming 10 will make sure that + # the connection pool isn't used at all. + 10.times do + threads << Thread.new do + cache.read("latency") end - - threads.each(&:join) end - ensure - threads.each(&:kill) + + threads.each(&:join) end + ensure + threads.each(&:kill) end end diff --git a/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb b/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb index da16142496..842400f4a3 100644 --- a/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb +++ b/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb @@ -6,7 +6,7 @@ module EncodedKeyCacheBehavior Encoding.list.each do |encoding| define_method "test_#{encoding.name.underscore}_encoded_values" do - key = "foo".dup.force_encoding(encoding) + key = (+"foo").force_encoding(encoding) assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) @@ -18,7 +18,7 @@ module EncodedKeyCacheBehavior end def test_common_utf8_values - key = "\xC3\xBCmlaut".dup.force_encoding(Encoding::UTF_8) + key = (+"\xC3\xBCmlaut").force_encoding(Encoding::UTF_8) assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) @@ -29,7 +29,7 @@ module EncodedKeyCacheBehavior end def test_retains_encoding - key = "\xC3\xBCmlaut".dup.force_encoding(Encoding::UTF_8) + key = (+"\xC3\xBCmlaut").force_encoding(Encoding::UTF_8) assert @cache.write(key, "1", raw: true) assert_equal Encoding::UTF_8, key.encoding end diff --git a/activesupport/test/cache/cache_key_test.rb b/activesupport/test/cache/cache_key_test.rb index 84e656f504..c2240d03c2 100644 --- a/activesupport/test/cache/cache_key_test.rb +++ b/activesupport/test/cache/cache_key_test.rb @@ -47,7 +47,7 @@ class CacheKeyTest < ActiveSupport::TestCase end def test_expand_cache_key_respond_to_cache_key - key = "foo".dup + key = +"foo" def key.cache_key :foo_key end @@ -55,7 +55,7 @@ class CacheKeyTest < ActiveSupport::TestCase end def test_expand_cache_key_array_with_something_that_responds_to_cache_key - key = "foo".dup + key = +"foo" def key.cache_key :foo_key end diff --git a/activesupport/test/cache/local_cache_middleware_test.rb b/activesupport/test/cache/local_cache_middleware_test.rb index e59fae0b4c..e46fa59784 100644 --- a/activesupport/test/cache/local_cache_middleware_test.rb +++ b/activesupport/test/cache/local_cache_middleware_test.rb @@ -17,7 +17,7 @@ module ActiveSupport }) _, _, body = middleware.call({}) assert LocalCacheRegistry.cache_for(key), "should still have a cache" - body.each {} + body.each { } assert LocalCacheRegistry.cache_for(key), "should still have a cache" body.close assert_nil LocalCacheRegistry.cache_for(key) diff --git a/activesupport/test/cache/stores/file_store_test.rb b/activesupport/test/cache/stores/file_store_test.rb index f6855bb308..0364d9ab64 100644 --- a/activesupport/test/cache/stores/file_store_test.rb +++ b/activesupport/test/cache/stores/file_store_test.rb @@ -101,7 +101,7 @@ class FileStoreTest < ActiveSupport::TestCase end assert File.exist?(cache_dir), "Parent of top level cache dir was deleted!" assert File.exist?(sub_cache_dir), "Top level cache dir was deleted!" - assert_empty Dir.entries(sub_cache_dir).reject { |f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f) } + assert_empty Dir.children(sub_cache_dir) end def test_log_exception_when_cache_read_fails diff --git a/activesupport/test/cache/stores/mem_cache_store_test.rb b/activesupport/test/cache/stores/mem_cache_store_test.rb index f426a37c66..0e472f5a1a 100644 --- a/activesupport/test/cache/stores/mem_cache_store_test.rb +++ b/activesupport/test/cache/stores/mem_cache_store_test.rb @@ -25,8 +25,9 @@ end class MemCacheStoreTest < ActiveSupport::TestCase begin - ss = Dalli::Client.new("localhost:11211").stats - raise Dalli::DalliError unless ss["localhost:11211"] + servers = ENV["MEMCACHE_SERVERS"] || "localhost:11211" + ss = Dalli::Client.new(servers).stats + raise Dalli::DalliError unless ss[servers] MEMCACHE_UP = true rescue Dalli::DalliError @@ -37,8 +38,8 @@ class MemCacheStoreTest < ActiveSupport::TestCase def setup skip "memcache server is not up" unless MEMCACHE_UP - @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, expires_in: 60) - @peek = ActiveSupport::Cache.lookup_store(:mem_cache_store) + @cache = ActiveSupport::Cache.lookup_store(*store, expires_in: 60) + @peek = ActiveSupport::Cache.lookup_store(*store) @data = @cache.instance_variable_get(:@data) @cache.clear @cache.silence! @@ -56,21 +57,21 @@ class MemCacheStoreTest < ActiveSupport::TestCase include FailureSafetyBehavior def test_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear cache.write("foo", 2) assert_equal "2", cache.read("foo") end def test_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear cache.write("foo", Marshal.dump([])) assert_equal [], cache.read("foo") end def test_local_cache_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", 2) @@ -79,7 +80,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_increment_expires_in - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear assert_called_with cache.instance_variable_get(:@data), :incr, [ "foo", 1, 60 ] do cache.increment("foo", 1, expires_in: 60) @@ -87,7 +88,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_decrement_expires_in - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear assert_called_with cache.instance_variable_get(:@data), :decr, [ "foo", 1, 60 ] do cache.decrement("foo", 1, expires_in: 60) @@ -95,7 +96,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_local_cache_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache = ActiveSupport::Cache.lookup_store(*store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", Marshal.dump([])) @@ -114,7 +115,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase private def store - :mem_cache_store + [:mem_cache_store, ENV["MEMCACHE_SERVERS"] || "localhost:11211"] end def emulating_latency diff --git a/activesupport/test/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb index 3b873de383..1d87f74347 100644 --- a/activesupport/test/cache/stores/redis_cache_store_test.rb +++ b/activesupport/test/cache/stores/redis_cache_store_test.rb @@ -103,9 +103,7 @@ module ActiveSupport::Cache::RedisCacheStoreTests private def build(**kwargs) - ActiveSupport::Cache::RedisCacheStore.new(driver: DRIVER, **kwargs).tap do |cache| - cache.redis - end + ActiveSupport::Cache::RedisCacheStore.new(driver: DRIVER, **kwargs).tap(&:redis) end end @@ -189,7 +187,7 @@ module ActiveSupport::Cache::RedisCacheStoreTests private def store - :redis_cache_store + [:redis_cache_store] end def emulating_latency @@ -206,7 +204,7 @@ module ActiveSupport::Cache::RedisCacheStoreTests class RedisDistributedConnectionPoolBehaviourTest < ConnectionPoolBehaviourTest private def store_options - { url: %w[ redis://localhost:6379/0 redis://localhost:6379/0 ] } + { url: [ENV["REDIS_URL"] || "redis://localhost:6379/0"] * 2 } end end diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 5c9a3b29e7..79098b2a7d 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -31,7 +31,7 @@ module CallbacksTest def callback_object(callback_method) klass = Class.new - klass.send(:define_method, callback_method) do |model| + klass.define_method(callback_method) do |model| model.history << [:"#{callback_method}_save", :object] end klass.new @@ -953,7 +953,7 @@ module CallbacksTest def test_proc_arity_2 assert_raises(ArgumentError) do - klass = build_class(->(x, y) {}) + klass = build_class(->(x, y) { }) klass.new.run end end @@ -1032,7 +1032,7 @@ module CallbacksTest def test_proc_arity2 assert_raises(ArgumentError) do - object = build_class(->(a, b) {}).new + object = build_class(->(a, b) { }).new object.run end end diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index 1b44c7c9bf..a0a7056952 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -74,3 +74,43 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase assert_equal [ "/class.rb" ], @bc.clean([ "/mongrel/class.rb" ]) end end + +class BacktraceCleanerDefaultFilterAndSilencerTest < ActiveSupport::TestCase + def setup + @bc = ActiveSupport::BacktraceCleaner.new + end + + test "should format installed gems correctly" do + backtrace = [ "#{Gem.default_dir}/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @bc.clean(backtrace, :all) + assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] + end + + test "should format installed gems not in Gem.default_dir correctly" do + target_dir = Gem.path.detect { |p| p != Gem.default_dir } + # skip this test if default_dir is the only directory on Gem.path + if target_dir + backtrace = [ "#{target_dir}/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @bc.clean(backtrace, :all) + assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] + end + end + + test "should format gems installed by bundler" do + backtrace = [ "#{Gem.default_dir}/bundler/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @bc.clean(backtrace, :all) + assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] + end + + test "should silence gems from the backtrace" do + backtrace = [ "#{Gem.path[0]}/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @bc.clean(backtrace) + assert_empty result + end + + test "should silence stdlib" do + backtrace = ["#{RbConfig::CONFIG["rubylibdir"]}/lib/foo.rb"] + result = @bc.clean(backtrace) + assert_empty result + end +end diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 98d8f3ee0d..4b3cfcd1d2 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -128,4 +128,12 @@ class ConcernTest < ActiveSupport::TestCase end end end + + def test_no_raise_on_same_included_call + assert_nothing_raised do + 2.times do + load File.expand_path("../fixtures/concern/some_concern.rb", __FILE__) + end + end + end end diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 2c6145940b..cdb8441b81 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -112,6 +112,16 @@ module ConstantizeTestCases assert_nil yield("A::Object::B") assert_nil yield("A::Object::Object::Object::B") + with_autoloading_fixtures do + assert_nil yield("Em") + end + + assert_raises(LoadError) do + with_autoloading_fixtures do + yield("RaisesLoadError") + end + end + assert_raises(NameError) do with_autoloading_fixtures do yield("RaisesNameError") diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index 8c217023cf..427b058925 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -32,6 +32,18 @@ class AccessTest < ActiveSupport::TestCase assert_equal array[-2], array.second_to_last end + def test_including + assert_equal [1, 2, 3, 4, 5], [1, 2, 4].including(3, 5).sort + assert_equal [1, 2, 3, 4, 5], [1, 2, 4].including([3, 5]).sort + assert_equal [[0, 1], [1, 0]], [[0, 1]].including([[1, 0]]) + end + + def test_excluding + assert_equal [1, 2, 4], [1, 2, 3, 4, 5].excluding(3, 5) + assert_equal [1, 2, 4], [1, 2, 3, 4, 5].excluding([3, 5]) + assert_equal [[0, 1]], [[0, 1], [1, 0]].excluding([[1, 0]]) + end + def test_without assert_equal [1, 2, 4], [1, 2, 3, 4, 5].without(3, 5) end diff --git a/activesupport/test/core_ext/array/extract_test.rb b/activesupport/test/core_ext/array/extract_test.rb new file mode 100644 index 0000000000..f26e055033 --- /dev/null +++ b/activesupport/test/core_ext/array/extract_test.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/core_ext/array" + +class ExtractTest < ActiveSupport::TestCase + def test_extract + numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + array_id = numbers.object_id + + odd_numbers = numbers.extract!(&:odd?) + + assert_equal [1, 3, 5, 7, 9], odd_numbers + assert_equal [0, 2, 4, 6, 8], numbers + assert_equal array_id, numbers.object_id + end + + def test_extract_without_block + numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + array_id = numbers.object_id + + extract_enumerator = numbers.extract! + + assert_instance_of Enumerator, extract_enumerator + assert_equal numbers.size, extract_enumerator.size + + odd_numbers = extract_enumerator.each(&:odd?) + + assert_equal [1, 3, 5, 7, 9], odd_numbers + assert_equal [0, 2, 4, 6, 8], numbers + assert_equal array_id, numbers.object_id + end + + def test_extract_on_empty_array + empty_array = [] + array_id = empty_array.object_id + + new_empty_array = empty_array.extract! { } + + assert_equal [], new_empty_array + assert_equal [], empty_array + assert_equal array_id, empty_array.object_id + end +end diff --git a/activesupport/test/core_ext/array/prepend_append_test.rb b/activesupport/test/core_ext/array/prepend_append_test.rb index c34acd66ad..8573dbd5a6 100644 --- a/activesupport/test/core_ext/array/prepend_append_test.rb +++ b/activesupport/test/core_ext/array/prepend_append_test.rb @@ -1,14 +1,11 @@ # frozen_string_literal: true 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) + def test_requiring_prepend_and_append_is_deprecated + assert_deprecated do + require "active_support/core_ext/array/prepend_and_append" + end end end diff --git a/activesupport/test/core_ext/date_and_time_compatibility_test.rb b/activesupport/test/core_ext/date_and_time_compatibility_test.rb index 266829a452..58a24b60b6 100644 --- a/activesupport/test/core_ext/date_and_time_compatibility_test.rb +++ b/activesupport/test/core_ext/date_and_time_compatibility_test.rb @@ -248,7 +248,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_string_to_time_frozen_preserves_timezone with_preserve_timezone(true) do with_env_tz "US/Eastern" do - source = "2016-04-23T15:11:12+01:00".freeze + source = "2016-04-23T15:11:12+01:00" time = source.to_time assert_instance_of Time, time @@ -262,7 +262,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_string_to_time_frozen_does_not_preserve_time_zone with_preserve_timezone(false) do with_env_tz "US/Eastern" do - source = "2016-04-23T15:11:12+01:00".freeze + source = "2016-04-23T15:11:12+01:00" time = source.to_time assert_instance_of Time, time diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 894fb80cba..f9f6b21c9b 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -152,8 +152,8 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2005, 2, 22, 11, 10, 10), DateTime.civil(2005, 2, 22, 10, 10, 10).since(3600) assert_equal DateTime.civil(2005, 2, 24, 10, 10, 10), DateTime.civil(2005, 2, 22, 10, 10, 10).since(86400 * 2) assert_equal DateTime.civil(2005, 2, 24, 11, 10, 35), DateTime.civil(2005, 2, 22, 10, 10, 10).since(86400 * 2 + 3600 + 25) - assert_equal DateTime.civil(2005, 2, 22, 10, 10, 11), DateTime.civil(2005, 2, 22, 10, 10, 10).since(1.333) - assert_equal DateTime.civil(2005, 2, 22, 10, 10, 12), DateTime.civil(2005, 2, 22, 10, 10, 10).since(1.667) + assert_not_equal DateTime.civil(2005, 2, 22, 10, 10, 11), DateTime.civil(2005, 2, 22, 10, 10, 10).since(1.333) + assert_not_equal DateTime.civil(2005, 2, 22, 10, 10, 12), DateTime.civil(2005, 2, 22, 10, 10, 10).since(1.667) end def test_change diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index b63464a36a..381b5a1f32 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -217,11 +217,18 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal false, GenericEnumerable.new([ 1 ]).exclude?(1) end + def test_excluding + assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).excluding(3, 5) + assert_equal [3, 4, 5], GenericEnumerable.new((1..5).to_a).excluding([1, 2]) + assert_equal [[0, 1]], GenericEnumerable.new([[0, 1], [1, 0]]).excluding([[1, 0]]) + assert_equal [1, 2, 4], (1..5).to_a.excluding(3, 5) + assert_equal [1, 2, 4], (1..5).to_set.excluding(3, 5) + assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.excluding(:bar)) + end + def test_without assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).without(3, 5) - assert_equal [1, 2, 4], (1..5).to_a.without(3, 5) - assert_equal [1, 2, 4], (1..5).to_set.without(3, 5) - assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.without(:bar)) + assert_equal [3, 4, 5], GenericEnumerable.new((1..5).to_a).without([1, 2]) end def test_pluck diff --git a/activesupport/test/core_ext/file_test.rb b/activesupport/test/core_ext/file_test.rb index 9c97700e5d..186c863f91 100644 --- a/activesupport/test/core_ext/file_test.rb +++ b/activesupport/test/core_ext/file_test.rb @@ -59,6 +59,20 @@ class AtomicWriteTest < ActiveSupport::TestCase File.unlink(file_name) rescue nil end + def test_atomic_write_preserves_file_permissions_same_directory + Dir.mktmpdir do |temp_dir| + File.chmod 0700, temp_dir + + probed_permissions = File.probe_stat_in(temp_dir).mode.to_s(8) + + File.atomic_write(File.join(temp_dir, file_name), &:close) + + actual_permissions = File.stat(File.join(temp_dir, file_name)).mode.to_s(8) + + assert_equal actual_permissions, probed_permissions + end + end + def test_atomic_write_returns_result_from_yielded_block block_return_value = File.atomic_write(file_name, Dir.pwd) do |file| "Hello world!" diff --git a/activesupport/test/core_ext/hash/transform_keys_test.rb b/activesupport/test/core_ext/hash/transform_keys_test.rb deleted file mode 100644 index b9e41f7b25..0000000000 --- a/activesupport/test/core_ext/hash/transform_keys_test.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -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 a sized Enumerator if no block is given" do - original = { a: "a", b: "b" } - enumerator = original.transform_keys - assert_equal original.size, enumerator.size - assert_equal Enumerator, enumerator.class - end - - test "transform_keys! returns a sized Enumerator if no block is given" do - original = { a: "a", b: "b" } - enumerator = original.transform_keys! - assert_equal original.size, enumerator.size - 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 - - test "transform_keys! is chainable with Enumerable methods" do - original = { a: "a", b: "b" } - original.transform_keys!.with_index { |k, i| [k, i].join.to_sym } - assert_equal({ a0: "a", b1: "b" }, original) - end - - test "transform_keys returns a Hash instance when self is inherited from Hash" do - class HashDescendant < ::Hash - def initialize(elements = nil) - super(elements) - (elements || {}).each_pair { |key, value| self[key] = value } - end - end - - original = HashDescendant.new(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) - assert_equal(::Hash, mapped.class) - end -end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index f4f0dd6b31..8572d56722 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -31,10 +31,10 @@ class HashExtTest < ActiveSupport::TestCase def test_methods h = {} - assert_respond_to h, :transform_keys - assert_respond_to h, :transform_keys! assert_respond_to h, :deep_transform_keys assert_respond_to h, :deep_transform_keys! + assert_respond_to h, :deep_transform_values + assert_respond_to h, :deep_transform_values! assert_respond_to h, :symbolize_keys assert_respond_to h, :symbolize_keys! assert_respond_to h, :deep_symbolize_keys @@ -49,18 +49,6 @@ class HashExtTest < ActiveSupport::TestCase assert_respond_to h, :except! end - def test_transform_keys - assert_equal @upcase_strings, @strings.transform_keys { |key| key.to_s.upcase } - assert_equal @upcase_strings, @symbols.transform_keys { |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.transform_keys { |key| key.to_s.upcase } - end - - def test_transform_keys_not_mutates - transformed_hash = @mixed.dup - transformed_hash.transform_keys { |key| key.to_s.upcase } - assert_equal @mixed, transformed_hash - end - def test_deep_transform_keys 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 } @@ -76,19 +64,6 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_mixed, transformed_hash end - def test_transform_keys! - assert_equal @upcase_strings, @symbols.dup.transform_keys! { |key| key.to_s.upcase } - assert_equal @upcase_strings, @strings.dup.transform_keys! { |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.dup.transform_keys! { |key| key.to_s.upcase } - end - - def test_transform_keys_with_bang_mutates - transformed_hash = @mixed.dup - transformed_hash.transform_keys! { |key| key.to_s.upcase } - assert_equal @upcase_strings, transformed_hash - assert_equal({ :a => 1, "b" => 2 }, @mixed) - end - def test_deep_transform_keys! 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 } @@ -105,6 +80,31 @@ class HashExtTest < ActiveSupport::TestCase assert_equal({ "a" => { b: { "c" => 3 } } }, @nested_mixed) end + def test_deep_transform_values + assert_equal({ "a" => "1", "b" => "2" }, @strings.deep_transform_values { |value| value.to_s }) + assert_equal({ "a" => { "b" => { "c" => "3" } } }, @nested_strings.deep_transform_values { |value| value.to_s }) + assert_equal({ "a" => [ { "b" => "2" }, { "c" => "3" }, "4" ] }, @string_array_of_hashes.deep_transform_values { |value| value.to_s }) + end + + def test_deep_transform_values_not_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_transform_values { |value| value.to_s } + assert_equal @nested_mixed, transformed_hash + end + + def test_deep_transform_values! + assert_equal({ "a" => "1", "b" => "2" }, @strings.deep_transform_values! { |value| value.to_s }) + assert_equal({ "a" => { "b" => { "c" => "3" } } }, @nested_strings.deep_transform_values! { |value| value.to_s }) + assert_equal({ "a" => [ { "b" => "2" }, { "c" => "3" }, "4" ] }, @string_array_of_hashes.deep_transform_values! { |value| value.to_s }) + end + + def test_deep_transform_values_with_bang_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_transform_values! { |value| value.to_s } + assert_equal({ "a" => { b: { "c" => "3" } } }, transformed_hash) + assert_equal({ "a" => { b: { "c" => 3 } } }, @nested_mixed) + end + def test_symbolize_keys assert_equal @symbols, @symbols.symbolize_keys assert_equal @symbols, @strings.symbolize_keys @@ -337,30 +337,16 @@ class HashExtTest < ActiveSupport::TestCase assert_equal expected, merged end - def test_slice - original = { a: "x", b: "y", c: 10 } - expected = { a: "x", b: "y" } - - # Should return a new hash with only the given keys. - assert_equal expected, original.slice(:a, :b) - assert_not_equal expected, original - end - def test_slice_inplace original = { a: "x", b: "y", c: 10 } - expected = { c: 10 } - - # Should replace the hash with only the given keys. - assert_equal expected, original.slice!(:a, :b) - end + expected_return = { c: 10 } + expected_original = { a: "x", b: "y" } - def test_slice_with_an_array_key - original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } - expected = { [:a, :b] => "an array key", :c => 10 } + # Should return a hash containing the removed key/value pairs. + assert_equal expected_return, original.slice!(:a, :b) - # Should return a new hash with only the given keys when given an array key. - assert_equal expected, original.slice([:a, :b], :c) - assert_not_equal expected, original + # Should replace the hash with only the given keys. + assert_equal expected_original, original end def test_slice_inplace_with_an_array_key @@ -371,14 +357,6 @@ class HashExtTest < ActiveSupport::TestCase assert_equal expected, original.slice!([:a, :b], :c) end - def test_slice_with_splatted_keys - original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } - expected = { a: "x", b: "y" } - - # Should grab each of the splatted keys. - assert_equal expected, original.slice(*[:a, :b]) - end - def test_slice_bang_does_not_override_default hash = Hash.new(0) hash.update(a: 1, b: 2) @@ -444,7 +422,7 @@ class HashExtTest < ActiveSupport::TestCase original.freeze assert_nothing_raised { original.except(:a) } - assert_raise(frozen_error_class) { original.except!(:a) } + assert_raise(FrozenError) { original.except!(:a) } end def test_except_does_not_delete_values_in_original diff --git a/activesupport/test/core_ext/load_error_test.rb b/activesupport/test/core_ext/load_error_test.rb index 126aa51cb4..6d3726e407 100644 --- a/activesupport/test/core_ext/load_error_test.rb +++ b/activesupport/test/core_ext/load_error_test.rb @@ -13,10 +13,9 @@ class TestLoadError < ActiveSupport::TestCase end def test_path - begin load "nor/this/one.rb" - rescue LoadError => e - assert_equal "nor/this/one.rb", e.path - end + load "nor/this/one.rb" + rescue LoadError => e + assert_equal "nor/this/one.rb", e.path end def test_is_missing_with_nil_path diff --git a/activesupport/test/core_ext/module/concerning_test.rb b/activesupport/test/core_ext/module/concerning_test.rb index 374114c11b..38fd60463d 100644 --- a/activesupport/test/core_ext/module/concerning_test.rb +++ b/activesupport/test/core_ext/module/concerning_test.rb @@ -5,7 +5,7 @@ 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) {} } + klass = Class.new { concerning(:Foo) { } } assert_includes klass.ancestors, klass::Foo, klass.ancestors.inspect end end diff --git a/activesupport/test/core_ext/module/introspection_test.rb b/activesupport/test/core_ext/module/introspection_test.rb index 76d3012239..d8409d5e44 100644 --- a/activesupport/test/core_ext/module/introspection_test.rb +++ b/activesupport/test/core_ext/module/introspection_test.rb @@ -15,25 +15,43 @@ module ParentA end class IntrospectionTest < ActiveSupport::TestCase + def test_module_parent_name + assert_equal "ParentA", ParentA::B.module_parent_name + assert_equal "ParentA::B", ParentA::B::C.module_parent_name + assert_nil ParentA.module_parent_name + end + + def test_module_parent_name_when_frozen + assert_equal "ParentA", ParentA::FrozenB.module_parent_name + assert_equal "ParentA::B", ParentA::B::FrozenC.module_parent_name + end + def test_parent_name - assert_equal "ParentA", ParentA::B.parent_name - assert_equal "ParentA::B", ParentA::B::C.parent_name - assert_nil ParentA.parent_name + assert_deprecated do + assert_equal "ParentA", ParentA::B.parent_name + end end - def test_parent_name_when_frozen - assert_equal "ParentA", ParentA::FrozenB.parent_name - assert_equal "ParentA::B", ParentA::B::FrozenC.parent_name + def test_module_parent + assert_equal ParentA::B, ParentA::B::C.module_parent + assert_equal ParentA, ParentA::B.module_parent + assert_equal Object, ParentA.module_parent end def test_parent - assert_equal ParentA::B, ParentA::B::C.parent - assert_equal ParentA, ParentA::B.parent - assert_equal Object, ParentA.parent + assert_deprecated do + assert_equal ParentA, ParentA::B.parent + end + end + + def test_module_parents + assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.module_parents + assert_equal [ParentA, Object], ParentA::B.module_parents end def test_parents - assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.parents - assert_equal [ParentA, Object], ParentA::B.parents + assert_deprecated do + assert_equal [ParentA, Object], ParentA::B.parents + end end end diff --git a/activesupport/test/core_ext/module/reachable_test.rb b/activesupport/test/core_ext/module/reachable_test.rb deleted file mode 100644 index f356d46957..0000000000 --- a/activesupport/test/core_ext/module/reachable_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require "abstract_unit" -require "active_support/core_ext/module/reachable" - -class AnonymousTest < ActiveSupport::TestCase - test "an anonymous class or module is not reachable" do - assert_deprecated do - assert_not_predicate Module.new, :reachable? - assert_not_predicate Class.new, :reachable? - end - end - - test "ordinary named classes or modules are reachable" do - assert_deprecated do - assert_predicate Kernel, :reachable? - assert_predicate Object, :reachable? - end - end - - test "a named class or module whose constant has gone is not reachable" do - c = eval "class C; end; C" - m = eval "module M; end; M" - - self.class.send(:remove_const, :C) - self.class.send(:remove_const, :M) - - assert_deprecated do - assert_not_predicate c, :reachable? - assert_not_predicate m, :reachable? - end - end - - test "a named class or module whose constants store different objects are not reachable" do - c = eval "class C; end; C" - m = eval "module M; end; M" - - self.class.send(:remove_const, :C) - self.class.send(:remove_const, :M) - - eval "class C; end" - eval "module M; end" - - assert_deprecated do - assert_predicate C, :reachable? - assert_predicate M, :reachable? - assert_not_predicate c, :reachable? - assert_not_predicate m, :reachable? - end - end -end diff --git a/activesupport/test/core_ext/object/instance_variables_test.rb b/activesupport/test/core_ext/object/instance_variables_test.rb index a3d8daab5b..9052d209a3 100644 --- a/activesupport/test/core_ext/object/instance_variables_test.rb +++ b/activesupport/test/core_ext/object/instance_variables_test.rb @@ -19,15 +19,15 @@ class ObjectInstanceVariableTest < ActiveSupport::TestCase end def test_instance_exec_passes_arguments_to_block - assert_equal %w(hello goodbye), "hello".dup.instance_exec("goodbye") { |v| [self, v] } + 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] } + assert_equal %w(olleh goodbye), "hello".instance_exec("goodbye") { |v| [reverse, v] } end def test_instance_exec_nested - assert_equal %w(goodbye olleh bar), "hello".dup.instance_exec("goodbye") { |arg| + 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/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index b0b7ef0913..561dadbbcf 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -88,7 +88,7 @@ class ToQueryTest < ActiveSupport::TestCase } expected = "foo[contents][][name]=gorby&foo[contents][][id]=123&foo[contents][][name]=puff&foo[contents][][d]=true" - assert_equal expected, URI.decode(params.to_query) + assert_equal expected, URI.decode_www_form_component(params.to_query) end private diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index 7c7a78f461..16d6a4c2f2 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -57,7 +57,7 @@ class RangeTest < ActiveSupport::TestCase end def test_should_include_other_with_exclusive_end - assert((1..10).include?(1...10)) + assert((1..10).include?(1...11)) end def test_should_compare_identical_inclusive @@ -69,7 +69,7 @@ class RangeTest < ActiveSupport::TestCase end def test_should_compare_other_with_exclusive_end - assert((1..10) === (1...10)) + assert((1..10) === (1...11)) end def test_exclusive_end_should_not_include_identical_with_inclusive_end @@ -93,6 +93,10 @@ class RangeTest < ActiveSupport::TestCase assert range.method(:include?) != range.method(:cover?) end + def test_should_cover_other_with_exclusive_end + assert((1..10).cover?(1...11)) + end + def test_overlaps_on_time time_range_1 = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30) time_range_2 = Time.utc(2005, 12, 10, 17, 00)..Time.utc(2005, 12, 10, 18, 00) @@ -108,14 +112,14 @@ class RangeTest < ActiveSupport::TestCase 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 {} + ((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) {} + ((twz - 1.hour)..twz).step(1) { } end end @@ -131,11 +135,11 @@ class RangeTest < ActiveSupport::TestCase def test_date_time_with_each datetime = DateTime.now - assert(((datetime - 1.hour)..datetime).each {}) + assert(((datetime - 1.hour)..datetime).each { }) end def test_date_time_with_step datetime = DateTime.now - assert(((datetime - 1.hour)..datetime).step(1) {}) + assert(((datetime - 1.hour)..datetime).step(1) { }) end end diff --git a/activesupport/test/core_ext/secure_random_test.rb b/activesupport/test/core_ext/secure_random_test.rb index 7067fb524c..4b73233971 100644 --- a/activesupport/test/core_ext/secure_random_test.rb +++ b/activesupport/test/core_ext/secure_random_test.rb @@ -19,4 +19,24 @@ class SecureRandomTest < ActiveSupport::TestCase assert_not_equal s1, s2 assert_equal 24, s1.length end + + def test_base36 + s1 = SecureRandom.base36 + s2 = SecureRandom.base36 + + assert_not_equal s1, s2 + assert_equal 16, s1.length + assert_match(/^[a-z0-9]+$/, s1) + assert_match(/^[a-z0-9]+$/, s2) + end + + def test_base36_with_length + s1 = SecureRandom.base36(24) + s2 = SecureRandom.base36(24) + + assert_not_equal s1, s2 + assert_equal 24, s1.length + assert_match(/^[a-z0-9]+$/, s1) + assert_match(/^[a-z0-9]+$/, s2) + end end diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index b8de16cc5e..4ffa33aa61 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -25,7 +25,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_strip_heredoc_on_a_frozen_string - assert "".freeze.strip_heredoc.frozen? + assert "".strip_heredoc.frozen? end def test_strip_heredoc_on_a_string_with_no_lines @@ -206,6 +206,12 @@ class StringInflectionsTest < ActiveSupport::TestCase end end + def test_parameterize_with_locale + word = "Fünf autos" + I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } }) + assert_equal("fuenf-autos", word.parameterize(locale: :de)) + end + def test_humanize UnderscoreToHuman.each do |underscore, human| assert_equal(human, underscore.humanize) @@ -245,8 +251,8 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_string_squish - original = %{\u205f\u3000 A string surrounded by various unicode spaces, - with tabs(\t\t), newlines(\n\n), unicode nextlines(\u0085\u0085) and many spaces( ). \u00a0\u2007}.dup + original = +%{\u205f\u3000 A string surrounded by various unicode spaces, + with tabs(\t\t), newlines(\n\n), unicode nextlines(\u0085\u0085) and many spaces( ). \u00a0\u2007} expected = "A string surrounded by various unicode spaces, " \ "with tabs( ), newlines( ), unicode nextlines( ) and many spaces( )." @@ -378,8 +384,8 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_truncate_multibyte - assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".dup.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".dup.force_encoding(Encoding::UTF_8).truncate(10) + 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) end def test_truncate_should_not_be_html_safe @@ -400,7 +406,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_remove! - original = "This is a very good day to die".dup + original = +"This is a very good day to die" assert_equal "This is a good day to die", original.remove!(" very") assert_equal "This is a good day to die", original assert_equal "This is a good day", original.remove!(" to ", /die/) @@ -469,6 +475,15 @@ class StringAccessTest < ActiveSupport::TestCase assert_not_same different_string, string end + test "#first with negative Integer is deprecated" do + string = "hello" + message = "Calling String#first with a negative integer limit " \ + "will raise an ArgumentError in Rails 6.1." + assert_deprecated(message) do + string.first(-1) + end + end + test "#last returns the last character" do assert_equal "o", "hello".last assert_equal "x", "x".last @@ -487,6 +502,15 @@ class StringAccessTest < ActiveSupport::TestCase assert_not_same different_string, string end + test "#last with negative Integer is deprecated" do + string = "hello" + message = "Calling String#last with a negative integer limit " \ + "will raise an ArgumentError in Rails 6.1." + assert_deprecated(message) do + string.last(-1) + end + end + test "access returns a real string" do hash = {} hash["h"] = true @@ -733,7 +757,7 @@ end class OutputSafetyTest < ActiveSupport::TestCase def setup - @string = "hello".dup + @string = +"hello" @object = Class.new(Object) do def to_s "other" @@ -809,7 +833,7 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "Concatting safe onto unsafe yields unsafe" do - @other_string = "other".dup + @other_string = +"other" string = @string.html_safe @other_string.concat(string) @@ -832,7 +856,7 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "Concatting safe onto unsafe with << yields unsafe" do - @other_string = "other".dup + @other_string = +"other" string = @string.html_safe @other_string << string @@ -888,7 +912,55 @@ class OutputSafetyTest < ActiveSupport::TestCase test "Concatting an integer to safe always yields safe" do string = @string.html_safe string = string.concat(13) - assert_equal "hello".dup.concat(13), string + assert_equal (+"hello").concat(13), string + assert_predicate string, :html_safe? + end + + test "Inserting safe into safe yields safe" do + string = "foo".html_safe + string.insert(0, "<b>".html_safe) + + assert_equal "<b>foo", string + assert_predicate string, :html_safe? + end + + test "Inserting unsafe into safe yields escaped safe" do + string = "foo".html_safe + string.insert(0, "<b>") + + assert_equal "<b>foo", string + assert_predicate string, :html_safe? + end + + test "Replacing safe with safe yields safe" do + string = "foo".html_safe + string.replace("<b>".html_safe) + + assert_equal "<b>", string + assert_predicate string, :html_safe? + end + + test "Replacing safe with unsafe yields escaped safe" do + string = "foo".html_safe + string.replace("<b>") + + assert_equal "<b>", string + assert_predicate string, :html_safe? + end + + test "Replacing index of safe with safe yields safe" do + string = "foo".html_safe + string[0] = "<b>".html_safe + + assert_equal "<b>oo", string + assert_predicate string, :html_safe? + end + + test "Replacing index of safe with unsafe yields escaped safe" do + string = "foo".html_safe + string[0] = "<b>" + + assert_equal "<b>oo", string assert_predicate string, :html_safe? end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index e1cb22fda8..590b81b770 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -514,6 +514,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase 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) + assert_equal Time.local(999, 10, 4, 15, 15, 10), Time.local(1000, 10, 4, 15, 15, 10).advance(years: -1) + assert_equal Time.local(1000, 10, 4, 15, 15, 10), Time.local(999, 10, 4, 15, 15, 10).advance(years: 1) end def test_last_week @@ -950,39 +952,39 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end class TimeExtMarshalingTest < ActiveSupport::TestCase - def test_marshaling_with_utc_instance + def test_marshalling_with_utc_instance t = Time.utc(2000) - unmarshaled = Marshal.load(Marshal.dump(t)) - assert_equal "UTC", unmarshaled.zone - assert_equal t, unmarshaled + unmarshalled = Marshal.load(Marshal.dump(t)) + assert_equal "UTC", unmarshalled.zone + assert_equal t, unmarshalled end - def test_marshaling_with_local_instance + def test_marshalling_with_local_instance t = Time.local(2000) - unmarshaled = Marshal.load(Marshal.dump(t)) - assert_equal t.zone, unmarshaled.zone - assert_equal t, unmarshaled + unmarshalled = Marshal.load(Marshal.dump(t)) + assert_equal t.zone, unmarshalled.zone + assert_equal t, unmarshalled end - def test_marshaling_with_frozen_utc_instance + def test_marshalling_with_frozen_utc_instance t = Time.utc(2000).freeze - unmarshaled = Marshal.load(Marshal.dump(t)) - assert_equal "UTC", unmarshaled.zone - assert_equal t, unmarshaled + unmarshalled = Marshal.load(Marshal.dump(t)) + assert_equal "UTC", unmarshalled.zone + assert_equal t, unmarshalled end - def test_marshaling_with_frozen_local_instance + def test_marshalling_with_frozen_local_instance t = Time.local(2000).freeze - unmarshaled = Marshal.load(Marshal.dump(t)) - assert_equal t.zone, unmarshaled.zone - assert_equal t, unmarshaled + unmarshalled = Marshal.load(Marshal.dump(t)) + assert_equal t.zone, unmarshalled.zone + assert_equal t, unmarshalled end def test_marshalling_preserves_fractional_seconds t = Time.parse("00:00:00.500") - unmarshaled = Marshal.load(Marshal.dump(t)) - assert_equal t.to_f, unmarshaled.to_f - assert_equal t, unmarshaled + unmarshalled = Marshal.load(Marshal.dump(t)) + assert_equal t.to_f, unmarshalled.to_f + assert_equal t, unmarshalled end def test_last_quarter_on_31st diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index e650209268..f6e836e446 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1105,7 +1105,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase def test_use_zone_raises_on_invalid_timezone Time.zone = "Alaska" assert_raise ArgumentError do - Time.use_zone("No such timezone exists") {} + Time.use_zone("No such timezone exists") { } end assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end diff --git a/activesupport/test/current_attributes_test.rb b/activesupport/test/current_attributes_test.rb index 1669f08f68..adbdc646bc 100644 --- a/activesupport/test/current_attributes_test.rb +++ b/activesupport/test/current_attributes_test.rb @@ -3,13 +3,18 @@ require "abstract_unit" class CurrentAttributesTest < ActiveSupport::TestCase - Person = Struct.new(:name, :time_zone) + Person = Struct.new(:id, :name, :time_zone) class Current < ActiveSupport::CurrentAttributes attribute :world, :account, :person, :request delegate :time_zone, to: :person - resets { Time.zone = "UTC" } + before_reset { Session.previous = person.try(:id) } + + resets do + Time.zone = "UTC" + Session.current = nil + end def account=(account) super @@ -19,6 +24,7 @@ class CurrentAttributesTest < ActiveSupport::TestCase def person=(person) super Time.zone = person.try(:time_zone) + Session.current = person.try(:id) end def request @@ -30,9 +36,14 @@ class CurrentAttributesTest < ActiveSupport::TestCase end end + class Session < ActiveSupport::CurrentAttributes + attribute :current, :previous + end + setup do @original_time_zone = Time.zone Current.reset + Session.reset end teardown do @@ -56,16 +67,28 @@ class CurrentAttributesTest < ActiveSupport::TestCase end test "set auxiliary class via overwritten method" do - Current.person = Person.new("David", "Central Time (US & Canada)") + Current.person = Person.new(42, "David", "Central Time (US & Canada)") assert_equal "Central Time (US & Canada)", Time.zone.name + assert_equal 42, Session.current end - test "resets auxiliary class via callback" do - Current.person = Person.new("David", "Central Time (US & Canada)") + test "resets auxiliary classes via callback" do + Current.person = Person.new(42, "David", "Central Time (US & Canada)") assert_equal "Central Time (US & Canada)", Time.zone.name Current.reset assert_equal "UTC", Time.zone.name + assert_nil Session.current + end + + test "set auxiliary class based on current attributes via before callback" do + Current.person = Person.new(42, "David", "Central Time (US & Canada)") + assert_nil Session.previous + assert_equal 42, Session.current + + Current.reset + assert_equal 42, Session.previous + assert_nil Session.current end test "set attribute only via scope" do @@ -92,13 +115,13 @@ class CurrentAttributesTest < ActiveSupport::TestCase end test "delegation" do - Current.person = Person.new("David", "Central Time (US & Canada)") + Current.person = Person.new(42, "David", "Central Time (US & Canada)") assert_equal "Central Time (US & Canada)", Current.time_zone assert_equal "Central Time (US & Canada)", Current.instance.time_zone end test "all methods forward to the instance" do - Current.person = Person.new("David", "Central Time (US & Canada)") + Current.person = Person.new(42, "David", "Central Time (US & Canada)") assert_equal "David, in Central Time (US & Canada)", Current.intro assert_equal "David, in Central Time (US & Canada)", Current.instance.intro end diff --git a/activesupport/test/dependencies/module_folder/lib_class.rb b/activesupport/test/dependencies/module_folder/lib_class.rb new file mode 100644 index 0000000000..c6b52610c1 --- /dev/null +++ b/activesupport/test/dependencies/module_folder/lib_class.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +ConstFromLib = 1 + +module ModuleFolder + class LibClass + end +end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 84cb64a7c2..d4e709137e 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -282,6 +282,32 @@ class DependenciesTest < ActiveSupport::TestCase remove_constants(:ModuleFolder) end + def test_module_with_nested_class_requiring_lib_class + with_autoloading_fixtures do + _ = ModuleFolder::NestedWithRequire # assignment to silence parse-time warning "possibly useless use of :: in void context" + + assert defined?(ModuleFolder::LibClass) + assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ModuleFolder::LibClass") + assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ConstFromLib") + end + ensure + remove_constants(:ModuleFolder) + remove_constants(:ConstFromLib) + end + + def test_module_with_nested_class_and_parent_requiring_lib_class + with_autoloading_fixtures do + _ = NestedWithRequireParent # assignment to silence parse-time warning "possibly useless use of a constant in void context" + + assert defined?(ModuleFolder::LibClass) + assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ModuleFolder::LibClass") + assert_not ActiveSupport::Dependencies.autoloaded_constants.include?("ConstFromLib") + end + ensure + remove_constants(:ModuleFolder) + remove_constants(:ConstFromLib) + end + def test_directories_may_manifest_as_nested_classes with_autoloading_fixtures do assert_kind_of Class, ClassFolder @@ -815,8 +841,8 @@ class DependenciesTest < ActiveSupport::TestCase remove_constants(:C) end - def test_new_contants_in_without_constants - assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) {}) + def test_new_constants_in_without_constants + assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { }) assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k, v| v.empty? } end @@ -892,7 +918,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_new_constants_in_with_illegal_module_name_raises_correct_error assert_raise(NameError) do - ActiveSupport::Dependencies.new_constants_in("Illegal-Name") {} + ActiveSupport::Dependencies.new_constants_in("Illegal-Name") { } end end @@ -1130,3 +1156,52 @@ class DependenciesTest < ActiveSupport::TestCase ActiveSupport::Dependencies.hook! end end + +class DependenciesLogging < ActiveSupport::TestCase + MESSAGE = "message" + + def with_settings(logger, verbose) + original_logger = ActiveSupport::Dependencies.logger + original_verbose = ActiveSupport::Dependencies.verbose + + ActiveSupport::Dependencies.logger = logger + ActiveSupport::Dependencies.verbose = verbose + + yield + ensure + ActiveSupport::Dependencies.logger = original_logger + ActiveSupport::Dependencies.verbose = original_verbose + end + + def fake_logger + Class.new do + def self.debug(message) + message + end + end + end + + test "does not log if the logger is nil and verbose is false" do + with_settings(nil, false) do + assert_nil ActiveSupport::Dependencies.log(MESSAGE) + end + end + + test "does not log if the logger is nil and verbose is true" do + with_settings(nil, true) do + assert_nil ActiveSupport::Dependencies.log(MESSAGE) + end + end + + test "does not log if the logger is set and verbose is false" do + with_settings(fake_logger, false) do + assert_nil ActiveSupport::Dependencies.log(MESSAGE) + end + end + + test "logs if the logger is set and verbose is true" do + with_settings(fake_logger, true) do + assert_equal "autoloading: #{MESSAGE}", ActiveSupport::Dependencies.log(MESSAGE) + end + end +end diff --git a/activesupport/test/deprecation/method_wrappers_test.rb b/activesupport/test/deprecation/method_wrappers_test.rb index 439e117c1d..18729941bc 100644 --- a/activesupport/test/deprecation/method_wrappers_test.rb +++ b/activesupport/test/deprecation/method_wrappers_test.rb @@ -21,6 +21,13 @@ class MethodWrappersTest < ActiveSupport::TestCase end end + def test_deprecate_methods_without_alternate_method + warning = /old_method is deprecated and will be removed from Rails \d.\d./ + ActiveSupport::Deprecation.deprecate_methods(@klass, :old_method) + + assert_deprecated(warning) { assert_equal "abc", @klass.new.old_method } + end + def test_deprecate_methods_warning_default warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method) @@ -55,4 +62,39 @@ class MethodWrappersTest < ActiveSupport::TestCase assert(@klass.private_method_defined?(:old_private_method)) end + + def test_deprecate_class_method + mod = Module.new do + extend self + + def old_method + "abc" + end + end + ActiveSupport::Deprecation.deprecate_methods(mod, old_method: :new_method) + + warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ + assert_deprecated(warning) { assert_equal "abc", mod.old_method } + end + + def test_deprecate_method_when_class_extends_module + mod = Module.new do + def old_method + "abc" + end + end + @klass.extend mod + ActiveSupport::Deprecation.deprecate_methods(mod, old_method: :new_method) + + warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ + assert_deprecated(warning) { assert_equal "abc", @klass.old_method } + end + + def test_method_with_without_deprecation_is_exposed + ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method) + + warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ + assert_deprecated(warning) { assert_equal "abc", @klass.new.old_method_with_deprecation } + assert_equal "abc", @klass.new.old_method_without_deprecation + end end diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb index 105153584d..f25c704586 100644 --- a/activesupport/test/deprecation_test.rb +++ b/activesupport/test/deprecation_test.rb @@ -31,6 +31,9 @@ class Deprecatee def f=(v); end deprecate :f= + deprecate :g + def g; end + module B C = 1 end @@ -425,6 +428,10 @@ class DeprecationTest < ActiveSupport::TestCase end end + def test_deprecate_work_before_define_method + assert_deprecated { @dtc.g } + end + private def deprecator_with_messages klass = Class.new(ActiveSupport::Deprecation) diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb index 2c94c3c56c..f8752688d2 100644 --- a/activesupport/test/descendants_tracker_test_cases.rb +++ b/activesupport/test/descendants_tracker_test_cases.rb @@ -27,6 +27,15 @@ module DescendantsTrackerTestCases assert_equal_sets [], Child2.descendants end + def test_descendants_with_garbage_collected_classes + 1.times do + child_klass = Class.new(Parent) + assert_equal_sets [Child1, Grandchild1, Grandchild2, Child2, child_klass], Parent.descendants + end + GC.start + assert_equal_sets [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants + end + def test_direct_descendants assert_equal_sets [Child1, Child2], Parent.direct_descendants assert_equal_sets [Grandchild1, Grandchild2], Child1.direct_descendants diff --git a/activesupport/test/encrypted_configuration_test.rb b/activesupport/test/encrypted_configuration_test.rb index 93ccf457de..387d6e1c1f 100644 --- a/activesupport/test/encrypted_configuration_test.rb +++ b/activesupport/test/encrypted_configuration_test.rb @@ -42,6 +42,12 @@ class EncryptedConfigurationTest < ActiveSupport::TestCase assert @credentials.something[:good] end + test "reading comment-only configuration" do + @credentials.write("# comment") + + assert_equal @credentials.config, {} + end + test "change configuration by key file" do @credentials.write({ something: { good: true } }.to_yaml) @credentials.change do |config_file| diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index d3af0dbef3..b2d5eb94c2 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -38,7 +38,7 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase FileUtils.touch(tmpfiles) - checker = new_checker(tmpfiles) {} + checker = new_checker(tmpfiles) { } assert_not_predicate checker, :updated? # Pipes used for flow control across fork. @@ -76,6 +76,34 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase Process.wait(pid) end + + test "updated should become true when nonexistent directory is added later" do + Dir.mktmpdir do |dir| + watched_dir = File.join(dir, "app") + unwatched_dir = File.join(dir, "node_modules") + not_exist_watched_dir = File.join(dir, "test") + + Dir.mkdir(watched_dir) + Dir.mkdir(unwatched_dir) + + checker = new_checker([], watched_dir => ".rb", not_exist_watched_dir => ".rb") { } + + FileUtils.touch(File.join(watched_dir, "a.rb")) + wait + assert_predicate checker, :updated? + assert checker.execute_if_updated + + Dir.mkdir(not_exist_watched_dir) + wait + assert_predicate checker, :updated? + assert checker.execute_if_updated + + FileUtils.touch(File.join(unwatched_dir, "a.rb")) + wait + assert_not_predicate checker, :updated? + assert_not checker.execute_if_updated + end + end end class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index af441064dd..3026f002c3 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -23,7 +23,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.to_run { @foo = true } executor.to_complete { result = @foo } - executor.wrap {} + executor.wrap { } assert result end @@ -85,7 +85,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) - executor.wrap {} + executor.wrap { } assert_equal :some_state, supplied_state end @@ -105,7 +105,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) - executor.wrap {} + executor.wrap { } assert_nil supplied_state end @@ -129,7 +129,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) assert_raises(DummyError) do - executor.wrap {} + executor.wrap { } end assert_equal :none, supplied_state @@ -154,7 +154,7 @@ class ExecutorTest < ActiveSupport::TestCase end assert_raises(DummyError) do - executor.wrap {} + executor.wrap { } end assert_equal :some_state, supplied_state @@ -187,7 +187,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook_class.new(:c), outer: true) executor.register_hook(hook_class.new(:d)) - executor.wrap {} + executor.wrap { } assert_equal [:run_c, :run_a, :run_b, :run_d, :complete_a, :complete_b, :complete_d, :complete_c], invoked assert_equal [:state_a, :state_b, :state_d, :state_c], supplied_state @@ -209,9 +209,9 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) before = RubyVM.stat(:class_serial) - executor.wrap {} - executor.wrap {} - executor.wrap {} + executor.wrap { } + executor.wrap { } + executor.wrap { } after = RubyVM.stat(:class_serial) assert_equal before, after diff --git a/activesupport/test/file_update_checker_shared_tests.rb b/activesupport/test/file_update_checker_shared_tests.rb index 72683816b3..84d89fa0a7 100644 --- a/activesupport/test/file_update_checker_shared_tests.rb +++ b/activesupport/test/file_update_checker_shared_tests.rb @@ -186,6 +186,18 @@ module FileUpdateCheckerSharedTests assert_equal 1, i end + test "should execute the block if files change in a watched directory any extensions" do + i = 0 + + checker = new_checker([], tmpdir => []) { i += 1 } + + touch(tmpfile("foo.rb")) + wait + + assert checker.execute_if_updated + assert_equal 1, i + end + test "should execute the block if files change in a watched directory several extensions" do i = 0 diff --git a/activesupport/test/fixtures/concern/some_concern.rb b/activesupport/test/fixtures/concern/some_concern.rb new file mode 100644 index 0000000000..87f660a81e --- /dev/null +++ b/activesupport/test/fixtures/concern/some_concern.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "active_support/concern" + +module SomeConcern + extend ActiveSupport::Concern + + included do + # shouldn't raise when module is loaded more than once + end +end diff --git a/activesupport/test/hash_with_indifferent_access_test.rb b/activesupport/test/hash_with_indifferent_access_test.rb index eebff18ef1..1d6a07ec5f 100644 --- a/activesupport/test/hash_with_indifferent_access_test.rb +++ b/activesupport/test/hash_with_indifferent_access_test.rb @@ -57,6 +57,13 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys end + def test_to_options_for_hash_with_indifferent_access + assert_instance_of Hash, @symbols.with_indifferent_access.to_options + assert_equal @symbols, @symbols.with_indifferent_access.to_options + assert_equal @symbols, @strings.with_indifferent_access.to_options + assert_equal @symbols, @mixed.with_indifferent_access.to_options + end + def test_deep_symbolize_keys_for_hash_with_indifferent_access assert_instance_of Hash, @nested_symbols.with_indifferent_access.deep_symbolize_keys assert_equal @nested_symbols, @nested_symbols.with_indifferent_access.deep_symbolize_keys @@ -440,6 +447,14 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end + def test_indifferent_assoc + indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) + key, value = indifferent_strings.assoc(:a) + + assert_equal("a", key) + assert_equal(1, value) + end + def test_indifferent_compact hash_contain_nil_value = @strings.merge("z" => nil) hash = ActiveSupport::HashWithIndifferentAccess.new(hash_contain_nil_value) @@ -471,7 +486,7 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_equal @strings, roundtrip assert_equal "1234", roundtrip.default - # Ensure nested hashes are not HashWithIndiffereneAccess + # Ensure nested hashes are not HashWithIndifferentAccess 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) @@ -672,6 +687,17 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_equal "bender", slice["login"] end + def test_indifferent_without + original = { a: "x", b: "y", c: 10 }.with_indifferent_access + expected = { c: 10 }.with_indifferent_access + + [["a", "b"], [:a, :b]].each do |keys| + # Should return a new hash without the given keys. + assert_equal expected, original.without(*keys), keys.inspect + assert_not_equal expected, original + end + end + def test_indifferent_extract original = { :a => 1, "b" => 2, :c => 3, "d" => 4 }.with_indifferent_access expected = { a: 1, b: 2 }.with_indifferent_access diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 5e50acf5db..ddf765a220 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -224,12 +224,6 @@ class InflectorTest < ActiveSupport::TestCase assert_equal("json_html_api", ActiveSupport::Inflector.underscore("JSONHTMLAPI")) end - def test_acronym_regexp_is_deprecated - assert_deprecated do - ActiveSupport::Inflector.inflections.acronym_regex - end - end - def test_underscore CamelToUnderscore.each do |camel, underscore| assert_equal(underscore, ActiveSupport::Inflector.underscore(camel)) @@ -310,6 +304,12 @@ class InflectorTest < ActiveSupport::TestCase end end + def test_parameterize_with_locale + word = "Fünf autos" + I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } }) + assert_equal("fuenf-autos", ActiveSupport::Inflector.parameterize(word, locale: :de)) + end + def test_classify ClassNameToTableName.each do |class_name, table_name| assert_equal(class_name, ActiveSupport::Inflector.classify(table_name)) diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 340a2abf75..7589ffd0ea 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -3,7 +3,6 @@ require "securerandom" require "abstract_unit" require "active_support/core_ext/string/inflections" -require "active_support/core_ext/regexp" require "active_support/json" require "active_support/time" require "time_zone_test_helpers" @@ -22,20 +21,18 @@ class TestJSONEncoding < ActiveSupport::TestCase JSONTest::EncodingTestCases.constants.each do |class_tests| define_method("test_#{class_tests[0..-6].underscore}") do - begin - prev = ActiveSupport.use_standard_json_time_format - - standard_class_tests = /Standard/.match?(class_tests) - - ActiveSupport.escape_html_entities_in_json = !standard_class_tests - ActiveSupport.use_standard_json_time_format = standard_class_tests - JSONTest::EncodingTestCases.const_get(class_tests).each do |pair| - assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first)) - end - ensure - ActiveSupport.escape_html_entities_in_json = false - ActiveSupport.use_standard_json_time_format = prev + prev = ActiveSupport.use_standard_json_time_format + + standard_class_tests = /Standard/.match?(class_tests) + + ActiveSupport.escape_html_entities_in_json = !standard_class_tests + ActiveSupport.use_standard_json_time_format = standard_class_tests + JSONTest::EncodingTestCases.const_get(class_tests).each do |pair| + assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first)) end + ensure + ActiveSupport.escape_html_entities_in_json = false + ActiveSupport.use_standard_json_time_format = prev end end @@ -158,6 +155,16 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal({ "foo" => "hello" }, JSON.parse(json)) end + def test_struct_to_json_with_options_nested + klass = Struct.new(:foo, :bar) + struct = klass.new "hello", "world" + parent_struct = klass.new struct, "world" + json = parent_struct.to_json only: [:foo] + + assert_equal({ "foo" => { "foo" => "hello" } }, JSON.parse(json)) + end + + def test_hash_should_pass_encoding_options_to_children_in_as_json person = { name: "John", diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb index cdde2c573a..9dfc0b2154 100644 --- a/activesupport/test/key_generator_test.rb +++ b/activesupport/test/key_generator_test.rb @@ -9,9 +9,6 @@ rescue LoadError, NameError $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install" else - require "active_support/time" - require "active_support/json" - class KeyGeneratorTest < ActiveSupport::TestCase def setup @secret = SecureRandom.hex(64) diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb index 2af9b1de30..7f05459493 100644 --- a/activesupport/test/log_subscriber_test.rb +++ b/activesupport/test/log_subscriber_test.rb @@ -75,6 +75,22 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase assert_kind_of ActiveSupport::Notifications::Event, @log_subscriber.event end + def test_event_attributes + ActiveSupport::LogSubscriber.attach_to :my_log_subscriber, @log_subscriber + instrument "some_event.my_log_subscriber" + wait + event = @log_subscriber.event + if defined?(JRUBY_VERSION) + assert_equal 0, event.cpu_time + assert_equal 0, event.allocations + else + assert_operator event.cpu_time, :>, 0 + assert_operator event.allocations, :>, 0 + end + assert_operator event.duration, :>, 0 + assert_operator event.idle_time, :>, 0 + end + def test_does_not_send_the_event_if_it_doesnt_match_the_class ActiveSupport::LogSubscriber.attach_to :my_log_subscriber, @log_subscriber instrument "unknown_event.my_log_subscriber" diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index 773b0daa1d..160e1156b6 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -40,7 +40,7 @@ class LoggerTest < ActiveSupport::TestCase logger = Logger.new f logger.level = Logger::DEBUG - str = "\x80".dup + str = +"\x80" str.force_encoding("ASCII-8BIT") logger.add Logger::DEBUG, str @@ -58,7 +58,7 @@ class LoggerTest < ActiveSupport::TestCase logger = Logger.new f logger.level = Logger::DEBUG - str = "\x80".dup + str = +"\x80" str.force_encoding("ASCII-8BIT") logger.add Logger::DEBUG, str diff --git a/activesupport/test/metadata/shared_metadata_tests.rb b/activesupport/test/metadata/shared_metadata_tests.rb index 08bb0c648e..cf571223e5 100644 --- a/activesupport/test/metadata/shared_metadata_tests.rb +++ b/activesupport/test/metadata/shared_metadata_tests.rb @@ -1,11 +1,6 @@ # frozen_string_literal: true module SharedMessageMetadataTests - def teardown - travel_back - super - end - def null_serializing? false end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 061446c782..5f4e3f3fd3 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -53,7 +53,7 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_with_non_string_result_should_be_returned_verbatim - str = "".dup + 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 } @@ -61,26 +61,32 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_concatenate - mb_a = "a".dup.mb_chars - mb_b = "b".dup.mb_chars + mb_a = (+"a").mb_chars + mb_b = (+"b").mb_chars assert_equal "ab", mb_a + "b" assert_equal "ab", "a" + mb_b assert_equal "ab", mb_a + mb_b assert_equal "ab", mb_a << "b" - assert_equal "ab", "a".dup << mb_b + assert_equal "ab", (+"a") << mb_b assert_equal "abb", mb_a << mb_b end def test_consumes_utf8_strings - assert @proxy_class.consumes?(UNICODE_STRING) - assert @proxy_class.consumes?(ASCII_STRING) - assert_not @proxy_class.consumes?(BYTE_STRING) + ActiveSupport::Deprecation.silence do + assert @proxy_class.consumes?(UNICODE_STRING) + assert @proxy_class.consumes?(ASCII_STRING) + assert_not @proxy_class.consumes?(BYTE_STRING) + end + end + + def test_consumes_is_deprecated + assert_deprecated { @proxy_class.consumes?(UNICODE_STRING) } end def test_concatenation_should_return_a_proxy_class_instance assert_equal ActiveSupport::Multibyte.proxy_class, ("a".mb_chars + "b").class - assert_equal ActiveSupport::Multibyte.proxy_class, ("a".dup.mb_chars << "b").class + assert_equal ActiveSupport::Multibyte.proxy_class, ((+"a").mb_chars << "b").class end def test_ascii_strings_are_treated_at_utf8_strings @@ -90,8 +96,8 @@ class MultibyteCharsTest < ActiveSupport::TestCase def test_concatenate_should_return_proxy_instance assert(("a".mb_chars + "b").kind_of?(@proxy_class)) assert(("a".mb_chars + "b".mb_chars).kind_of?(@proxy_class)) - assert(("a".dup.mb_chars << "b").kind_of?(@proxy_class)) - assert(("a".dup.mb_chars << "b".mb_chars).kind_of?(@proxy_class)) + assert(((+"a").mb_chars << "b").kind_of?(@proxy_class)) + assert(((+"a").mb_chars << "b".mb_chars).kind_of?(@proxy_class)) end def test_should_return_string_as_json @@ -135,7 +141,7 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_tidy_bytes_bang_should_change_wrapped_string - original = " Un bUen café \x92".dup + original = +" Un bUen café \x92" proxy = chars(original.dup) proxy.tidy_bytes! assert_not_equal original, proxy.to_s @@ -152,7 +158,7 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_string_methods_are_chainable - assert chars("".dup).insert(0, "").kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars(+"").insert(0, "").kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").rjust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").ljust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").center(1).kind_of?(ActiveSupport::Multibyte.proxy_class) @@ -165,7 +171,9 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert chars("").upcase.kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").downcase.kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").capitalize.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars("").normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + ActiveSupport::Deprecation.silence do + assert chars("").normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + end assert chars("").decompose.kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").compose.kind_of?(ActiveSupport::Multibyte.proxy_class) assert chars("").tidy_bytes.kind_of?(ActiveSupport::Multibyte.proxy_class) @@ -197,7 +205,7 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_should_use_character_offsets_for_insert_offsets - assert_equal "", "".dup.mb_chars.insert(0, "") + assert_equal "", (+"").mb_chars.insert(0, "") assert_equal "こわにちわ", @chars.insert(1, "わ") assert_equal "こわわわにちわ", @chars.insert(2, "わわ") assert_equal "わこわわわにちわ", @chars.insert(0, "わ") @@ -383,10 +391,12 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase def test_reverse_should_work_with_normalized_strings str = "bös" reversed_str = "söb" - assert_equal chars(reversed_str).normalize(:kc), chars(str).normalize(:kc).reverse - assert_equal chars(reversed_str).normalize(:c), chars(str).normalize(:c).reverse - assert_equal chars(reversed_str).normalize(:d), chars(str).normalize(:d).reverse - assert_equal chars(reversed_str).normalize(:kd), chars(str).normalize(:kd).reverse + ActiveSupport::Deprecation.silence do + assert_equal chars(reversed_str).normalize(:kc), chars(str).normalize(:kc).reverse + assert_equal chars(reversed_str).normalize(:c), chars(str).normalize(:c).reverse + assert_equal chars(reversed_str).normalize(:d), chars(str).normalize(:d).reverse + assert_equal chars(reversed_str).normalize(:kd), chars(str).normalize(:kd).reverse + end assert_equal chars(reversed_str).decompose, chars(str).decompose.reverse assert_equal chars(reversed_str).compose, chars(str).compose.reverse end @@ -420,13 +430,13 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_slice_bang_removes_the_slice_from_the_receiver - chars = "úüù".dup.mb_chars + chars = (+"úüù").mb_chars chars.slice!(0, 2) assert_equal "ù", chars end def test_slice_bang_returns_nil_and_does_not_modify_receiver_if_out_of_bounds - string = "úüù".dup + string = +"úüù" chars = string.mb_chars assert_nil chars.slice!(4, 5) assert_equal "úüù", chars @@ -477,7 +487,7 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase def test_method_works_for_proxyed_methods assert_equal "ll", "hello".mb_chars.method(:slice).call(2..3) # Defined on Chars - chars = "hello".mb_chars + chars = +"hello".mb_chars assert_equal "Hello", chars.method(:capitalize!).call # Defined on Chars assert_equal "Hello", chars assert_equal "jello", "hello".mb_chars.method(:gsub).call(/h/, "j") # Defined on String @@ -568,7 +578,9 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_composition_exclusion_is_set_up_properly # Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly qa = [0x915, 0x93c].pack("U*") - assert_equal qa, chars(qa).normalize(:c) + ActiveSupport::Deprecation.silence do + assert_equal qa, chars(qa).normalize(:c) + end end # Test for the Public Review Issue #29, bad explanation of composition might lead to a @@ -578,17 +590,21 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase [0x0B47, 0x0300, 0x0B3E], [0x1100, 0x0300, 0x1161] ].map { |c| c.pack("U*") }.each do |c| - assert_equal_codepoints c, chars(c).normalize(:c) + ActiveSupport::Deprecation.silence do + assert_equal_codepoints c, chars(c).normalize(:c) + end end end def test_normalization_shouldnt_strip_null_bytes null_byte_str = "Test\0test" - assert_equal null_byte_str, chars(null_byte_str).normalize(:kc) - assert_equal null_byte_str, chars(null_byte_str).normalize(:c) - assert_equal null_byte_str, chars(null_byte_str).normalize(:d) - assert_equal null_byte_str, chars(null_byte_str).normalize(:kd) + ActiveSupport::Deprecation.silence do + assert_equal null_byte_str, chars(null_byte_str).normalize(:kc) + assert_equal null_byte_str, chars(null_byte_str).normalize(:c) + assert_equal null_byte_str, chars(null_byte_str).normalize(:d) + assert_equal null_byte_str, chars(null_byte_str).normalize(:kd) + end assert_equal null_byte_str, chars(null_byte_str).decompose assert_equal null_byte_str, chars(null_byte_str).compose end @@ -601,11 +617,13 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase 323 # COMBINING DOT BELOW ].pack("U*") - assert_equal_codepoints "", chars("").normalize - assert_equal_codepoints [44, 105, 106, 328, 323].pack("U*"), chars(comp_str).normalize(:kc).to_s - assert_equal_codepoints [44, 307, 328, 323].pack("U*"), chars(comp_str).normalize(:c).to_s - assert_equal_codepoints [44, 307, 110, 780, 78, 769].pack("U*"), chars(comp_str).normalize(:d).to_s - assert_equal_codepoints [44, 105, 106, 110, 780, 78, 769].pack("U*"), chars(comp_str).normalize(:kd).to_s + ActiveSupport::Deprecation.silence do + assert_equal_codepoints "", chars("").normalize + assert_equal_codepoints [44, 105, 106, 328, 323].pack("U*"), chars(comp_str).normalize(:kc).to_s + assert_equal_codepoints [44, 307, 328, 323].pack("U*"), chars(comp_str).normalize(:c).to_s + assert_equal_codepoints [44, 307, 110, 780, 78, 769].pack("U*"), chars(comp_str).normalize(:d).to_s + assert_equal_codepoints [44, 105, 106, 110, 780, 78, 769].pack("U*"), chars(comp_str).normalize(:kd).to_s + end end def test_should_compute_grapheme_length @@ -719,6 +737,51 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase assert_equal BYTE_STRING.dup.mb_chars.class, ActiveSupport::Multibyte::Chars end + def test_unicode_normalize_deprecation + # String#unicode_normalize default form is `:nfc`, and + # different than Multibyte::Unicode default, `:nkfc`. + # Deprecation should suggest the right form if no params + # are given and default is used. + assert_deprecated(/unicode_normalize\(:nfkc\)/) do + ActiveSupport::Multibyte::Unicode.normalize("") + end + + assert_deprecated(/unicode_normalize\(:nfd\)/) do + ActiveSupport::Multibyte::Unicode.normalize("", :d) + end + end + + def test_chars_normalize_deprecation + # String#unicode_normalize default form is `:nfc`, and + # different than Multibyte::Unicode default, `:nkfc`. + # Deprecation should suggest the right form if no params + # are given and default is used. + assert_deprecated(/unicode_normalize\(:nfkc\)/) do + "".mb_chars.normalize + end + + assert_deprecated(/unicode_normalize\(:nfc\)/) { "".mb_chars.normalize(:c) } + assert_deprecated(/unicode_normalize\(:nfd\)/) { "".mb_chars.normalize(:d) } + assert_deprecated(/unicode_normalize\(:nfkc\)/) { "".mb_chars.normalize(:kc) } + assert_deprecated(/unicode_normalize\(:nfkd\)/) { "".mb_chars.normalize(:kd) } + end + + def test_unicode_deprecations + assert_deprecated { ActiveSupport::Multibyte::Unicode.downcase("") } + assert_deprecated { ActiveSupport::Multibyte::Unicode.upcase("") } + assert_deprecated { ActiveSupport::Multibyte::Unicode.swapcase("") } + end + + def test_normalize_non_unicode_string + # Fullwidth Latin Capital Letter A in Windows 31J + str = "\u{ff21}".encode(Encoding::Windows_31J) + assert_raise Encoding::CompatibilityError do + ActiveSupport::Deprecation.silence do + ActiveSupport::Multibyte::Unicode.normalize(str) + end + end + end + private def string_from_classes(classes) @@ -732,21 +795,3 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase end.pack("U*") end end - -class MultibyteInternalsTest < ActiveSupport::TestCase - include MultibyteTestHelpers - - test "Chars translates a character offset to a byte offset" do - example = chars("Puisque c'était son erreur, il m'a aidé") - [ - [0, 0], - [3, 3], - [12, 11], - [14, 13], - [41, 39] - ].each do |byte_offset, character_offset| - assert_equal character_offset, example.send(:translate_offset, byte_offset), - "Expected byte offset #{byte_offset} to translate to #{character_offset}" - end - end -end diff --git a/activesupport/test/multibyte_conformance_test.rb b/activesupport/test/multibyte_conformance_test.rb index a704505fc6..b19689723f 100644 --- a/activesupport/test/multibyte_conformance_test.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -18,64 +18,72 @@ class MultibyteConformanceTest < ActiveSupport::TestCase end def test_normalizations_C - each_line_of_norm_tests do |*cols| - col1, col2, col3, col4, col5, comment = *cols + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do |*cols| + col1, col2, col3, col4, col5, comment = *cols - # CONFORMANCE: - # 1. The following invariants must be true for all conformant implementations - # - # NFC - # c2 == NFC(c1) == NFC(c2) == NFC(c3) - assert_equal_codepoints col2, @proxy.new(col1).normalize(:c), "Form C - Col 2 has to be NFC(1) - #{comment}" - assert_equal_codepoints col2, @proxy.new(col2).normalize(:c), "Form C - Col 2 has to be NFC(2) - #{comment}" - assert_equal_codepoints col2, @proxy.new(col3).normalize(:c), "Form C - Col 2 has to be NFC(3) - #{comment}" - # - # c4 == NFC(c4) == NFC(c5) - assert_equal_codepoints col4, @proxy.new(col4).normalize(:c), "Form C - Col 4 has to be C(4) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col5).normalize(:c), "Form C - Col 4 has to be C(5) - #{comment}" + # CONFORMANCE: + # 1. The following invariants must be true for all conformant implementations + # + # NFC + # c2 == NFC(c1) == NFC(c2) == NFC(c3) + assert_equal_codepoints col2, @proxy.new(col1).normalize(:c), "Form C - Col 2 has to be NFC(1) - #{comment}" + assert_equal_codepoints col2, @proxy.new(col2).normalize(:c), "Form C - Col 2 has to be NFC(2) - #{comment}" + assert_equal_codepoints col2, @proxy.new(col3).normalize(:c), "Form C - Col 2 has to be NFC(3) - #{comment}" + # + # c4 == NFC(c4) == NFC(c5) + assert_equal_codepoints col4, @proxy.new(col4).normalize(:c), "Form C - Col 4 has to be C(4) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col5).normalize(:c), "Form C - Col 4 has to be C(5) - #{comment}" + end end end def test_normalizations_D - each_line_of_norm_tests do |*cols| - col1, col2, col3, col4, col5, comment = *cols - # - # NFD - # c3 == NFD(c1) == NFD(c2) == NFD(c3) - assert_equal_codepoints col3, @proxy.new(col1).normalize(:d), "Form D - Col 3 has to be NFD(1) - #{comment}" - assert_equal_codepoints col3, @proxy.new(col2).normalize(:d), "Form D - Col 3 has to be NFD(2) - #{comment}" - assert_equal_codepoints col3, @proxy.new(col3).normalize(:d), "Form D - Col 3 has to be NFD(3) - #{comment}" - # c5 == NFD(c4) == NFD(c5) - assert_equal_codepoints col5, @proxy.new(col4).normalize(:d), "Form D - Col 5 has to be NFD(4) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col5).normalize(:d), "Form D - Col 5 has to be NFD(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do |*cols| + col1, col2, col3, col4, col5, comment = *cols + # + # NFD + # c3 == NFD(c1) == NFD(c2) == NFD(c3) + assert_equal_codepoints col3, @proxy.new(col1).normalize(:d), "Form D - Col 3 has to be NFD(1) - #{comment}" + assert_equal_codepoints col3, @proxy.new(col2).normalize(:d), "Form D - Col 3 has to be NFD(2) - #{comment}" + assert_equal_codepoints col3, @proxy.new(col3).normalize(:d), "Form D - Col 3 has to be NFD(3) - #{comment}" + # c5 == NFD(c4) == NFD(c5) + assert_equal_codepoints col5, @proxy.new(col4).normalize(:d), "Form D - Col 5 has to be NFD(4) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col5).normalize(:d), "Form D - Col 5 has to be NFD(5) - #{comment}" + end end end def test_normalizations_KC - each_line_of_norm_tests do | *cols | - col1, col2, col3, col4, col5, comment = *cols - # - # NFKC - # c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) - assert_equal_codepoints col4, @proxy.new(col1).normalize(:kc), "Form D - Col 4 has to be NFKC(1) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col2).normalize(:kc), "Form D - Col 4 has to be NFKC(2) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col3).normalize(:kc), "Form D - Col 4 has to be NFKC(3) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col4).normalize(:kc), "Form D - Col 4 has to be NFKC(4) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col5).normalize(:kc), "Form D - Col 4 has to be NFKC(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do | *cols | + col1, col2, col3, col4, col5, comment = *cols + # + # NFKC + # c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) + assert_equal_codepoints col4, @proxy.new(col1).normalize(:kc), "Form D - Col 4 has to be NFKC(1) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col2).normalize(:kc), "Form D - Col 4 has to be NFKC(2) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col3).normalize(:kc), "Form D - Col 4 has to be NFKC(3) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col4).normalize(:kc), "Form D - Col 4 has to be NFKC(4) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col5).normalize(:kc), "Form D - Col 4 has to be NFKC(5) - #{comment}" + end end end def test_normalizations_KD - each_line_of_norm_tests do | *cols | - col1, col2, col3, col4, col5, comment = *cols - # - # NFKD - # c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) - assert_equal_codepoints col5, @proxy.new(col1).normalize(:kd), "Form KD - Col 5 has to be NFKD(1) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col2).normalize(:kd), "Form KD - Col 5 has to be NFKD(2) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col3).normalize(:kd), "Form KD - Col 5 has to be NFKD(3) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col4).normalize(:kd), "Form KD - Col 5 has to be NFKD(4) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col5).normalize(:kd), "Form KD - Col 5 has to be NFKD(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do | *cols | + col1, col2, col3, col4, col5, comment = *cols + # + # NFKD + # c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) + assert_equal_codepoints col5, @proxy.new(col1).normalize(:kd), "Form KD - Col 5 has to be NFKD(1) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col2).normalize(:kd), "Form KD - Col 5 has to be NFKD(2) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col3).normalize(:kd), "Form KD - Col 5 has to be NFKD(3) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col4).normalize(:kd), "Form KD - Col 5 has to be NFKD(4) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col5).normalize(:kd), "Form KD - Col 5 has to be NFKD(5) - #{comment}" + end end end diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb index 61b171a8d4..97963279af 100644 --- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb +++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb @@ -17,10 +17,12 @@ class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase end def test_breaks - each_line_of_break_tests do |*cols| - *clusters, comment = *cols - packed = ActiveSupport::Multibyte::Unicode.pack_graphemes(clusters) - assert_equal clusters, ActiveSupport::Multibyte::Unicode.unpack_graphemes(packed), comment + ActiveSupport::Deprecation.silence do + each_line_of_break_tests do |*cols| + *clusters, comment = *cols + packed = ActiveSupport::Multibyte::Unicode.pack_graphemes(clusters) + assert_equal clusters, ActiveSupport::Multibyte::Unicode.unpack_graphemes(packed), comment + end end end diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb index 3674ea44f3..82edf69294 100644 --- a/activesupport/test/multibyte_normalization_conformance_test.rb +++ b/activesupport/test/multibyte_normalization_conformance_test.rb @@ -18,64 +18,72 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase end def test_normalizations_C - each_line_of_norm_tests do |*cols| - col1, col2, col3, col4, col5, comment = *cols + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do |*cols| + col1, col2, col3, col4, col5, comment = *cols - # CONFORMANCE: - # 1. The following invariants must be true for all conformant implementations - # - # NFC - # c2 == NFC(c1) == NFC(c2) == NFC(c3) - assert_equal_codepoints col2, @proxy.new(col1).normalize(:c), "Form C - Col 2 has to be NFC(1) - #{comment}" - assert_equal_codepoints col2, @proxy.new(col2).normalize(:c), "Form C - Col 2 has to be NFC(2) - #{comment}" - assert_equal_codepoints col2, @proxy.new(col3).normalize(:c), "Form C - Col 2 has to be NFC(3) - #{comment}" - # - # c4 == NFC(c4) == NFC(c5) - assert_equal_codepoints col4, @proxy.new(col4).normalize(:c), "Form C - Col 4 has to be C(4) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col5).normalize(:c), "Form C - Col 4 has to be C(5) - #{comment}" + # CONFORMANCE: + # 1. The following invariants must be true for all conformant implementations + # + # NFC + # c2 == NFC(c1) == NFC(c2) == NFC(c3) + assert_equal_codepoints col2, @proxy.new(col1).normalize(:c), "Form C - Col 2 has to be NFC(1) - #{comment}" + assert_equal_codepoints col2, @proxy.new(col2).normalize(:c), "Form C - Col 2 has to be NFC(2) - #{comment}" + assert_equal_codepoints col2, @proxy.new(col3).normalize(:c), "Form C - Col 2 has to be NFC(3) - #{comment}" + # + # c4 == NFC(c4) == NFC(c5) + assert_equal_codepoints col4, @proxy.new(col4).normalize(:c), "Form C - Col 4 has to be C(4) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col5).normalize(:c), "Form C - Col 4 has to be C(5) - #{comment}" + end end end def test_normalizations_D - each_line_of_norm_tests do |*cols| - col1, col2, col3, col4, col5, comment = *cols - # - # NFD - # c3 == NFD(c1) == NFD(c2) == NFD(c3) - assert_equal_codepoints col3, @proxy.new(col1).normalize(:d), "Form D - Col 3 has to be NFD(1) - #{comment}" - assert_equal_codepoints col3, @proxy.new(col2).normalize(:d), "Form D - Col 3 has to be NFD(2) - #{comment}" - assert_equal_codepoints col3, @proxy.new(col3).normalize(:d), "Form D - Col 3 has to be NFD(3) - #{comment}" - # c5 == NFD(c4) == NFD(c5) - assert_equal_codepoints col5, @proxy.new(col4).normalize(:d), "Form D - Col 5 has to be NFD(4) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col5).normalize(:d), "Form D - Col 5 has to be NFD(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do |*cols| + col1, col2, col3, col4, col5, comment = *cols + # + # NFD + # c3 == NFD(c1) == NFD(c2) == NFD(c3) + assert_equal_codepoints col3, @proxy.new(col1).normalize(:d), "Form D - Col 3 has to be NFD(1) - #{comment}" + assert_equal_codepoints col3, @proxy.new(col2).normalize(:d), "Form D - Col 3 has to be NFD(2) - #{comment}" + assert_equal_codepoints col3, @proxy.new(col3).normalize(:d), "Form D - Col 3 has to be NFD(3) - #{comment}" + # c5 == NFD(c4) == NFD(c5) + assert_equal_codepoints col5, @proxy.new(col4).normalize(:d), "Form D - Col 5 has to be NFD(4) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col5).normalize(:d), "Form D - Col 5 has to be NFD(5) - #{comment}" + end end end def test_normalizations_KC - each_line_of_norm_tests do | *cols | - col1, col2, col3, col4, col5, comment = *cols - # - # NFKC - # c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) - assert_equal_codepoints col4, @proxy.new(col1).normalize(:kc), "Form D - Col 4 has to be NFKC(1) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col2).normalize(:kc), "Form D - Col 4 has to be NFKC(2) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col3).normalize(:kc), "Form D - Col 4 has to be NFKC(3) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col4).normalize(:kc), "Form D - Col 4 has to be NFKC(4) - #{comment}" - assert_equal_codepoints col4, @proxy.new(col5).normalize(:kc), "Form D - Col 4 has to be NFKC(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do | *cols | + col1, col2, col3, col4, col5, comment = *cols + # + # NFKC + # c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) + assert_equal_codepoints col4, @proxy.new(col1).normalize(:kc), "Form D - Col 4 has to be NFKC(1) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col2).normalize(:kc), "Form D - Col 4 has to be NFKC(2) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col3).normalize(:kc), "Form D - Col 4 has to be NFKC(3) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col4).normalize(:kc), "Form D - Col 4 has to be NFKC(4) - #{comment}" + assert_equal_codepoints col4, @proxy.new(col5).normalize(:kc), "Form D - Col 4 has to be NFKC(5) - #{comment}" + end end end def test_normalizations_KD - each_line_of_norm_tests do | *cols | - col1, col2, col3, col4, col5, comment = *cols - # - # NFKD - # c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) - assert_equal_codepoints col5, @proxy.new(col1).normalize(:kd), "Form KD - Col 5 has to be NFKD(1) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col2).normalize(:kd), "Form KD - Col 5 has to be NFKD(2) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col3).normalize(:kd), "Form KD - Col 5 has to be NFKD(3) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col4).normalize(:kd), "Form KD - Col 5 has to be NFKD(4) - #{comment}" - assert_equal_codepoints col5, @proxy.new(col5).normalize(:kd), "Form KD - Col 5 has to be NFKD(5) - #{comment}" + ActiveSupport::Deprecation.silence do + each_line_of_norm_tests do | *cols | + col1, col2, col3, col4, col5, comment = *cols + # + # NFKD + # c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) + assert_equal_codepoints col5, @proxy.new(col1).normalize(:kd), "Form KD - Col 5 has to be NFKD(1) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col2).normalize(:kd), "Form KD - Col 5 has to be NFKD(2) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col3).normalize(:kd), "Form KD - Col 5 has to be NFKD(3) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col4).normalize(:kd), "Form KD - Col 5 has to be NFKD(4) - #{comment}" + assert_equal_codepoints col5, @proxy.new(col5).normalize(:kd), "Form KD - Col 5 has to be NFKD(5) - #{comment}" + end end end diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index 98f36aa939..7565655f25 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -27,9 +27,9 @@ module MultibyteTestHelpers CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}" FileUtils.mkdir_p(CACHE_DIR) - UNICODE_STRING = "こにちわ".freeze - ASCII_STRING = "ohayo".freeze - BYTE_STRING = "\270\236\010\210\245".dup.force_encoding("ASCII-8BIT").freeze + UNICODE_STRING = "こにちわ" + ASCII_STRING = "ohayo" + 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/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb index 4beb8194b9..ab2a9b8659 100644 --- a/activesupport/test/notifications/evented_notification_test.rb +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -84,6 +84,39 @@ module ActiveSupport [:finish, "hi", 1, {}] ], listener.events end + + def test_listen_to_regexp + notifier = Fanout.new + listener = Listener.new + notifier.subscribe(/[a-z]*.world/, listener) + notifier.start("hi.world", 1, {}) + notifier.finish("hi.world", 2, {}) + notifier.start("hello.world", 1, {}) + notifier.finish("hello.world", 2, {}) + + assert_equal [ + [:start, "hi.world", 1, {}], + [:finish, "hi.world", 2, {}], + [:start, "hello.world", 1, {}], + [:finish, "hello.world", 2, {}] + ], listener.events + end + + def test_listen_to_regexp_with_exclusions + notifier = Fanout.new + listener = Listener.new + notifier.subscribe(/[a-z]*.world/, listener) + notifier.unsubscribe("hi.world") + notifier.start("hi.world", 1, {}) + notifier.finish("hi.world", 2, {}) + notifier.start("hello.world", 1, {}) + notifier.finish("hello.world", 2, {}) + + assert_equal [ + [:start, "hello.world", 1, {}], + [:finish, "hello.world", 2, {}] + ], listener.events + end end end end diff --git a/activesupport/test/notifications/instrumenter_test.rb b/activesupport/test/notifications/instrumenter_test.rb index d5c9e82e9f..9729ad5c89 100644 --- a/activesupport/test/notifications/instrumenter_test.rb +++ b/activesupport/test/notifications/instrumenter_test.rb @@ -44,6 +44,12 @@ module ActiveSupport assert_equal Hash[result: 2], payload end + def test_instrument_works_without_a_block + instrumenter.instrument("no.block", payload) + assert_equal 1, notifier.finishes.size + assert_equal "no.block", notifier.finishes.first.first + end + def test_start instrumenter.start("foo", payload) assert_equal [["foo", instrumenter.id, payload]], notifier.starts diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index d035f993f7..bb20d26a25 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -26,6 +26,42 @@ module Notifications end end + class SubscribeEventObjectsTest < TestCase + def test_subscribe_events + events = [] + @notifier.subscribe do |event| + events << event + end + + ActiveSupport::Notifications.instrument("foo") + event = events.first + assert event, "should have an event" + assert_operator event.allocations, :>, 0 + assert_operator event.cpu_time, :>, 0 + assert_operator event.idle_time, :>, 0 + assert_operator event.duration, :>, 0 + end + + def test_subscribe_via_top_level_api + old_notifier = ActiveSupport::Notifications.notifier + ActiveSupport::Notifications.notifier = ActiveSupport::Notifications::Fanout.new + + event = nil + ActiveSupport::Notifications.subscribe("foo") do |e| + event = e + end + + ActiveSupport::Notifications.instrument("foo") do + 100.times { Object.new } # allocate at least 100 objects + end + + assert event + assert_operator event.allocations, :>=, 100 + ensure + ActiveSupport::Notifications.notifier = old_notifier + end + end + class SubscribedTest < TestCase def test_subscribed name = "foo" @@ -45,7 +81,7 @@ module Notifications assert_equal expected, events end - def test_subsribing_to_instrumentation_while_inside_it + def test_subscribing_to_instrumentation_while_inside_it # the repro requires that there are no evented subscribers for the "foo" event, # so we have to duplicate some of the setup code old_notifier = ActiveSupport::Notifications.notifier @@ -54,7 +90,7 @@ module Notifications ActiveSupport::Notifications.subscribe("foo", TestSubscriber.new) ActiveSupport::Notifications.instrument("foo") do - ActiveSupport::Notifications.subscribe("foo") {} + ActiveSupport::Notifications.subscribe("foo") { } end ensure ActiveSupport::Notifications.notifier = old_notifier @@ -92,6 +128,25 @@ module Notifications assert_equal [["named.subscription", :foo], ["named.subscription", :foo]], @events end + def test_unsubscribing_by_name_leaves_regexp_matched_subscriptions + @matched_events = [] + @notifier.subscribe(/subscription/) { |*args| @matched_events << event(*args) } + @notifier.publish("named.subscription", :before) + @notifier.wait + [@events, @named_events, @matched_events].each do |collector| + assert_includes(collector, ["named.subscription", :before]) + end + @notifier.unsubscribe("named.subscription") + @notifier.publish("named.subscription", :after) + @notifier.publish("other.subscription", :after) + @notifier.wait + assert_includes(@events, ["named.subscription", :after]) + assert_includes(@events, ["other.subscription", :after]) + assert_includes(@matched_events, ["other.subscription", :after]) + assert_not_includes(@matched_events, ["named.subscription", :after]) + assert_not_includes(@named_events, ["named.subscription", :after]) + end + private def event(*args) args diff --git a/activesupport/test/parameter_filter_test.rb b/activesupport/test/parameter_filter_test.rb new file mode 100644 index 0000000000..d2dc71061d --- /dev/null +++ b/activesupport/test/parameter_filter_test.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/core_ext/hash" +require "active_support/parameter_filter" + +class ParameterFilterTest < ActiveSupport::TestCase + test "process parameter filter" do + test_hashes = [ + [{ "foo" => "bar" }, { "foo" => "bar" }, %w'food'], + [{ "foo" => "bar" }, { "foo" => "[FILTERED]" }, %w'foo'], + [{ "foo" => "bar", "bar" => "foo" }, { "foo" => "[FILTERED]", "bar" => "foo" }, %w'foo baz'], + [{ "foo" => "bar", "baz" => "foo" }, { "foo" => "[FILTERED]", "baz" => "[FILTERED]" }, %w'foo baz'], + [{ "bar" => { "foo" => "bar", "bar" => "foo" } }, { "bar" => { "foo" => "[FILTERED]", "bar" => "foo" } }, %w'fo'], + [{ "foo" => { "foo" => "bar", "bar" => "foo" } }, { "foo" => "[FILTERED]" }, %w'f banana'], + [{ "deep" => { "cc" => { "code" => "bar", "bar" => "foo" }, "ss" => { "code" => "bar" } } }, { "deep" => { "cc" => { "code" => "[FILTERED]", "bar" => "foo" }, "ss" => { "code" => "bar" } } }, %w'deep.cc.code'], + [{ "baz" => [{ "foo" => "baz" }, "1"] }, { "baz" => [{ "foo" => "[FILTERED]" }, "1"] }, [/foo/]]] + + test_hashes.each do |before_filter, after_filter, filter_words| + parameter_filter = ActiveSupport::ParameterFilter.new(filter_words) + assert_equal after_filter, parameter_filter.filter(before_filter) + + filter_words << "blah" + filter_words << lambda { |key, value| + value.reverse! if key =~ /bargain/ + } + filter_words << lambda { |key, value, original_params| + value.replace("world!") if original_params["barg"]["blah"] == "bar" && key == "hello" + } + + parameter_filter = ActiveSupport::ParameterFilter.new(filter_words) + before_filter["barg"] = { :bargain => "gain", "blah" => "bar", "bar" => { "bargain" => { "blah" => "foo", "hello" => "world" } } } + after_filter["barg"] = { :bargain => "niag", "blah" => "[FILTERED]", "bar" => { "bargain" => { "blah" => "[FILTERED]", "hello" => "world!" } } } + + assert_equal after_filter, parameter_filter.filter(before_filter) + end + end + + test "filter should return mask option when value is filtered" do + mask = Object.new.freeze + test_hashes = [ + [{ "foo" => "bar" }, { "foo" => "bar" }, %w'food'], + [{ "foo" => "bar" }, { "foo" => mask }, %w'foo'], + [{ "foo" => "bar", "bar" => "foo" }, { "foo" => mask, "bar" => "foo" }, %w'foo baz'], + [{ "foo" => "bar", "baz" => "foo" }, { "foo" => mask, "baz" => mask }, %w'foo baz'], + [{ "bar" => { "foo" => "bar", "bar" => "foo" } }, { "bar" => { "foo" => mask, "bar" => "foo" } }, %w'fo'], + [{ "foo" => { "foo" => "bar", "bar" => "foo" } }, { "foo" => mask }, %w'f banana'], + [{ "deep" => { "cc" => { "code" => "bar", "bar" => "foo" }, "ss" => { "code" => "bar" } } }, { "deep" => { "cc" => { "code" => mask, "bar" => "foo" }, "ss" => { "code" => "bar" } } }, %w'deep.cc.code'], + [{ "baz" => [{ "foo" => "baz" }, "1"] }, { "baz" => [{ "foo" => mask }, "1"] }, [/foo/]]] + + test_hashes.each do |before_filter, after_filter, filter_words| + parameter_filter = ActiveSupport::ParameterFilter.new(filter_words, mask: mask) + assert_equal after_filter, parameter_filter.filter(before_filter) + + filter_words << "blah" + filter_words << lambda { |key, value| + value.reverse! if key =~ /bargain/ + } + filter_words << lambda { |key, value, original_params| + value.replace("world!") if original_params["barg"]["blah"] == "bar" && key == "hello" + } + + parameter_filter = ActiveSupport::ParameterFilter.new(filter_words, mask: mask) + before_filter["barg"] = { :bargain => "gain", "blah" => "bar", "bar" => { "bargain" => { "blah" => "foo", "hello" => "world" } } } + after_filter["barg"] = { :bargain => "niag", "blah" => mask, "bar" => { "bargain" => { "blah" => mask, "hello" => "world!" } } } + + assert_equal after_filter, parameter_filter.filter(before_filter) + end + end + + test "filter_param" do + parameter_filter = ActiveSupport::ParameterFilter.new(["foo", /bar/]) + assert_equal "[FILTERED]", parameter_filter.filter_param("food", "secret vlaue") + assert_equal "[FILTERED]", parameter_filter.filter_param("baz.foo", "secret vlaue") + assert_equal "[FILTERED]", parameter_filter.filter_param("barbar", "secret vlaue") + assert_equal "non secret value", parameter_filter.filter_param("baz", "non secret value") + end + + test "filter_param can work with empty filters" do + parameter_filter = ActiveSupport::ParameterFilter.new + assert_equal "bar", parameter_filter.filter_param("foo", "bar") + end + + test "parameter filter should maintain hash with indifferent access" do + test_hashes = [ + [{ "foo" => "bar" }.with_indifferent_access, ["blah"]], + [{ "foo" => "bar" }.with_indifferent_access, []] + ] + + test_hashes.each do |before_filter, filter_words| + parameter_filter = ActiveSupport::ParameterFilter.new(filter_words) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, + parameter_filter.filter(before_filter) + end + end + + test "filter_param should return mask option when value is filtered" do + mask = Object.new.freeze + parameter_filter = ActiveSupport::ParameterFilter.new(["foo", /bar/], mask: mask) + assert_equal mask, parameter_filter.filter_param("food", "secret vlaue") + assert_equal mask, parameter_filter.filter_param("baz.foo", "secret vlaue") + assert_equal mask, parameter_filter.filter_param("barbar", "secret vlaue") + assert_equal "non secret value", parameter_filter.filter_param("baz", "non secret value") + end +end diff --git a/activesupport/test/reloader_test.rb b/activesupport/test/reloader_test.rb index 976917c1a1..1b7cc253d9 100644 --- a/activesupport/test/reloader_test.rb +++ b/activesupport/test/reloader_test.rb @@ -35,13 +35,13 @@ class ReloaderTest < ActiveSupport::TestCase r = new_reloader { true } invoked = false r.to_run { invoked = true } - r.wrap {} + r.wrap { } assert invoked r = new_reloader { false } invoked = false r.to_run { invoked = true } - r.wrap {} + r.wrap { } assert_not invoked end @@ -53,7 +53,7 @@ class ReloaderTest < ActiveSupport::TestCase reloader.executor.to_run { called << :executor_run } reloader.executor.to_complete { called << :executor_complete } - reloader.wrap {} + reloader.wrap { } assert_equal [:executor_run, :reloader_run, :prepare, :reloader_complete, :executor_complete], called called = [] @@ -63,7 +63,7 @@ class ReloaderTest < ActiveSupport::TestCase reloader.check = lambda { false } called = [] - reloader.wrap {} + reloader.wrap { } assert_equal [:executor_run, :executor_complete], called called = [] diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 9456bb8753..b1a1c2d390 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -75,16 +75,73 @@ class SafeBufferTest < ActiveSupport::TestCase assert_equal "my_test", str end - test "Should not return safe buffer from gsub" do - altered_buffer = @buffer.gsub("", "asdf") - assert_equal "asdf", altered_buffer - assert_not_predicate altered_buffer, :html_safe? + { + capitalize: nil, + chomp: nil, + chop: nil, + delete: "foo", + delete_prefix: "foo", + delete_suffix: "foo", + downcase: nil, + gsub: ["foo", "bar"], + lstrip: nil, + next: nil, + reverse: nil, + rstrip: nil, + slice: "foo", + squeeze: nil, + strip: nil, + sub: ["foo", "bar"], + succ: nil, + swapcase: nil, + tr: ["foo", "bar"], + tr_s: ["foo", "bar"], + unicode_normalize: nil, + upcase: nil, + }.each do |unsafe_method, dummy_args| + test "Should not return safe buffer from #{unsafe_method}" do + skip unless String.method_defined?(unsafe_method) + altered_buffer = @buffer.send(unsafe_method, *dummy_args) + assert_not_predicate altered_buffer, :html_safe? + end + + test "Should not return safe buffer from #{unsafe_method}!" do + skip unless String.method_defined?("#{unsafe_method}!") + @buffer.send("#{unsafe_method}!", *dummy_args) + assert_not_predicate @buffer, :html_safe? + end + end + + test "can assign value into zero-index" do + buffer = ActiveSupport::SafeBuffer.new("012345") + + buffer[0] = "<" + + assert_equal "<12345", buffer + end + + test "can assign value into non zero-index" do + buffer = ActiveSupport::SafeBuffer.new("012345") + + buffer[2] = "<" + + assert_equal "01<345", buffer + end + + test "can assign value into slice" do + buffer = ActiveSupport::SafeBuffer.new("012345") + + buffer[0, 3] = "<" + + assert_equal "<345", buffer end - test "Should not return safe buffer from gsub!" do - @buffer.gsub!("", "asdf") - assert_equal "asdf", @buffer - assert_not_predicate @buffer, :html_safe? + test "can assign value into offset slice" do + buffer = ActiveSupport::SafeBuffer.new("012345") + + buffer[1, 3] = "<" + + assert_equal "0<45", buffer end test "Should escape dirty buffers on add" do @@ -126,7 +183,7 @@ class SafeBufferTest < ActiveSupport::TestCase assert_equal "", ActiveSupport::SafeBuffer.new("foo").clone_empty end - test "clone_empty keeps the original dirtyness" do + test "clone_empty keeps the original dirtiness" do assert_predicate @buffer.clone_empty, :html_safe? assert_not_predicate @buffer.gsub!("", "").clone_empty, :html_safe? end @@ -150,6 +207,18 @@ class SafeBufferTest < ActiveSupport::TestCase assert_not y.html_safe?, "should not be safe" end + test "Should continue safe on slice" do + x = "<div>foo</div>".html_safe + + assert_predicate x, :html_safe? + + # getting a slice of it + y = x[0..-1] + + # should still be safe + assert_predicate y, :html_safe? + end + test "Should work with interpolation (array argument)" do x = "foo %s bar".html_safe % ["qux"] assert_equal "foo qux bar", x @@ -179,4 +248,22 @@ class SafeBufferTest < ActiveSupport::TestCase x = "Hello".html_safe assert_nil x[/a/, 1] end + + test "Should set back references" do + a = "foo123".html_safe + a2 = a.sub(/([a-z]+)([0-9]+)/) { $2 + $1 } + assert_equal "123foo", a2 + assert_not_predicate a2, :html_safe? + a.sub!(/([a-z]+)([0-9]+)/) { $2 + $1 } + assert_equal "123foo", a + assert_not_predicate a, :html_safe? + + b = "foo123 bar456".html_safe + b2 = b.gsub(/([a-z]+)([0-9]+)/) { $2 + $1 } + assert_equal "123foo 456bar", b2 + assert_not_predicate b2, :html_safe? + b.gsub!(/([a-z]+)([0-9]+)/) { $2 + $1 } + assert_equal "123foo 456bar", b + assert_not_predicate b, :html_safe? + end end diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb index 42fd5eefc1..a40c813fe3 100644 --- a/activesupport/test/share_lock_test.rb +++ b/activesupport/test/share_lock_test.rb @@ -11,38 +11,38 @@ class ShareLockTest < ActiveSupport::TestCase def test_reentrancy thread = Thread.new do - @lock.sharing { @lock.sharing {} } - @lock.exclusive { @lock.exclusive {} } + @lock.sharing { @lock.sharing { } } + @lock.exclusive { @lock.exclusive { } } end assert_threads_not_stuck thread end def test_sharing_doesnt_block with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_latch| - assert_threads_not_stuck(Thread.new { @lock.sharing {} }) + assert_threads_not_stuck(Thread.new { @lock.sharing { } }) end end def test_sharing_blocks_exclusive with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| @lock.exclusive(no_wait: true) { flunk } # polling should fail - exclusive_thread = Thread.new { @lock.exclusive {} } + exclusive_thread = Thread.new { @lock.exclusive { } } assert_threads_stuck_but_releasable_by_latch exclusive_thread, sharing_thread_release_latch end end def test_exclusive_blocks_sharing with_thread_waiting_in_lock_section(:exclusive) do |exclusive_thread_release_latch| - sharing_thread = Thread.new { @lock.sharing {} } + sharing_thread = Thread.new { @lock.sharing { } } assert_threads_stuck_but_releasable_by_latch sharing_thread, exclusive_thread_release_latch end end - def test_multiple_exlusives_are_able_to_progress + def test_multiple_exclusives_are_able_to_progress with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| exclusive_threads = (1..2).map do Thread.new do - @lock.exclusive {} + @lock.exclusive { } end end @@ -53,7 +53,7 @@ class ShareLockTest < ActiveSupport::TestCase def test_sharing_is_upgradeable_to_exclusive upgrading_thread = Thread.new do @lock.sharing do - @lock.exclusive {} + @lock.exclusive { } end end assert_threads_not_stuck upgrading_thread @@ -66,7 +66,7 @@ class ShareLockTest < ActiveSupport::TestCase upgrading_thread = Thread.new do @lock.sharing do in_sharing.count_down - @lock.exclusive {} + @lock.exclusive { } end end @@ -81,7 +81,7 @@ class ShareLockTest < ActiveSupport::TestCase exclusive_threads = (1..2).map do Thread.new do @lock.send(use_upgrading ? :sharing : :tap) do - @lock.exclusive(purpose: :load, compatible: [:load, :unload]) {} + @lock.exclusive(purpose: :load, compatible: [:load, :unload]) { } end end end @@ -95,7 +95,7 @@ class ShareLockTest < ActiveSupport::TestCase with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| thread = Thread.new do @lock.sharing do - @lock.exclusive {} + @lock.exclusive { } end end @@ -105,7 +105,7 @@ class ShareLockTest < ActiveSupport::TestCase sharing_thread_release_latch.count_down thread = Thread.new do - @lock.exclusive {} + @lock.exclusive { } end assert_threads_not_stuck thread @@ -115,68 +115,66 @@ class ShareLockTest < ActiveSupport::TestCase def test_exclusive_conflicting_purpose [true, false].each do |use_upgrading| with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_release_latch| - begin - together = Concurrent::CyclicBarrier.new(2) - conflicting_exclusive_threads = [ - Thread.new do - @lock.send(use_upgrading ? :sharing : :tap) do - together.wait - @lock.exclusive(purpose: :red, compatible: [:green, :purple]) {} - end - end, - Thread.new do - @lock.send(use_upgrading ? :sharing : :tap) do - together.wait - @lock.exclusive(purpose: :blue, compatible: [:green]) {} - end + together = Concurrent::CyclicBarrier.new(2) + conflicting_exclusive_threads = [ + Thread.new do + @lock.send(use_upgrading ? :sharing : :tap) do + together.wait + @lock.exclusive(purpose: :red, compatible: [:green, :purple]) { } + end + end, + Thread.new do + @lock.send(use_upgrading ? :sharing : :tap) do + together.wait + @lock.exclusive(purpose: :blue, compatible: [:green]) { } end - ] - - assert_threads_stuck conflicting_exclusive_threads # wait for threads to get into their respective `exclusive {}` blocks - - # This thread will be stuck as long as any other thread is in - # a sharing block. While it's blocked, it holds no lock, so it - # doesn't interfere with any other attempts. - no_purpose_thread = Thread.new do - @lock.exclusive {} end - assert_threads_stuck no_purpose_thread + ] - # This thread is compatible with both of the "primary" - # attempts above. It's initially stuck on the outer share - # lock, but as soon as that's released, it can run -- - # regardless of whether those threads hold share locks. - compatible_thread = Thread.new do - @lock.exclusive(purpose: :green, compatible: []) {} - end - assert_threads_stuck compatible_thread + assert_threads_stuck conflicting_exclusive_threads # wait for threads to get into their respective `exclusive {}` blocks - assert_threads_stuck conflicting_exclusive_threads + # This thread will be stuck as long as any other thread is in + # a sharing block. While it's blocked, it holds no lock, so it + # doesn't interfere with any other attempts. + no_purpose_thread = Thread.new do + @lock.exclusive { } + end + assert_threads_stuck no_purpose_thread + + # This thread is compatible with both of the "primary" + # attempts above. It's initially stuck on the outer share + # lock, but as soon as that's released, it can run -- + # regardless of whether those threads hold share locks. + compatible_thread = Thread.new do + @lock.exclusive(purpose: :green, compatible: []) { } + end + assert_threads_stuck compatible_thread - sharing_thread_release_latch.count_down + assert_threads_stuck conflicting_exclusive_threads - assert_threads_not_stuck compatible_thread # compatible thread is now able to squeak through + sharing_thread_release_latch.count_down - if use_upgrading - # The "primary" threads both each hold a share lock, and are - # mutually incompatible; they're still stuck. - assert_threads_stuck conflicting_exclusive_threads + assert_threads_not_stuck compatible_thread # compatible thread is now able to squeak through - # The thread without a specified purpose is also stuck; it's - # not compatible with anything. - assert_threads_stuck no_purpose_thread - else - # As the primaries didn't hold a share lock, as soon as the - # outer one was released, all the exclusive locks are free - # to be acquired in turn. + if use_upgrading + # The "primary" threads both each hold a share lock, and are + # mutually incompatible; they're still stuck. + assert_threads_stuck conflicting_exclusive_threads - assert_threads_not_stuck conflicting_exclusive_threads - assert_threads_not_stuck no_purpose_thread - end - ensure - conflicting_exclusive_threads.each(&:kill) - no_purpose_thread.kill + # The thread without a specified purpose is also stuck; it's + # not compatible with anything. + assert_threads_stuck no_purpose_thread + else + # As the primaries didn't hold a share lock, as soon as the + # outer one was released, all the exclusive locks are free + # to be acquired in turn. + + assert_threads_not_stuck conflicting_exclusive_threads + assert_threads_not_stuck no_purpose_thread end + ensure + conflicting_exclusive_threads.each(&:kill) + no_purpose_thread.kill end end end @@ -231,7 +229,7 @@ class ShareLockTest < ActiveSupport::TestCase assert_threads_stuck waiting_exclusive late_share_attempt = Thread.new do - @lock.sharing {} + @lock.sharing { } end assert_threads_stuck late_share_attempt @@ -252,14 +250,14 @@ class ShareLockTest < ActiveSupport::TestCase @lock.sharing do ready.wait attempt_reentrancy.wait - @lock.sharing {} + @lock.sharing { } end end exclusive = Thread.new do @lock.sharing do ready.wait - @lock.exclusive {} + @lock.exclusive { } end end @@ -280,7 +278,7 @@ class ShareLockTest < ActiveSupport::TestCase Thread.new do @lock.sharing do ready.wait - @lock.exclusive(purpose: :x, compatible: [:x], after_compatible: [:x]) {} + @lock.exclusive(purpose: :x, compatible: [:x], after_compatible: [:x]) { } done.wait end end @@ -297,7 +295,7 @@ class ShareLockTest < ActiveSupport::TestCase Thread.new do @lock.sharing do ready.wait - @lock.exclusive(purpose: :x) {} + @lock.exclusive(purpose: :x) { } done.wait end end, @@ -323,7 +321,7 @@ class ShareLockTest < ActiveSupport::TestCase Thread.new do @lock.sharing do ready.wait - @lock.exclusive(purpose: :x) {} + @lock.exclusive(purpose: :x) { } done.wait end end, @@ -352,7 +350,7 @@ class ShareLockTest < ActiveSupport::TestCase Thread.new do @lock.sharing do ready.wait - @lock.exclusive(purpose: :x) {} + @lock.exclusive(purpose: :x) { } done.wait end end, @@ -386,7 +384,7 @@ class ShareLockTest < ActiveSupport::TestCase incompatible_thread = Thread.new do @lock.sharing do ready.wait - @lock.exclusive(purpose: :x) {} + @lock.exclusive(purpose: :x) { } end end @@ -418,7 +416,7 @@ class ShareLockTest < ActiveSupport::TestCase incompatible_thread = Thread.new do ready.wait - @lock.exclusive(purpose: :z) {} + @lock.exclusive(purpose: :z) { } end recursive_yield_shares_thread = Thread.new do @@ -427,7 +425,7 @@ class ShareLockTest < ActiveSupport::TestCase @lock.yield_shares(compatible: [:y]) do do_nesting.wait @lock.sharing do - @lock.yield_shares(compatible: [:x, :y]) {} + @lock.yield_shares(compatible: [:x, :y]) { } end after_nesting.wait end @@ -439,12 +437,12 @@ class ShareLockTest < ActiveSupport::TestCase assert_threads_stuck incompatible_thread compatible_thread = Thread.new do - @lock.exclusive(purpose: :y) {} + @lock.exclusive(purpose: :y) { } end assert_threads_not_stuck compatible_thread post_nesting_incompatible_thread = Thread.new do - @lock.exclusive(purpose: :x) {} + @lock.exclusive(purpose: :x) { } end assert_threads_stuck post_nesting_incompatible_thread diff --git a/activesupport/test/silence_logger_test.rb b/activesupport/test/silence_logger_test.rb new file mode 100644 index 0000000000..bd0c6b7f86 --- /dev/null +++ b/activesupport/test/silence_logger_test.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/logger_silence" +require "logger" + +class LoggerSilenceTest < ActiveSupport::TestCase + class MyLogger < ::Logger + include ActiveSupport::LoggerSilence + end + + setup do + @io = StringIO.new + @logger = MyLogger.new(@io) + end + + test "#silence silences the log" do + @logger.silence(Logger::ERROR) do + @logger.info("Foo") + end + @io.rewind + + assert_empty @io.read + end + + test "#debug? is true when setting the temporary level to Logger::DEBUG" do + @logger.level = Logger::INFO + + @logger.silence(Logger::DEBUG) do + assert_predicate @logger, :debug? + end + + assert_predicate @logger, :info? + end +end diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb index 6b012e43af..bc8d8f1c13 100644 --- a/activesupport/test/subscriber_test.rb +++ b/activesupport/test/subscriber_test.rb @@ -23,6 +23,21 @@ class TestSubscriber < ActiveSupport::Subscriber end end +class TestSubscriber2 < ActiveSupport::Subscriber + attach_to :doodle + detach_from :doodle + + cattr_reader :events + + def self.clear + @@events = [] + end + + def open_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 @@ -34,6 +49,7 @@ end class SubscriberTest < ActiveSupport::TestCase def setup TestSubscriber.clear + TestSubscriber2.clear end def test_attaches_subscribers @@ -53,4 +69,11 @@ class SubscriberTest < ActiveSupport::TestCase assert_equal [], TestSubscriber.events end + + def test_detaches_subscribers + ActiveSupport::Notifications.instrument("open_party.doodle") + + assert_equal [], TestSubscriber2.events + assert_equal 1, TestSubscriber.events.size + end end diff --git a/activesupport/test/tagged_logging_test.rb b/activesupport/test/tagged_logging_test.rb index e2b41cf8ee..cff73472c3 100644 --- a/activesupport/test/tagged_logging_test.rb +++ b/activesupport/test/tagged_logging_test.rb @@ -19,9 +19,10 @@ class TaggedLoggingTest < ActiveSupport::TestCase test "sets logger.formatter if missing and extends it with a tagging API" do logger = Logger.new(StringIO.new) assert_nil logger.formatter - ActiveSupport::TaggedLogging.new(logger) - assert_not_nil logger.formatter - assert_respond_to logger.formatter, :tagged + + other_logger = ActiveSupport::TaggedLogging.new(logger) + assert_not_nil other_logger.formatter + assert_respond_to other_logger.formatter, :tagged end test "tagged once" do @@ -83,16 +84,28 @@ class TaggedLoggingTest < ActiveSupport::TestCase end test "keeps each tag in their own instance" do - @other_output = StringIO.new - @other_logger = ActiveSupport::TaggedLogging.new(MyLogger.new(@other_output)) + other_output = StringIO.new + other_logger = ActiveSupport::TaggedLogging.new(MyLogger.new(other_output)) @logger.tagged("OMG") do - @other_logger.tagged("BCX") do + other_logger.tagged("BCX") do @logger.info "Cool story" - @other_logger.info "Funky time" + other_logger.info "Funky time" end end assert_equal "[OMG] Cool story\n", @output.string - assert_equal "[BCX] Funky time\n", @other_output.string + assert_equal "[BCX] Funky time\n", other_output.string + end + + test "does not share the same formatter instance of the original logger" do + other_logger = ActiveSupport::TaggedLogging.new(@logger) + + @logger.tagged("OMG") do + other_logger.tagged("BCX") do + @logger.info "Cool story" + other_logger.info "Funky time" + end + end + assert_equal "[OMG] Cool story\n[BCX] Funky time\n", @output.string end test "cleans up the taggings on flush" do diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index 8698c66e6d..56cd2665e0 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -104,7 +104,7 @@ class AssertionsTest < ActiveSupport::TestCase def test_expression_is_evaluated_in_the_appropriate_scope silence_warnings do local_scope = "foo" - local_scope = local_scope # to suppress unused variable warning + _ = local_scope # to suppress unused variable warning assert_difference("local_scope; @object.num") { @object.increment } end end diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb index 0500e47def..669463bd31 100644 --- a/activesupport/test/testing/method_call_assertions_test.rb +++ b/activesupport/test/testing/method_call_assertions_test.rb @@ -36,6 +36,8 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase assert_called(@object, :increment, returns: 10) do assert_equal 10, @object.increment end + + assert_equal 1, @object.increment end def test_assert_called_failure @@ -58,18 +60,20 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase assert_match(/dang it.\nExpected increment/, error.message) end - def test_assert_called_with - assert_called_with(@object, :increment) do - @object.increment - end - end - def test_assert_called_with_arguments assert_called_with(@object, :<<, [ 2 ]) do @object << 2 end end + def test_assert_called_with_arguments_and_returns + assert_called_with(@object, :<<, [ 2 ], returns: 10) do + assert_equal(10, @object << 2) + end + + assert_nil(@object << 2) + end + def test_assert_called_with_failure assert_raises(MockExpectationError) do assert_called_with(@object, :<<, [ 4567 ]) do @@ -78,19 +82,72 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase end end - def test_assert_called_with_returns - assert_called_with(@object, :increment, returns: 1) do + def test_assert_called_with_multiple_expected_arguments + assert_called_with(@object, :<<, [ [ 1 ], [ 2 ] ]) do + @object << 1 + @object << 2 + end + end + + def test_assert_called_on_instance_of_with_defaults_to_expect_once + assert_called_on_instance_of Level, :increment do @object.increment end end - def test_assert_called_with_multiple_expected_arguments - assert_called_with(@object, :<<, [ [ 1 ], [ 2 ] ]) do - @object << 1 + def test_assert_called_on_instance_of_more_than_once + assert_called_on_instance_of(Level, :increment, times: 2) do + @object.increment + @object.increment + end + end + + def test_assert_called_on_instance_of_with_arguments + assert_called_on_instance_of(Level, :<<) do @object << 2 end end + def test_assert_called_on_instance_of_returns + assert_called_on_instance_of(Level, :increment, returns: 10) do + assert_equal 10, @object.increment + end + + assert_equal 1, @object.increment + end + + def test_assert_called_on_instance_of_failure + error = assert_raises(Minitest::Assertion) do + assert_called_on_instance_of(Level, :increment) do + # Call nothing... + end + end + + assert_equal "Expected increment to be called 1 times, but was called 0 times.\nExpected: 1\n Actual: 0", error.message + end + + def test_assert_called_on_instance_of_with_message + error = assert_raises(Minitest::Assertion) do + assert_called_on_instance_of(Level, :increment, "dang it") do + # Call nothing... + end + end + + assert_match(/dang it.\nExpected increment/, error.message) + end + + def test_assert_called_on_instance_of_nesting + assert_called_on_instance_of(Level, :increment, times: 3) do + assert_called_on_instance_of(Level, :decrement, times: 2) do + @object.increment + @object.decrement + @object.increment + @object.decrement + @object.increment + end + end + end + def test_assert_not_called assert_not_called(@object, :decrement) do @object.increment @@ -107,6 +164,30 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase assert_equal "Expected increment to be called 0 times, but was called 1 times.\nExpected: 0\n Actual: 1", error.message end + def test_assert_not_called_on_instance_of + assert_not_called_on_instance_of(Level, :decrement) do + @object.increment + end + end + + def test_assert_not_called_on_instance_of_failure + error = assert_raises(Minitest::Assertion) do + assert_not_called_on_instance_of(Level, :increment) do + @object.increment + end + end + + assert_equal "Expected increment to be called 0 times, but was called 1 times.\nExpected: 0\n Actual: 1", error.message + end + + def test_assert_not_called_on_instance_of_nesting + assert_not_called_on_instance_of(Level, :increment) do + assert_not_called_on_instance_of(Level, :decrement) do + # Call nothing... + end + end + end + def test_stub_any_instance stub_any_instance(Level) do |instance| assert_equal instance, Level.new diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb index 9c2c635f43..a1f84bf69e 100644 --- a/activesupport/test/time_travel_test.rb +++ b/activesupport/test/time_travel_test.rb @@ -3,24 +3,25 @@ require "abstract_unit" require "active_support/core_ext/date_time" require "active_support/core_ext/numeric/time" +require "time_zone_test_helpers" class TimeTravelTest < ActiveSupport::TestCase + include TimeZoneTestHelpers + class TimeSubclass < ::Time; end class DateSubclass < ::Date; end class DateTimeSubclass < ::DateTime; end def test_time_helper_travel Time.stub(:now, Time.now) do - begin - expected_time = Time.now + 1.day - travel 1.day + 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 - assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) - ensure - travel_back - end + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_equal expected_time.to_date, Date.today + assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) + ensure + travel_back end end @@ -42,16 +43,14 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_to Time.stub(:now, Time.now) do - begin - expected_time = Time.new(2004, 11, 24, 01, 04, 44) - travel_to expected_time + 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 - assert_equal expected_time.to_datetime, DateTime.now - ensure - travel_back - end + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + ensure + travel_back end end @@ -71,23 +70,35 @@ class TimeTravelTest < ActiveSupport::TestCase end end + def test_time_helper_travel_to_with_time_zone + with_env_tz "US/Eastern" do + with_tz_default ActiveSupport::TimeZone["UTC"] do + Time.stub(:now, Time.now) do + expected_time = 5.minutes.ago + + travel_to 5.minutes.ago do + assert_equal expected_time.to_s(:db), Time.zone.now.to_s(:db) + end + end + end + end + end + def test_time_helper_travel_back Time.stub(:now, Time.now) do - begin - expected_time = Time.new(2004, 11, 24, 01, 04, 44) + 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 - assert_equal expected_time.to_datetime, DateTime.now - travel_back + travel_to expected_time + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + travel_back - assert_not_equal expected_time, Time.now - assert_not_equal Date.new(2004, 11, 24), Date.today - assert_not_equal expected_time.to_datetime, DateTime.now - ensure - travel_back - end + assert_not_equal expected_time, Time.now + assert_not_equal Date.new(2004, 11, 24), Date.today + assert_not_equal expected_time.to_datetime, DateTime.now + ensure + travel_back end end @@ -122,24 +133,22 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_to_with_subsequent_calls Time.stub(:now, Time.now) do - begin - initial_expected_time = Time.new(2004, 11, 24, 01, 04, 44) - subsequent_expected_time = Time.new(2004, 10, 24, 01, 04, 44) - assert_nothing_raised do - travel_to initial_expected_time - travel_to subsequent_expected_time + initial_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + subsequent_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + assert_nothing_raised do + travel_to initial_expected_time + travel_to subsequent_expected_time - assert_equal subsequent_expected_time, Time.now + assert_equal subsequent_expected_time, Time.now - travel_back - end - ensure travel_back end + ensure + travel_back end end - def test_travel_to_will_reset_the_usec_to_avoid_mysql_rouding + def test_travel_to_will_reset_the_usec_to_avoid_mysql_rounding Time.stub(:now, Time.now) do travel_to Time.utc(2014, 10, 10, 10, 10, 50, 999999) do assert_equal 50, Time.now.sec @@ -186,4 +195,8 @@ class TimeTravelTest < ActiveSupport::TestCase assert_operator expected_time.to_s(:db), :<, Time.now.to_s(:db) end + + def test_time_helper_unfreeze_time + assert_equal method(:travel_back), method(:unfreeze_time) + end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 6d45a6726d..f948c363df 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -32,7 +32,7 @@ class TimeZoneTest < ActiveSupport::TestCase end end - def test_period_for_local_with_ambigiuous_time + def test_period_for_local_with_ambiguous_time zone = ActiveSupport::TimeZone["Moscow"] period = zone.period_for_local(Time.utc(2015, 1, 1)) assert_equal period, zone.period_for_local(Time.utc(2014, 10, 26, 1, 0, 0)) diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb index 7d19447598..9e29a93ea0 100644 --- a/activesupport/test/transliterate_test.rb +++ b/activesupport/test/transliterate_test.rb @@ -30,6 +30,12 @@ class TransliterateTest < ActiveSupport::TestCase I18n.locale = default_locale end + def test_transliterate_respects_the_locale_argument + char = [117, 776].pack("U*") # "ü" as ASCII "u" plus COMBINING DIAERESIS + I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } }) + assert_equal "ue", ActiveSupport::Inflector.transliterate(char, locale: :de) + end + def test_transliterate_should_allow_a_custom_replacement_char assert_equal "a*b", ActiveSupport::Inflector.transliterate("a索b", "*") end diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb index 34bf81fa75..b711619ba7 100644 --- a/activesupport/test/xml_mini/rexml_engine_test.rb +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -12,7 +12,7 @@ class REXMLEngineTest < XMLMiniEngineTest end def test_parse_from_frozen_string - xml_string = "<root></root>".freeze + xml_string = "<root></root>" assert_equal({ "root" => {} }, ActiveSupport::XmlMini.parse(xml_string)) end diff --git a/activesupport/test/xml_mini/xml_mini_engine_test.rb b/activesupport/test/xml_mini/xml_mini_engine_test.rb index 5c4c28d9b7..c62e7e32c9 100644 --- a/activesupport/test/xml_mini/xml_mini_engine_test.rb +++ b/activesupport/test/xml_mini/xml_mini_engine_test.rb @@ -78,7 +78,7 @@ class XMLMiniEngineTest < ActiveSupport::TestCase end def test_parse_from_frozen_string - xml_string = "<root/>".freeze + xml_string = "<root/>" assert_equal({ "root" => {} }, ActiveSupport::XmlMini.parse(xml_string)) end |