diff options
Diffstat (limited to 'activesupport')
21 files changed, 337 insertions, 42 deletions
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 3c422e0252..448db538ab 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -99,11 +99,16 @@ module ActiveSupport class Store cattr_accessor :logger + attr_reader :silence, :logger_off + def silence! @silence = true self end + alias silence? silence + alias logger_off? logger_off + # Fetches data from the cache, using the given key. If there is data in # the cache with the given key, then that data is returned. # @@ -233,11 +238,15 @@ module ActiveSupport private def expires_in(options) - (options && options[:expires_in]) || 0 + expires_in = options && options[:expires_in] + + raise ":expires_in must be a number" if expires_in && !expires_in.is_a?(Numeric) + + expires_in || 0 end def log(operation, key, options) - logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !@silence && !@logger_off + logger.debug("Cache #{operation}: #{key}#{options ? " (#{options.inspect})" : ""}") if logger && !silence? && !logger_off? end end end diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 1b30d49155..21ba79cf3d 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -26,7 +26,7 @@ module ActiveSupport def write(name, value, options = nil) super - @data[name] = value.freeze + @data[name] = (value.duplicable? ? value.dup : value).freeze end def delete(name, options = nil) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index a44344806d..11e01437aa 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -108,14 +108,21 @@ class Module prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" - allow_nil = options[:allow_nil] && "#{to} && " - - file, line = caller[0].split(":") + file, line = caller.first.split(':', 2) + line = line.to_i methods.each do |method| - module_eval(<<-EOS, file, line.to_i) + on_nil = + if options[:allow_nil] + 'return' + else + %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") + end + + module_eval(<<-EOS, file, line) def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) - #{allow_nil}#{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block) + #{on_nil} if #{to}.nil? + #{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block) end # end EOS end diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index ff70d6d76e..92c1de057b 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -183,7 +183,7 @@ module ActiveSupport if first_letter_in_uppercase lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } else - lower_case_and_underscored_word.first.downcase + camelize(lower_case_and_underscored_word)[1..-1] + lower_case_and_underscored_word.to_s.first.downcase + camelize(lower_case_and_underscored_word)[1..-1] end end diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 068b58b997..f440d6ce58 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,5 +1,7 @@ -# encoding: binary +# encoding: utf-8 require 'active_support/core_ext/array/wrap' +require 'active_support/core_ext/hash/except' +require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/instance_variables' require 'active_support/deprecation' @@ -95,12 +97,14 @@ module ActiveSupport def escape(string) string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding) - json = '"' + string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] } - json.gsub(/([\xC0-\xDF][\x80-\xBF]| + json = string. + gsub(escape_regex) { |s| ESCAPED_CHARS[s] }. + gsub(/([\xC0-\xDF][\x80-\xBF]| [\xE0-\xEF][\x80-\xBF]{2}| [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| - s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&') - } + '"' + s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&') + } + %("#{json}") end end diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index bab2a401eb..d5282bad6a 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -1,5 +1,13 @@ +require 'test/unit/testcase' +require 'active_support/testing/setup_and_teardown' +require 'active_support/testing/assertions' +require 'active_support/testing/deprecation' +require 'active_support/testing/declarative' +require 'active_support/testing/pending' +require 'active_support/testing/isolation' + begin - gem 'mocha', '>= 0.9.3' + gem 'mocha', ">= 0.9.7" require 'mocha' rescue LoadError # Fake Mocha::ExpectationError so we can rescue it in #run. Bleh. @@ -7,13 +15,6 @@ rescue LoadError Mocha.const_set :ExpectationError, Class.new(StandardError) end -require 'test/unit/testcase' -require 'active_support/testing/setup_and_teardown' -require 'active_support/testing/assertions' -require 'active_support/testing/deprecation' -require 'active_support/testing/declarative' -require 'active_support/testing/pending' - module ActiveSupport class TestCase < ::Test::Unit::TestCase if defined? MiniTest diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb index a7af7f4224..a7df473644 100644 --- a/activesupport/lib/active_support/testing/declarative.rb +++ b/activesupport/lib/active_support/testing/declarative.rb @@ -15,12 +15,6 @@ module ActiveSupport end end - if defined?(Spec) - class << self - alias_method :test, :it - end - end - end end diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb new file mode 100644 index 0000000000..090e0c5c89 --- /dev/null +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -0,0 +1,98 @@ +module ActiveSupport::Testing + class ProxyTestResult + def initialize + @calls = [] + end + + def __replay__(result) + @calls.each do |name, args| + result.send(name, *args) + end + end + + def method_missing(name, *args) + @calls << [name, args] + end + end + + module Isolation + def self.forking_env? + !ENV["NO_FORK"] && RUBY_PLATFORM !~ /mswin|mingw|java/ + end + + def run(result) + yield(Test::Unit::TestCase::STARTED, name) + + @_result = result + + proxy = run_in_isolation do |proxy| + super(proxy) { } + end + + proxy.__replay__(@_result) + + yield(Test::Unit::TestCase::FINISHED, name) + end + + module Forking + def run_in_isolation(&blk) + read, write = IO.pipe + + pid = fork do + read.close + proxy = ProxyTestResult.new + yield proxy + write.puts [Marshal.dump(proxy)].pack("m") + exit! + end + + write.close + result = read.read + Process.wait2(pid) + Marshal.load(result.unpack("m")[0]) + end + end + + module Subprocess + # Crazy H4X to get this working in windows / jruby with + # no forking. + def run_in_isolation(&blk) + require "tempfile" + + if ENV["ISOLATION_TEST"] + proxy = ProxyTestResult.new + yield proxy + File.open(ENV["ISOLATION_OUTPUT"], "w") do |file| + file.puts [Marshal.dump(proxy)].pack("m") + end + exit! + else + Tempfile.open("isolation") do |tmpfile| + ENV["ISOLATION_TEST"] = @method_name + ENV["ISOLATION_OUTPUT"] = tmpfile.path + + load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ") + `#{Gem.ruby} #{load_paths} #{$0} #{ORIG_ARGV.join(" ")} -t\"#{self.class}\"` + + ENV.delete("ISOLATION_TEST") + ENV.delete("ISOLATION_OUTPUT") + + return Marshal.load(tmpfile.read.unpack("m")[0]) + end + end + end + end + + include forking_env? ? Forking : Subprocess + end +end + +# Only in subprocess for windows / jruby. +if ENV['ISOLATION_TEST'] + require "test/unit/collector/objectspace" + class Test::Unit::Collector::ObjectSpace + def include?(test) + super && test.method_name == ENV['ISOLATION_TEST'] + end + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 4537c30e9c..b59ac79e7b 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -10,8 +10,6 @@ module ActiveSupport if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions include ForMiniTest - elsif defined? Spec - include ForRspec else include ForClassicTestUnit end diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb index dfcba6901f..4e78e71b34 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb @@ -2,7 +2,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'active_support' diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb index 50d6832c9e..2835ec4eab 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb @@ -2,7 +2,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'active_support' diff --git a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb index 65f3ac11a6..a1696c77f6 100644 --- a/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb +++ b/activesupport/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb @@ -3,7 +3,6 @@ $:.unshift "lib" require 'rubygems' require 'test/unit' -require 'mocha' require 'i18n' require 'time' require 'yaml' diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index 30f598a8de..3ae6150f2d 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -1,8 +1,8 @@ module ActiveSupport module VERSION #:nodoc: - MAJOR = 2 - MINOR = 3 - TINY = 2 + MAJOR = 3 + MINOR = 0 + TINY = "pre" STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index 428a06b0bf..61914231ef 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,9 +1,8 @@ +ORIG_ARGV = ARGV.dup + require 'rubygems' require 'test/unit' -gem 'mocha', '>= 0.9.5' -require 'mocha' - ENV['NO_RELOAD'] = '1' $:.unshift "#{File.dirname(__FILE__)}/../lib" require 'active_support' diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index c2a03818e1..7667f11343 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -1,3 +1,4 @@ +require 'logger' require 'abstract_unit' require 'active_support/cache' @@ -176,6 +177,12 @@ class MemoryStoreTest < ActiveSupport::TestCase assert_raise(ActiveSupport::FrozenObjectError) { @cache.read('foo').gsub!(/.*/, 'baz') } assert_equal 'bar', @cache.read('foo') end + + def test_original_store_objects_should_not_be_immutable + bar = 'bar' + @cache.write('foo', bar) + assert_nothing_raised { bar.gsub!(/.*/, 'baz') } + end end uses_memcached 'memcached backed store' do @@ -184,6 +191,8 @@ uses_memcached 'memcached backed store' do @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store) @data = @cache.instance_variable_get(:@data) @cache.clear + @cache.silence! + @cache.logger = Logger.new("/dev/null") end include CacheStoreBehavior @@ -306,6 +315,22 @@ uses_memcached 'memcached backed store' do app = @cache.middleware.new(app) app.call({}) end + + def test_expires_in + result = @cache.write('foo', 'bar', :expires_in => 1) + assert_equal 'bar', @cache.read('foo') + sleep 2 + assert_equal nil, @cache.read('foo') + end + + def test_expires_in_with_invalid_value + @cache.write('baz', 'bat') + assert_raise(RuntimeError) do + @cache.write('foo', 'bar', :expires_in => 'Mon Jun 29 13:10:40 -0700 2150') + end + assert_equal 'bat', @cache.read('baz') + assert_equal nil, @cache.read('foo') + end end class CompressedMemCacheStore < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index c3c696f93a..f8387ae4ab 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -142,7 +142,7 @@ class ModuleTest < Test::Unit::TestCase def test_delegation_without_allow_nil_and_nil_value david = Someone.new("David") - assert_raise(NoMethodError) { david.street } + assert_raise(RuntimeError) { david.street } end def test_parent diff --git a/activesupport/test/fixtures/omgomg.rb b/activesupport/test/fixtures/omgomg.rb new file mode 100644 index 0000000000..a512a93ae4 --- /dev/null +++ b/activesupport/test/fixtures/omgomg.rb @@ -0,0 +1,2 @@ +class OmgOmg +end
\ No newline at end of file diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 8c4d831a39..7d1554910e 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -202,6 +202,12 @@ class InflectorTest < Test::Unit::TestCase end end + def test_symbol_to_lower_camel + SymbolToLowerCamel.each do |symbol, lower_camel| + assert_equal(lower_camel, ActiveSupport::Inflector.camelize(symbol, false)) + end + end + %w{plurals singulars uncountables humans}.each do |inflection_type| class_eval " def test_clear_#{inflection_type} diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index 584cbff3e7..2fa94b8e9c 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -117,6 +117,13 @@ module InflectorTestCases "area51_controller" => "area51Controller" } + SymbolToLowerCamel = { + :product => 'product', + :special_guest => 'specialGuest', + :application_controller => 'applicationController', + :area51_controller => 'area51Controller' + } + CamelToUnderscoreWithoutReverse = { "HTMLTidy" => "html_tidy", "HTMLTidyGenerator" => "html_tidy_generator", diff --git a/activesupport/test/isolation_test.rb b/activesupport/test/isolation_test.rb new file mode 100644 index 0000000000..b844bbb673 --- /dev/null +++ b/activesupport/test/isolation_test.rb @@ -0,0 +1,143 @@ +require 'abstract_unit' + +# Does awesome +if ENV['CHILD'] + class ChildIsolationTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + @instance = "HELLO" + end + + def teardown + raise if @boom + end + + test "runs the test" do + assert true + end + + test "captures errors" do + raise + end + + test "captures failures" do + assert false + end + + test "first runs in isolation" do + assert_nil $x + $x = 1 + end + + test "second runs in isolation" do + assert_nil $x + $x = 2 + end + + test "runs with slow tests" do + sleep 0.3 + assert true + sleep 0.2 + end + + test "runs setup" do + assert "HELLO", @instance + end + + test "runs teardown" do + @boom = true + end + + test "resets requires one" do + assert !defined?(OmgOmg) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + end + + test "resets requires two" do + assert !defined?(OmgOmg) + assert_equal 0, $LOADED_FEATURES.grep(/fixtures\/omgomg/).size + require File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "omgomg")) + end + end +else + class ParentIsolationTest < ActiveSupport::TestCase + + ENV["CHILD"] = "1" + OUTPUT = `#{Gem.ruby} -I#{File.dirname(__FILE__)} #{File.expand_path(__FILE__)} -v` + ENV.delete("CHILD") + + def setup + # Extract the results + @results = {} + OUTPUT[/Started\n\s*(.*)\s*\nFinished/mi, 1].split(/\s*\n\s*/).each do |result| + result =~ %r'^(\w+)\(\w+\):\s*(\.|E|F)$' + @results[$1] = { 'E' => :error, '.' => :success, 'F' => :failure }[$2] + end + + # Extract the backtraces + @backtraces = {} + OUTPUT.scan(/^\s*\d+\).*?\n\n/m).each do |backtrace| + # \n 1) Error:\ntest_captures_errors(ChildIsolationTest): + backtrace =~ %r'\s*\d+\)\s*(Error|Failure):\n(\w+)'i + @backtraces[$2] = { :type => $1, :output => backtrace } + end + end + + def assert_failing(name) + assert_equal :failure, @results[name.to_s], "Test #{name} did not fail" + end + + def assert_passing(name) + assert_equal :success, @results[name.to_s], "Test #{name} did not pass" + end + + def assert_erroring(name) + assert_equal :error, @results[name.to_s], "Test #{name} did not error" + end + + test "has all tests" do + assert_equal 10, @results.length + end + + test "passing tests are still reported" do + assert_passing :test_runs_the_test + assert_passing :test_runs_with_slow_tests + end + + test "resets global variables" do + assert_passing :test_first_runs_in_isolation + assert_passing :test_second_runs_in_isolation + end + + test "resets requires" do + assert_passing :test_resets_requires_one + assert_passing :test_resets_requires_two + end + + test "erroring tests are still reported" do + assert_erroring :test_captures_errors + end + + test "runs setup and teardown methods" do + assert_passing :test_runs_setup + assert_erroring :test_runs_teardown + end + + test "correct tests fail" do + assert_failing :test_captures_failures + end + + test "backtrace is printed for errors" do + assert_equal 'Error', @backtraces["test_captures_errors"][:type] + assert_match %{isolation_test.rb:21:in `test_captures_errors'}, @backtraces["test_captures_errors"][:output] + end + + test "backtrace is printed for failures" do + assert_equal 'Failure', @backtraces["test_captures_failures"][:type] + assert_match %{isolation_test.rb:25:in `test_captures_failures'}, @backtraces["test_captures_failures"][:output] + end + + end +end
\ No newline at end of file diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 983235d06c..5d81d09f03 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -75,8 +75,13 @@ class TestJSONEncoding < Test::Unit::TestCase def test_utf8_string_encoded_properly_when_kcode_is_utf8 with_kcode 'UTF8' do - assert_equal '"\\u20ac2.99"', ActiveSupport::JSON.encode('€2.99') - assert_equal '"\\u270e\\u263a"', ActiveSupport::JSON.encode('✎☺') + result = ActiveSupport::JSON.encode('€2.99') + assert_equal '"\\u20ac2.99"', result + assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding) + + result = ActiveSupport::JSON.encode('✎☺') + assert_equal '"\\u270e\\u263a"', result + assert_equal(Encoding::UTF_8, result.encoding) if result.respond_to?(:encoding) end end |