From e1a340a91d4ee0bbbe8ce1a74b88b3f7e80c1197 Mon Sep 17 00:00:00 2001 From: Comron Sattari Date: Sun, 2 May 2010 13:09:22 +0200 Subject: cache connection when quoting [#3642 state:committed] Signed-off-by: Marius Nuennerich Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/base.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c02af328c1..37675d8ab1 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1362,7 +1362,8 @@ module ActiveRecord #:nodoc: def replace_bind_variables(statement, values) #:nodoc: raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) bound = values.dup - statement.gsub('?') { quote_bound_value(bound.shift) } + c = connection + statement.gsub('?') { quote_bound_value(bound.shift, c) } end def replace_named_bind_variables(statement, bind_vars) #:nodoc: @@ -1394,15 +1395,15 @@ module ActiveRecord #:nodoc: expanded end - def quote_bound_value(value) #:nodoc: + def quote_bound_value(value, c = connection) #:nodoc: if value.respond_to?(:map) && !value.acts_like?(:string) if value.respond_to?(:empty?) && value.empty? - connection.quote(nil) + c.quote(nil) else - value.map { |v| connection.quote(v) }.join(',') + value.map { |v| c.quote(v) }.join(',') end else - connection.quote(value) + c.quote(value) end end -- cgit v1.2.3 From 4db10bce7b5ca794c4d408de3b8002bf58233bb7 Mon Sep 17 00:00:00 2001 From: pleax Date: Mon, 17 May 2010 01:47:56 +0400 Subject: AR::Base#clone fixed to set dirty bits for cloned object [#2919 state:committed] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/base.rb | 8 +++++- activerecord/test/cases/base_test.rb | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 37675d8ab1..18f75af11b 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1463,12 +1463,18 @@ module ActiveRecord #:nodoc: callback(:after_initialize) if respond_to_without_attributes?(:after_initialize) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) + @attributes = cloned_attributes + + @changed_attributes = {} + attributes_from_column_definition.each do |attr, orig_value| + @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) + end + clear_aggregation_cache @attributes_cache = {} @new_record = true ensure_proper_type - @changed_attributes = other.changed_attributes.dup if scope = self.class.send(:current_scoped_methods) create_with = scope.scope_for_create diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b7ae619787..7c4d92f3f8 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1456,6 +1456,56 @@ class BasicsTest < ActiveRecord::TestCase assert_kind_of Client, clone end + def test_clone_of_new_object_with_defaults + developer = Developer.new + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert !cloned_developer.name_changed? + assert !cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_attributes_as_dirty + developer = Developer.new :name => 'Bjorn', :salary => 100000 + assert developer.name_changed? + assert developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_as_dirty_only_changed_attributes + developer = Developer.new :name => 'Bjorn' + assert developer.name_changed? # obviously + assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert !cloned_developer.salary_changed? # ... and cloned instance should behave same + end + + def test_clone_of_saved_object_marks_attributes_as_dirty + developer = Developer.create! :name => 'Bjorn', :salary => 100000 + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # both attributes differ from defaults + assert cloned_developer.salary_changed? + end + + def test_clone_of_saved_object_marks_as_dirty_only_changed_attributes + developer = Developer.create! :name => 'Bjorn' + assert !developer.name_changed? # both attributes of saved object should be threated as not changed + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # ... but on cloned object should be + assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be threated as not changed on cloned instance + end + def test_bignum company = Company.find(1) company.rating = 2147483647 -- cgit v1.2.3 From a06e9b46021acac1832b7df672213e5218ec29b5 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sun, 16 May 2010 18:03:27 -0700 Subject: Ruby 1.9: helper path may be a pathname, so convert to a string before quoting for regexp --- actionpack/lib/action_controller/metal/helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 1110d7c117..b6d4fb1284 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -104,7 +104,7 @@ module ActionController def all_application_helpers helpers = [] helpers_path.each do |path| - extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ + extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/ helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } end helpers.sort! -- cgit v1.2.3 From c2fb8afaa0e6a8f3d1782c97790a4bea8d4f0b0b Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 17 May 2010 08:19:48 +0200 Subject: Use assert_equal correctly in transaction callback tests (exposing some of them as broken) [#4612] Signed-off-by: Jeremy Kemper --- .../test/cases/transaction_callbacks_test.rb | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index a07da093f1..9c74dce965 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -54,7 +54,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.history << :after_rollback} @first.save! - assert @first.history, [:after_commit] + assert_equal [:after_commit], @first.history end def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record @@ -67,7 +67,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} @first.save! - assert @first.history, [:commit_on_update] + assert_equal [:commit_on_update], @first.history end def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record @@ -80,7 +80,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} @first.destroy - assert @first.history, [:commit_on_destroy] + assert_equal [:commit_on_destroy], @first.history end def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record @@ -93,7 +93,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} @new_record.save! - assert @new_record.history, [:commit_on_create] + assert_equal [:commit_on_create], @new_record.history end def test_call_after_rollback_after_transaction_rollsback @@ -105,7 +105,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert @first.history, [:after_rollback] + assert_equal [:after_rollback], @first.history end def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record @@ -122,7 +122,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert @first.history, [:rollback_on_update] + assert_equal [:rollback_on_update], @first.history end def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record @@ -139,7 +139,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert @first.history, [:rollback_on_destroy] + assert_equal [:rollback_on_destroy], @first.history end def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record @@ -156,7 +156,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert @new_record.history, [:rollback_on_create] + assert_equal [:rollback_on_create], @new_record.history end def test_call_after_rollback_when_commit_fails @@ -170,7 +170,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.history << :after_rollback} assert !@first.save rescue nil - assert @first.history == [:after_rollback] + assert_equal [:after_rollback], @first.history ensure @first.connection.class.send(:remove_method, :commit_db_transaction) @first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) @@ -196,10 +196,10 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end end - assert 1, @first.commits - assert 0, @first.rollbacks - assert 1, @second.commits - assert 1, @second.rollbacks + assert_equal 1, @first.commits + assert_equal 0, @first.rollbacks + assert_equal 1, @second.commits + assert_equal 1, @second.rollbacks end def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails @@ -221,8 +221,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end end - assert 1, @first.commits - assert 2, @first.rollbacks + assert_equal 1, @first.commits + assert_equal 2, @first.rollbacks end def test_after_transaction_callbacks_should_not_raise_errors @@ -232,13 +232,13 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";} @first.save! - assert_equal @first.last_after_transaction_error, :commit + assert_equal :commit, @first.last_after_transaction_error Topic.transaction do @first.save! raise ActiveRecord::Rollback end - assert_equal @first.last_after_transaction_error, :rollback + assert_equal :rollback, @first.last_after_transaction_error end end -- cgit v1.2.3 From 5371242384171dc0255716e31e9257ddeec17d10 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 17 May 2010 07:58:26 -0700 Subject: Valid hex strings aren't valid float column values, to match the integer restriction. [#4622 state:resolved] --- activemodel/lib/active_model/validations/numericality.rb | 11 ++++++++--- .../test/cases/validations/numericality_validation_test.rb | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 716010e88b..ac8308b0d7 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -57,10 +57,15 @@ module ActiveModel protected def parse_raw_value_as_a_number(raw_value) - begin - Kernel.Float(raw_value) - rescue ArgumentError, TypeError + case raw_value + when /\A0x/ nil + else + begin + Kernel.Float(raw_value) + rescue ArgumentError, TypeError + nil + end end end diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index be620c53fa..963ad6450b 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -18,7 +18,7 @@ class NumericalityValidationTest < ActiveModel::TestCase FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS INTEGERS = [0, 10, -10] + INTEGER_STRINGS BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) } - JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] + JUNK = ["not a number", "42 not a number", "0xdeadbeef", "0xinvalidhex", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] INFINITY = [1.0/0.0] def test_default_validates_numericality_of -- cgit v1.2.3 From 107c6381a0a3403461f1dc00e140565028af73e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 17 May 2010 17:36:34 +0200 Subject: Allow root to be given in the resources scope without need to specify :on => collection. --- actionpack/lib/action_dispatch/routing/mapper.rb | 5 +++++ actionpack/test/dispatch/routing_test.rb | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 4b02c2deb3..8a8d21c434 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -693,6 +693,11 @@ module ActionDispatch super end + def root(options={}) + options[:on] ||= :collection if @scope[:scope_level] == :resources + super(options) + end + protected def parent_resource #:nodoc: @scope[:scope_level_resource] diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 651a7a6be0..180889ddf2 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -186,6 +186,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resources :products, :constraints => { :id => /\d{4}/ } do + root :to => "products#root" + get :favorite, :on => :collection resources :images end @@ -963,7 +965,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/products/1' assert_equal 'pass', @response.headers['X-Cascade'] get '/products' - assert_equal 'products#index', @response.body + assert_equal 'products#root', @response.body + get '/products/favorite' + assert_equal 'products#favorite', @response.body get '/products/0001' assert_equal 'products#show', @response.body @@ -981,6 +985,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_root_works_in_the_resources_scope + get '/products' + assert_equal 'products#root', @response.body + assert_equal '/products', products_root_path + end + def test_module_scope with_test_routes do get '/token' -- cgit v1.2.3 From c7e6777961239224e28171a46c9768db881c5506 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 16 May 2010 18:00:08 -0300 Subject: Added default currency values to NumberHelper and pass them to I18n.translate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4604 state:committed] Signed-off-by: José Valim --- actionpack/lib/action_view/helpers/number_helper.rb | 7 +++++-- actionpack/test/template/number_helper_i18n_test.rb | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 01fecc0f23..fccf004adf 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -13,6 +13,9 @@ module ActionView # unchanged if can't be converted into a valid number. module NumberHelper + DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",", + :precision => 2, :significant => false, :strip_insignificant_zeros => false } + # Raised when argument +number+ param given to the helpers is invalid and # the option :raise is set to +true+. class InvalidNumberError < StandardError @@ -104,9 +107,9 @@ module ActionView defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {}) currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {}) - defaults = defaults.merge(currency) - options = options.reverse_merge(defaults) + defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency) + options = defaults.merge!(options) unit = options.delete(:unit) format = options.delete(:format) diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb index f730a0d7f5..8561019461 100644 --- a/actionpack/test/template/number_helper_i18n_test.rb +++ b/actionpack/test/template/number_helper_i18n_test.rb @@ -45,6 +45,12 @@ class NumberHelperTest < ActionView::TestCase assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) end + def test_number_to_currency_with_clean_i18n_settings + clean_i18n do + assert_equal("$10.00", number_to_currency(10)) + end + end + def test_number_with_precision #Delimiter was set to "" assert_equal("10000", number_with_precision(10000, :locale => 'ts')) @@ -92,4 +98,15 @@ class NumberHelperTest < ActionView::TestCase #Significant was set to true with precision 2, with custom translated units assert_equal "4.3 cm", number_to_human(0.0432, :locale => 'ts', :units => :custom_units_for_number_to_human) end + + private + def clean_i18n + load_path = I18n.load_path.dup + I18n.load_path.clear + I18n.reload! + yield + ensure + I18n.load_path = load_path + I18n.reload! + end end -- cgit v1.2.3 From 02c36cf5cb736a6c7321c8cb9a632a3a74344f25 Mon Sep 17 00:00:00 2001 From: wycats Date: Mon, 17 May 2010 19:39:38 +0400 Subject: Make sure encoding changes don't break 1.8 --- actionpack/lib/action_view/template/handlers/erb.rb | 4 +++- actionpack/test/template/template_test.rb | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index bbf012ab15..cbed0108cf 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -7,7 +7,7 @@ module ActionView class OutputBuffer < ActiveSupport::SafeBuffer def initialize(*) super - encode! + encode! if encoding_aware? end def <<(value) @@ -106,6 +106,8 @@ module ActionView if !encoding && (template.source.encoding == Encoding::BINARY) raise WrongEncodingError.new(template_source, Encoding.default_external) end + else + erb = template.source.dup end result = self.class.erb_implementation.new( diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb index c4a65d84fc..995d728d50 100644 --- a/actionpack/test/template/template_test.rb +++ b/actionpack/test/template/template_test.rb @@ -1,9 +1,11 @@ require "abstract_unit" -# These are the normal settings that will be set up by Railties -# TODO: Have these tests support other combinations of these values -Encoding.default_internal = "UTF-8" -Encoding.default_external = "UTF-8" +if "ruby".encoding_aware? + # These are the normal settings that will be set up by Railties + # TODO: Have these tests support other combinations of these values + Encoding.default_internal = "UTF-8" + Encoding.default_external = "UTF-8" +end class TestERBTemplate < ActiveSupport::TestCase ERBHandler = ActionView::Template::Handlers::ERB -- cgit v1.2.3 From 80b60671f7216c571ea8711d1de8ca824aefbe54 Mon Sep 17 00:00:00 2001 From: wycats Date: Mon, 17 May 2010 19:41:54 +0400 Subject: Revert "Moved encoding work in progress to a feature branch." This reverts commit ade756fe42423033bae8e5aea8f58782f7a6c517. --- actionpack/lib/action_view.rb | 6 +- actionpack/lib/action_view/template.rb | 195 ++++++++++++++++++--- actionpack/lib/action_view/template/error.rb | 18 ++ .../lib/action_view/template/handlers/erb.rb | 137 ++++++++++----- actionpack/lib/action_view/template/resolver.rb | 5 +- actionpack/test/abstract_unit.rb | 4 + actionpack/test/controller/assert_select_test.rb | 4 +- actionpack/test/controller/capture_test.rb | 2 +- actionpack/test/controller/render_test.rb | 4 +- actionpack/test/fixtures/test/content_for.erb | 3 +- .../fixtures/test/content_for_concatenated.erb | 2 +- .../fixtures/test/content_for_with_parameter.erb | 2 +- .../test/non_erb_block_content_for.builder | 2 +- actionpack/test/template/render_test.rb | 10 +- actionpack/test/template/template_test.rb | 128 ++++++++++++++ .../lib/active_support/core_ext/string/encoding.rb | 11 ++ activesupport/lib/active_support/ruby/shim.rb | 1 + activesupport/test/core_ext/string_ext_test.rb | 8 + railties/guides/source/getting_started.textile | 21 +++ railties/lib/rails.rb | 1 + railties/lib/rails/application/configuration.rb | 10 +- railties/test/application/configuration_test.rb | 3 +- 22 files changed, 488 insertions(+), 89 deletions(-) create mode 100644 actionpack/test/template/template_test.rb create mode 100644 activesupport/lib/active_support/core_ext/string/encoding.rb diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 5555217ee2..9f56cca869 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -51,13 +51,17 @@ module ActionView autoload :MissingTemplate, 'action_view/template/error' autoload :ActionViewError, 'action_view/template/error' - autoload :TemplateError, 'action_view/template/error' + autoload :EncodingError, 'action_view/template/error' + autoload :TemplateError, 'action_view/template/error' + autoload :WrongEncodingError, 'action_view/template/error' autoload :TemplateHandler, 'action_view/template' autoload :TemplateHandlers, 'action_view/template' end autoload :TestCase, 'action_view/test_case' + + ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' end require 'active_support/i18n' diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index a1a970e2d2..5d8ac6b115 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,12 +1,89 @@ -# encoding: utf-8 -# This is so that templates compiled in this file are UTF-8 require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/kernel/singleton_class' module ActionView class Template extend ActiveSupport::Autoload + # === Encodings in ActionView::Template + # + # ActionView::Template is one of a few sources of potential + # encoding issues in Rails. This is because the source for + # templates are usually read from disk, and Ruby (like most + # encoding-aware programming languages) assumes that the + # String retrieved through File IO is encoded in the + # default_external encoding. In Rails, the default + # default_external encoding is UTF-8. + # + # As a result, if a user saves their template as ISO-8859-1 + # (for instance, using a non-Unicode-aware text editor), + # and uses characters outside of the ASCII range, their + # users will see diamonds with question marks in them in + # the browser. + # + # To mitigate this problem, we use a few strategies: + # 1. If the source is not valid UTF-8, we raise an exception + # when the template is compiled to alert the user + # to the problem. + # 2. The user can specify the encoding using Ruby-style + # encoding comments in any template engine. If such + # a comment is supplied, Rails will apply that encoding + # to the resulting compiled source returned by the + # template handler. + # 3. In all cases, we transcode the resulting String to + # the default_internal encoding (which defaults + # to UTF-8). + # + # This means that other parts of Rails can always assume + # that templates are encoded in UTF-8, even if the original + # source of the template was not UTF-8. + # + # From a user's perspective, the easiest thing to do is + # to save your templates as UTF-8. If you do this, you + # do not need to do anything else for things to "just work". + # + # === Instructions for template handlers + # + # The easiest thing for you to do is to simply ignore + # encodings. Rails will hand you the template source + # as the default_internal (generally UTF-8), raising + # an exception for the user before sending the template + # to you if it could not determine the original encoding. + # + # For the greatest simplicity, you can support only + # UTF-8 as the default_internal. This means + # that from the perspective of your handler, the + # entire pipeline is just UTF-8. + # + # === Advanced: Handlers with alternate metadata sources + # + # If you want to provide an alternate mechanism for + # specifying encodings (like ERB does via <%# encoding: ... %>), + # you may indicate that you are willing to accept + # BINARY data by implementing self.accepts_binary? + # on your handler. + # + # If you do, Rails will not raise an exception if + # the template's encoding could not be determined, + # assuming that you have another mechanism for + # making the determination. + # + # In this case, make sure you return a String from + # your handler encoded in the default_internal. Since + # you are handling out-of-band metadata, you are + # also responsible for alerting the user to any + # problems with converting the user's data to + # the default_internal. + # + # To do so, simply raise the raise WrongEncodingError + # as follows: + # + # raise WrongEncodingError.new( + # problematic_string, + # expected_encoding + # ) + eager_autoload do autoload :Error autoload :Handler @@ -16,20 +93,22 @@ module ActionView extend Template::Handlers - attr_reader :source, :identifier, :handler, :virtual_path, :formats + attr_reader :source, :identifier, :handler, :virtual_path, :formats, + :original_encoding - Finalizer = proc do |method_name| + Finalizer = proc do |method_name, mod| proc do - ActionView::CompiledTemplates.module_eval do + mod.module_eval do remove_possible_method method_name end end end def initialize(source, identifier, handler, details) - @source = source - @identifier = identifier - @handler = handler + @source = source + @identifier = identifier + @handler = handler + @original_encoding = nil @virtual_path = details[:virtual_path] @method_names = {} @@ -42,7 +121,13 @@ module ActionView # Notice that we use a bang in this instrumentation because you don't want to # consume this in production. This is only slow if it's being listened to. ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do - method_name = compile(locals, view) + if view.is_a?(ActionView::CompiledTemplates) + mod = ActionView::CompiledTemplates + else + mod = view.singleton_class + end + + method_name = compile(locals, view, mod) view.send(method_name, locals, &block) end rescue Exception => e @@ -50,7 +135,7 @@ module ActionView e.sub_template_of(self) raise e else - raise Template::Error.new(self, view.assigns, e) + raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e) end end @@ -75,37 +160,97 @@ module ActionView end private - def compile(locals, view) + # Among other things, this method is responsible for properly setting + # the encoding of the source. Until this point, we assume that the + # source is BINARY data. If no additional information is supplied, + # we assume the encoding is the same as Encoding.default_external. + # + # The user can also specify the encoding via a comment on the first + # line of the template (# encoding: NAME-OF-ENCODING). This will work + # with any template engine, as we process out the encoding comment + # before passing the source on to the template engine, leaving a + # blank line in its stead. + # + # Note that after we figure out the correct encoding, we then + # encode the source into Encoding.default_internal. In general, + # this means that templates will be UTF-8 inside of Rails, + # regardless of the original source encoding. + def compile(locals, view, mod) method_name = build_method_name(locals) return method_name if view.respond_to?(method_name) locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join - code = @handler.call(self) - if code.sub!(/\A(#.*coding.*)\n/, '') - encoding_comment = $1 - elsif defined?(Encoding) && Encoding.respond_to?(:default_external) - encoding_comment = "#coding:#{Encoding.default_external}" + if source.encoding_aware? + if source.sub!(/\A#{ENCODING_FLAG}/, '') + encoding = $1 + else + encoding = Encoding.default_external + end + + # Tag the source with the default external encoding + # or the encoding specified in the file + source.force_encoding(encoding) + + # If the original encoding is BINARY, the actual + # encoding is either stored out-of-band (such as + # in ERB <%# %> style magic comments) or missing. + # This is also true if the original encoding is + # something other than BINARY, but it's invalid. + if source.encoding != Encoding::BINARY && source.valid_encoding? + source.encode! + # If the assumed encoding is incorrect, check to + # see whether the handler accepts BINARY. If it + # does, it has another mechanism for determining + # the true encoding of the String. + elsif @handler.respond_to?(:accepts_binary?) && @handler.accepts_binary? + source.force_encoding(Encoding::BINARY) + # If the handler does not accept BINARY, the + # assumed encoding (either the default_external, + # or the explicit encoding specified by the user) + # is incorrect. We raise an exception here. + else + raise WrongEncodingError.new(source, encoding) + end + + # Don't validate the encoding yet -- the handler + # may treat the String as raw bytes and extract + # the encoding some other way end + code = @handler.call(self) + source = <<-end_src def #{method_name}(local_assigns) - _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code} + _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code} ensure - @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer + @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer end end_src - if encoding_comment - source = "#{encoding_comment}\n#{source}" - line = -1 - else - line = 0 + if source.encoding_aware? + # Handlers should return their source Strings in either the + # default_internal or BINARY. If the handler returns a BINARY + # String, we assume its encoding is the one we determined + # earlier, and encode the resulting source in the default_internal. + if source.encoding == Encoding::BINARY + source.force_encoding(Encoding.default_internal) + end + + # In case we get back a String from a handler that is not in + # BINARY or the default_internal, encode it to the default_internal + source.encode! + + # Now, validate that the source we got back from the template + # handler is valid in the default_internal + unless source.valid_encoding? + raise WrongEncodingError.new(@source, Encoding.default_internal) + end end begin - ActionView::CompiledTemplates.module_eval(source, identifier, line) - ObjectSpace.define_finalizer(self, Finalizer[method_name]) + mod.module_eval(source, identifier, 0) + ObjectSpace.define_finalizer(self, Finalizer[method_name, mod]) method_name rescue Exception => e # errors from template code diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 6866eabf77..d3a53d2147 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -4,6 +4,24 @@ module ActionView class ActionViewError < StandardError #:nodoc: end + class EncodingError < StandardError #:nodoc: + end + + class WrongEncodingError < EncodingError #:nodoc: + def initialize(string, encoding) + @string, @encoding = string, encoding + end + + def message + "Your template was not saved as valid #{@encoding}. Please " \ + "either specify #{@encoding} as the encoding for your template " \ + "in your text editor, or mark the template with its " \ + "encoding by inserting the following as the first line " \ + "of the template:\n\n# encoding: .\n\n" \ + "The source of your template was:\n\n#{@string}" + end + end + class MissingTemplate < ActionViewError #:nodoc: attr_reader :path diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 237746437a..bbf012ab15 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -1,9 +1,15 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/string/output_safety' +require "action_view/template" require 'erubis' module ActionView class OutputBuffer < ActiveSupport::SafeBuffer + def initialize(*) + super + encode! + end + def <<(value) super(value.to_s) end @@ -17,65 +23,106 @@ module ActionView end end - module Template::Handlers - class Erubis < ::Erubis::Eruby - def add_preamble(src) - src << "@output_buffer = ActionView::OutputBuffer.new;" - end + class Template + module Handlers + class Erubis < ::Erubis::Eruby + def add_preamble(src) + src << "@output_buffer = ActionView::OutputBuffer.new;" + end - def add_text(src, text) - return if text.empty? - src << "@output_buffer.safe_concat('" << escape_text(text) << "');" - end + def add_text(src, text) + return if text.empty? + src << "@output_buffer.safe_concat('" << escape_text(text) << "');" + end - BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ + BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ - def add_expr_literal(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append= ' << code - else - src << '@output_buffer.append= (' << code << ');' + def add_expr_literal(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append= ' << code + else + src << '@output_buffer.append= (' << code << ');' + end end - end - def add_stmt(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append_if_string= ' << code - else - super + def add_stmt(src, code) + if code =~ BLOCK_EXPR + src << '@output_buffer.append_if_string= ' << code + else + super + end end - end - def add_expr_escaped(src, code) - src << '@output_buffer.append= ' << escaped_expr(code) << ';' - end + def add_expr_escaped(src, code) + src << '@output_buffer.append= ' << escaped_expr(code) << ';' + end - def add_postamble(src) - src << '@output_buffer.to_s' + def add_postamble(src) + src << '@output_buffer.to_s' + end end - end - class ERB < Template::Handler - include Compilable + class ERB < Handler + include Compilable + + ## + # :singleton-method: + # Specify trim mode for the ERB compiler. Defaults to '-'. + # See ERb documentation for suitable values. + cattr_accessor :erb_trim_mode + self.erb_trim_mode = '-' + + self.default_format = Mime::HTML + + cattr_accessor :erb_implementation + self.erb_implementation = Erubis - ## - # :singleton-method: - # Specify trim mode for the ERB compiler. Defaults to '-'. - # See ERb documentation for suitable values. - cattr_accessor :erb_trim_mode - self.erb_trim_mode = '-' + ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*") - self.default_format = Mime::HTML + def self.accepts_binary? + true + end + + def compile(template) + if template.source.encoding_aware? + # Even though Rails has given us a String tagged with the + # default_internal encoding (likely UTF-8), it is possible + # that the String is actually encoded using a different + # encoding, specified via an ERB magic comment. If the + # String is not actually UTF-8, the regular expression + # engine will (correctly) raise an exception. For now, + # we'll reset the String to BINARY so we can run regular + # expressions against it + template_source = template.source.dup.force_encoding("BINARY") + + # Erubis does not have direct support for encodings. + # As a result, we will extract the ERB-style magic + # comment, give the String to Erubis as BINARY data, + # and then tag the resulting String with the extracted + # encoding later + erb = template_source.gsub(ENCODING_TAG, '') + encoding = $2 - cattr_accessor :erb_implementation - self.erb_implementation = Erubis + if !encoding && (template.source.encoding == Encoding::BINARY) + raise WrongEncodingError.new(template_source, Encoding.default_external) + end + end - def compile(template) - source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '') - erb = "<% __in_erb_template=true %>#{source}" - result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src - result = "#{$2}\n#{result}" if $2 - result + result = self.class.erb_implementation.new( + erb, + :trim => (self.class.erb_trim_mode == "-") + ).src + + # If an encoding tag was found, tag the String + # we're returning with that encoding. Otherwise, + # return a BINARY String, which is what ERB + # returns. Note that if a magic comment was + # not specified, we will return the data to + # Rails as BINARY, which will then use its + # own encoding logic to create a UTF-8 String. + result = "\n#{result}".force_encoding(encoding).encode if encoding + result + end end end end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index a223b3a55f..ef44925951 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -70,7 +70,10 @@ module ActionView Dir[query].reject { |p| File.directory?(p) }.map do |p| handler, format = extract_handler_and_format(p, formats) - Template.new(File.read(p), File.expand_path(p), handler, + + contents = File.open(p, "rb") {|io| io.read } + + Template.new(contents, File.expand_path(p), handler, :virtual_path => path, :format => format) end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 89ba0990f1..479e62b23d 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -12,6 +12,10 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') +if defined?(Encoding.default_internal) + Encoding.default_internal = "UTF-8" +end + require 'test/unit' require 'abstract_controller' require 'action_controller' diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 7012c4c9b0..4f8ad23174 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -212,12 +212,12 @@ class AssertSelectTest < ActionController::TestCase assert_nothing_raised { assert_select "div", "bar" } assert_nothing_raised { assert_select "div", /\w*/ } assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>"bar" } assert_nothing_raised { assert_select "div", :html=>/\w*/ } assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 } - assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } + assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 } end end diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb index d1dbd535c4..47253f22b8 100644 --- a/actionpack/test/controller/capture_test.rb +++ b/actionpack/test/controller/capture_test.rb @@ -68,6 +68,6 @@ class CaptureTest < ActionController::TestCase private def expected_content_for_output - "Putting stuff in the title!\n\nGreat stuff!" + "Putting stuff in the title!\nGreat stuff!" end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 52049f2a8a..2b1f2a27df 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1079,7 +1079,7 @@ class RenderTest < ActionController::TestCase def test_action_talk_to_layout get :action_talk_to_layout - assert_equal "Talking to the layout\n\nAction was here!", @response.body + assert_equal "Talking to the layout\nAction was here!", @response.body end # :addressed: @@ -1096,7 +1096,7 @@ class RenderTest < ActionController::TestCase def test_yield_content_for assert_not_deprecated { get :yield_content_for } - assert_equal "Putting stuff in the title!\n\nGreat stuff!\n", @response.body + assert_equal "Putting stuff in the title!\nGreat stuff!\n", @response.body end def test_overwritting_rendering_relative_file_with_extension diff --git a/actionpack/test/fixtures/test/content_for.erb b/actionpack/test/fixtures/test/content_for.erb index 0e47ca8c3d..1fb829f54c 100644 --- a/actionpack/test/fixtures/test/content_for.erb +++ b/actionpack/test/fixtures/test/content_for.erb @@ -1,2 +1 @@ -<% content_for :title do %>Putting stuff in the title!<% end %> -Great stuff! \ No newline at end of file +<% content_for :title do -%>Putting stuff in the title!<% end -%>Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_concatenated.erb b/actionpack/test/fixtures/test/content_for_concatenated.erb index fb6b4b05d7..e65f629574 100644 --- a/actionpack/test/fixtures/test/content_for_concatenated.erb +++ b/actionpack/test/fixtures/test/content_for_concatenated.erb @@ -1,3 +1,3 @@ <% content_for :title, "Putting stuff " - content_for :title, "in the title!" %> + content_for :title, "in the title!" -%> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/content_for_with_parameter.erb b/actionpack/test/fixtures/test/content_for_with_parameter.erb index 57aecbac05..aeb6f73ce0 100644 --- a/actionpack/test/fixtures/test/content_for_with_parameter.erb +++ b/actionpack/test/fixtures/test/content_for_with_parameter.erb @@ -1,2 +1,2 @@ -<% content_for :title, "Putting stuff in the title!" %> +<% content_for :title, "Putting stuff in the title!" -%> Great stuff! \ No newline at end of file diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder index a94643561c..d539a425a4 100644 --- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder +++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder @@ -1,4 +1,4 @@ content_for :title do 'Putting stuff in the title!' end -xml << "\nGreat stuff!" +xml << "Great stuff!" diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index d0212024ae..aca96e0a24 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -232,13 +232,13 @@ module RenderTestCases # TODO: Move to deprecated_tests.rb def test_render_with_nested_layout_deprecated assert_deprecated do - assert_equal %(title\n\n\n
column
\n
content
\n), + assert_equal %(title\n\n
column
\n
content
\n), @view.render(:file => "test/deprecated_nested_layout.erb", :layout => "layouts/yield") end end def test_render_with_nested_layout - assert_equal %(title\n\n\n
column
\n
content
\n), + assert_equal %(title\n\n
column
\n
content
\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") end @@ -284,7 +284,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase with_external_encoding Encoding::ASCII_8BIT do result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding - assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end @@ -302,7 +302,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message end end end @@ -313,7 +313,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error - assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message end end end diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb new file mode 100644 index 0000000000..c4a65d84fc --- /dev/null +++ b/actionpack/test/template/template_test.rb @@ -0,0 +1,128 @@ +require "abstract_unit" + +# These are the normal settings that will be set up by Railties +# TODO: Have these tests support other combinations of these values +Encoding.default_internal = "UTF-8" +Encoding.default_external = "UTF-8" + +class TestERBTemplate < ActiveSupport::TestCase + ERBHandler = ActionView::Template::Handlers::ERB + + class Context + def initialize + @output_buffer = "original" + end + + def hello + "Hello" + end + + def partial + ActionView::Template.new( + "<%= @_virtual_path %>", + "partial", + ERBHandler, + :virtual_path => "partial" + ) + end + + def logger + require "logger" + Logger.new(STDERR) + end + + def my_buffer + @output_buffer + end + end + + def new_template(body = "<%= hello %>", handler = ERBHandler, details = {}) + ActionView::Template.new(body, "hello template", ERBHandler, {:virtual_path => "hello"}) + end + + def render(locals = {}) + @template.render(@obj, locals) + end + + def setup + @obj = Context.new + end + + def test_basic_template + @template = new_template + assert_equal "Hello", render + end + + def test_locals + @template = new_template("<%= my_local %>") + assert_equal "I'm a local", render(:my_local => "I'm a local") + end + + def test_restores_buffer + @template = new_template + assert_equal "Hello", render + assert_equal "original", @obj.my_buffer + end + + def test_virtual_path + @template = new_template("<%= @_virtual_path %>" \ + "<%= partial.render(self, {}) %>" \ + "<%= @_virtual_path %>") + assert_equal "hellopartialhello", render + end + + if "ruby".encoding_aware? + def test_resulting_string_is_utf8 + @template = new_template + assert_equal Encoding::UTF_8, render.encoding + end + + def test_no_magic_comment_word_with_utf_8 + @template = new_template("hello \u{fc}mlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + + # This test ensures that if the default_external + # is set to something other than UTF-8, we don't + # get any errors and get back a UTF-8 String. + def test_default_external_works + Encoding.default_external = "ISO-8859-1" + @template = new_template("hello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + ensure + Encoding.default_external = "UTF-8" + end + + def test_encoding_can_be_specified_with_magic_comment + @template = new_template("# encoding: ISO-8859-1\nhello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "\nhello \u{fc}mlat", render + end + + # TODO: This is currently handled inside ERB. The case of explicitly + # lying about encodings via the normal Rails API should be handled + # inside Rails. + def test_lying_with_magic_comment + assert_raises(ActionView::Template::Error) do + @template = new_template("# encoding: UTF-8\nhello \xFCmlat") + render + end + end + + def test_encoding_can_be_specified_with_magic_comment_in_erb + @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat") + result = render + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + + def test_error_when_template_isnt_valid_utf8 + assert_raises(ActionView::Template::Error, /\xFC/) do + @template = new_template("hello \xFCmlat") + render + end + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/string/encoding.rb b/activesupport/lib/active_support/core_ext/string/encoding.rb new file mode 100644 index 0000000000..d4781bfe0c --- /dev/null +++ b/activesupport/lib/active_support/core_ext/string/encoding.rb @@ -0,0 +1,11 @@ +class String + if defined?(Encoding) && "".respond_to?(:encode) + def encoding_aware? + true + end + else + def encoding_aware? + false + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb index 4a9ac920e8..608b3fe4b9 100644 --- a/activesupport/lib/active_support/ruby/shim.rb +++ b/activesupport/lib/active_support/ruby/shim.rb @@ -15,6 +15,7 @@ require 'active_support/core_ext/enumerable' require 'active_support/core_ext/process/daemon' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/string/interpolation' +require 'active_support/core_ext/string/encoding' require 'active_support/core_ext/rexml' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/file/path' diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 97b08da0e4..09ce39bae2 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -439,6 +439,14 @@ class OutputSafetyTest < ActiveSupport::TestCase test 'emits normal string yaml' do assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) end + + test 'knows whether it is encoding aware' do + if RUBY_VERSION >= "1.9" + assert 'ruby'.encoding_aware? + else + assert !'ruby'.encoding_aware? + end + end end class StringExcludeTest < ActiveSupport::TestCase diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 5da7ff7daa..b7301bff20 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1462,11 +1462,32 @@ Rails also comes with built-in help that you can generate using the rake command * Running +rake doc:guides+ will put a full copy of the Rails Guides in the +doc/guides+ folder of your application. Open +doc/guides/index.html+ in your web browser to explore the Guides. * Running +rake doc:rails+ will put a full copy of the API documentation for Rails in the +doc/api+ folder of your application. Open +doc/api/index.html+ in your web browser to explore the API documentation. +h3. Configuration Gotchas + +The easiest way to work with Rails is to store all external data as UTF-8. If you don't, Ruby libraries and Rails will often be able to convert your native data into UTF-8, but this doesn't always work reliably, so you're better off ensuring that all external data is UTF-8. + +If you have made a mistake in this area, the most common symptom is a black diamond with a question mark inside appearing in the browser. Another common symptom is characters like "ü" appearing instead of "ü". Rails takes a number of internal steps to mitigate common causes of these problems that can be automatically detected and corrected. However, if you have external data that is not stored as UTF-8, it can occasionally result in these kinds of issues that cannot be automatically detected by Rails and corrected. + +Two very common sources of data that are not UTF-8: +* Your text editor: Most text editors (such as Textmate), default to saving files as + UTF-8. If your text editor does not, this can result in special characters that you + enter in your templates (such as é) to appear as a diamond with a question mark inside + in the browser. This also applies to your I18N translation files. + Most editors that do not already default to UTF-8 (such as some versions of + Dreamweaver) offer a way to change the default to UTF-8. Do so. +* Your database. Rails defaults to converting data from your database into UTF-8 at + the boundary. However, if your database is not using UTF-8 internally, it may not + be able to store all characters that your users enter. For instance, if your database + is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese + character, the data will be lost forever once it enters the database. If possible, + use UTF-8 as the internal storage of your database. h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2 +* May 16, 2010: Added a section on configuration gotchas to address common encoding + problems that people might have * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com * April 25, 2010: Couple of more minor fixups "Mikel Lindsaar":credits:html#raasdnil * April 1, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 0611b2a9f5..be486ef2ac 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -23,6 +23,7 @@ if RUBY_VERSION < '1.9' $KCODE='u' else Encoding.default_external = Encoding::UTF_8 + Encoding.default_internal = Encoding::UTF_8 end module Rails diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 9353fbefef..8afe423973 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,4 +1,5 @@ require 'active_support/deprecation' +require 'active_support/core_ext/string/encoding' require 'rails/engine/configuration' module Rails @@ -27,8 +28,15 @@ module Rails def encoding=(value) @encoding = value - if defined?(Encoding) && Encoding.respond_to?(:default_external=) + if "ruby".encoding_aware? Encoding.default_external = value + Encoding.default_internal = value + else + $KCODE = value + if $KCODE == "NONE" + raise "The value you specified for config.encoding is " \ + "invalid. The possible values are UTF8, SJIS, or EUC" + end end end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index dfc4e2359b..c08bd2ef22 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -180,7 +180,8 @@ module ApplicationTests require "#{app_path}/config/application" unless RUBY_VERSION < '1.9' - assert_equal Encoding.find("utf-8"), Encoding.default_external + assert_equal Encoding::UTF_8, Encoding.default_external + assert_equal Encoding::UTF_8, Encoding.default_internal end end -- cgit v1.2.3 From 8c5e1652c7d1343a4b4acbc10bbcb59e202bf37d Mon Sep 17 00:00:00 2001 From: Rizwan Reza Date: Mon, 17 May 2010 01:55:56 +0430 Subject: Renames Array#rand -> Array#random_element Signed-off-by: Xavier Noria --- activesupport/CHANGELOG | 2 ++ .../lib/active_support/core_ext/array/random_access.rb | 12 +----------- activesupport/test/core_ext/array_ext_test.rb | 4 ---- railties/test/application/initializers/frameworks_test.rb | 4 ++-- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 7afd9926b5..7d00211ea1 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [beta 4/release candidate] (unreleased)* +* Renames Array#rand -> Array#random_element. [Santiago Pastorino, Rizwan Reza] + * Defines prev_(month|year) in Date and Time, and deprecates last_(month|year). [fxn] * Aliases Date#sunday to Date#end_of_week. [fxn] diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb index 5338836b29..67c322daea 100644 --- a/activesupport/lib/active_support/core_ext/array/random_access.rb +++ b/activesupport/lib/active_support/core_ext/array/random_access.rb @@ -1,16 +1,6 @@ class Array - # This method is deprecated because it masks Kernel#rand within the Array class itself, - # which may be used by a 3rd party library extending Array in turn. See - # - # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555 - # - def rand # :nodoc: - ActiveSupport::Deprecation.warn "Array#rand is deprecated, use random_element instead", caller - random_element - end - # Returns a random element from the array. def random_element self[Kernel.rand(length)] end -end +end \ No newline at end of file diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index ebd6806416..1f7cdb8ec1 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -368,10 +368,6 @@ class ArrayExtRandomTests < ActiveSupport::TestCase Kernel.expects(:rand).with(3).returns(1) assert_equal 2, [1, 2, 3].random_element end - - def test_deprecated_rand_on_array - assert_deprecated { [].rand } - end end class ArrayWrapperTests < Test::Unit::TestCase diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 8e57022e5b..fadcc4c025 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -47,7 +47,7 @@ module ApplicationTests test "if there's no config.active_support.bare, all of ActiveSupport is required" do use_frameworks [] require "#{app_path}/config/environment" - assert_nothing_raised { [1,2,3].rand } + assert_nothing_raised { [1,2,3].random_element } end test "config.active_support.bare does not require all of ActiveSupport" do @@ -57,7 +57,7 @@ module ApplicationTests Dir.chdir("#{app_path}/app") do require "#{app_path}/config/environment" - assert_raises(NoMethodError) { [1,2,3].rand } + assert_raises(NoMethodError) { [1,2,3].random_element } end end -- cgit v1.2.3 From 941b653627b9ca7b7f2ddb4a712fb0efccc10500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 01:42:35 +0200 Subject: Rely on set and delete cookie logic from rack. --- actionpack/lib/action_dispatch/http/response.rb | 35 ++----------------------- actionpack/test/dispatch/response_test.rb | 4 +++ 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 8b730a97ee..3b85a98576 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -140,7 +140,7 @@ module ActionDispatch # :nodoc: def to_a assign_default_content_type_and_charset! handle_conditional_get! - self["Set-Cookie"] = @cookie.join("\n") unless @cookie.blank? + self["Set-Cookie"] = self["Set-Cookie"].join("\n") if self["Set-Cookie"].respond_to?(:join) self["ETag"] = @_etag if @_etag super end @@ -170,7 +170,7 @@ module ActionDispatch # :nodoc: # assert_equal 'AuthorOfNewPage', r.cookies['author'] def cookies cookies = {} - if header = @cookie + if header = self["Set-Cookie"] header = header.split("\n") if header.respond_to?(:to_str) header.each do |cookie| if pair = cookie.split(';').first @@ -182,37 +182,6 @@ module ActionDispatch # :nodoc: cookies end - def set_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Rack::Utils.escape(key) + "=" + - value.map { |v| Rack::Utils.escape v }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - - @cookie << cookie - end - - def delete_cookie(key, value={}) - @cookie.reject! { |cookie| - cookie =~ /\A#{Rack::Utils.escape(key)}=/ - } - - set_cookie(key, - {:value => '', :path => nil, :domain => nil, - :expires => Time.at(0) }.merge(value)) - end - private def assign_default_content_type_and_charset! return if headers[CONTENT_TYPE].present? diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index c7f7f3102d..c20fa10f63 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -113,6 +113,10 @@ class ResponseTest < ActiveSupport::TestCase status, headers, body = @response.to_a assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", headers["Set-Cookie"] assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies) + + @response.delete_cookie("login") + status, headers, body = @response.to_a + assert_equal({"user_name" => "david", "login" => nil}, @response.cookies) end test "read cache control" do -- cgit v1.2.3 From 25f7c030e4ea440ea6c2a84c92118299753392d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 01:43:06 +0200 Subject: Simplify cookie_store by simply relying on cookies.signed. --- .../lib/action_dispatch/middleware/cookies.rb | 32 +++++- .../middleware/session/cookie_store.rb | 107 +++------------------ actionpack/test/abstract_unit.rb | 1 + actionpack/test/controller/cookie_test.rb | 55 ++++++++++- actionpack/test/controller/flash_test.rb | 11 ++- .../test/dispatch/session/cookie_store_test.rb | 66 ++++--------- railties/lib/rails/application/configuration.rb | 8 +- railties/test/application/configuration_test.rb | 4 +- railties/test/application/middleware_test.rb | 5 +- 9 files changed, 138 insertions(+), 151 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 42ab1d1ebb..1e49a307ed 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -52,6 +52,9 @@ module ActionDispatch # * :httponly - Whether this cookie is accessible via scripting or # only HTTP. Defaults to +false+. class Cookies + # Raised when storing more than 4K of session data. + class CookieOverflow < StandardError; end + class CookieJar < Hash #:nodoc: def self.build(request) secret = request.env["action_dispatch.secret_token"] @@ -166,8 +169,11 @@ module ActionDispatch end class SignedCookieJar < CookieJar #:nodoc: + MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes. + SECRET_MIN_LENGTH = 30 # Characters + def initialize(parent_jar, secret) - raise "You must set config.secret_token in your app's config" if secret.blank? + ensure_secret_secure(secret) @parent_jar = parent_jar @verifier = ActiveSupport::MessageVerifier.new(secret) end @@ -176,6 +182,8 @@ module ActionDispatch if signed_message = @parent_jar[name] @verifier.verify(signed_message) end + rescue ActiveSupport::MessageVerifier::InvalidSignature + nil end def []=(key, options) @@ -186,12 +194,34 @@ module ActionDispatch options = { :value => @verifier.generate(options) } end + raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE @parent_jar[key] = options end def method_missing(method, *arguments, &block) @parent_jar.send(method, *arguments, &block) end + + protected + + # To prevent users from using something insecure like "Password" we make sure that the + # secret they've provided is at least 30 characters in length. + def ensure_secret_secure(secret) + if secret.blank? + raise ArgumentError, "A secret is required to generate an " + + "integrity hash for cookie session data. Use " + + "config.secret_token = \"some secret phrase of at " + + "least #{SECRET_MIN_LENGTH} characters\"" + + "in config/application.rb" + end + + if secret.length < SECRET_MIN_LENGTH + raise ArgumentError, "Secret should be something secure, " + + "like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " + + "provided, \"#{secret}\", is shorter than the minimum length " + + "of #{SECRET_MIN_LENGTH} characters" + end + end end def initialize(app) diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 7114f42003..0c1712bf84 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,3 +1,4 @@ +require 'action_dispatch/middleware/cookies' require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/object/blank' @@ -39,10 +40,6 @@ module ActionDispatch # # Note that changing digest or secret invalidates all existing sessions! class CookieStore - # Cookies can typically store 4096 bytes. - MAX = 4096 - SECRET_MIN_LENGTH = 30 # characters - DEFAULT_OPTIONS = { :key => '_session_id', :domain => nil, @@ -54,7 +51,7 @@ module ActionDispatch class OptionsHash < Hash def initialize(by, env, default_options) @session_data = env[CookieStore::ENV_SESSION_KEY] - default_options.each { |key, value| self[key] = value } + merge!(default_options) end def [](key) @@ -64,14 +61,12 @@ module ActionDispatch ENV_SESSION_KEY = "rack.session".freeze ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze - HTTP_SET_COOKIE = "Set-Cookie".freeze - - # Raised when storing more than 4K of session data. - class CookieOverflow < StandardError; end def initialize(app, options = {}) # Process legacy CGI options + # TODO Refactor and deprecate me options = options.symbolize_keys + if options.has_key?(:session_path) options[:path] = options.delete(:session_path) end @@ -88,15 +83,7 @@ module ActionDispatch ensure_session_key(options[:key]) @key = options.delete(:key).freeze - # The secret option is required. - ensure_secret_secure(options[:secret]) - @secret = options.delete(:secret).freeze - - @digest = options.delete(:digest) || 'SHA1' - @verifier = verifier_for(@secret, @digest) - @default_options = DEFAULT_OPTIONS.merge(options).freeze - freeze end @@ -111,66 +98,32 @@ module ActionDispatch if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after] session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?) - session_data = marshal(session_data.to_hash) - - raise CookieOverflow if session_data.size > MAX + session_data = persistent_session_id!(session_data.to_hash) - cookie = Hash.new - cookie[:value] = session_data + cookie = { :value => session_data } unless options[:expire_after].nil? - cookie[:expires] = Time.now + options[:expire_after] + cookie[:expires] = Time.now + options.delete(:expire_after) end - cookie = build_cookie(@key, cookie.merge(options)) - unless headers[HTTP_SET_COOKIE].blank? - headers[HTTP_SET_COOKIE] << "\n#{cookie}" - else - headers[HTTP_SET_COOKIE] = cookie - end + request = ActionDispatch::Request.new(env) + request.cookie_jar.signed[@key] = cookie.merge!(options) end [status, headers, body] end private - # Should be in Rack::Utils soon - def build_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Rack::Utils.escape(key) + "=" + - value.map { |v| Rack::Utils.escape(v) }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - end def load_session(env) - request = Rack::Request.new(env) - session_data = request.cookies[@key] - data = unmarshal(session_data) || persistent_session_id!({}) + request = ActionDispatch::Request.new(env) + data = request.cookie_jar.signed[@key] + data = persistent_session_id!(data || {}) data.stringify_keys! [data["session_id"], data] end - # Marshal a session hash into safe cookie data. Include an integrity hash. - def marshal(session) - @verifier.generate(persistent_session_id!(session)) - end - - # Unmarshal cookie data to a hash and verify its integrity. - def unmarshal(cookie) - persistent_session_id!(@verifier.verify(cookie)) if cookie - rescue ActiveSupport::MessageVerifier::InvalidSignature - nil + def generate_sid + ActiveSupport::SecureRandom.hex(16) end def ensure_session_key(key) @@ -182,38 +135,6 @@ module ActionDispatch end end - # To prevent users from using something insecure like "Password" we make sure that the - # secret they've provided is at least 30 characters in length. - def ensure_secret_secure(secret) - # There's no way we can do this check if they've provided a proc for the - # secret. - return true if secret.is_a?(Proc) - - if secret.blank? - raise ArgumentError, "A secret is required to generate an " + - "integrity hash for cookie session data. Use " + - "config.secret_token = \"some secret phrase of at " + - "least #{SECRET_MIN_LENGTH} characters\"" + - "in config/application.rb" - end - - if secret.length < SECRET_MIN_LENGTH - raise ArgumentError, "Secret should be something secure, " + - "like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " + - "provided, \"#{secret}\", is shorter than the minimum length " + - "of #{SECRET_MIN_LENGTH} characters" - end - end - - def verifier_for(secret, digest) - key = secret.respond_to?(:call) ? secret.call : secret - ActiveSupport::MessageVerifier.new(key, digest) - end - - def generate_sid - ActiveSupport::SecureRandom.hex(16) - end - def persistent_session_id!(data) (data ||= {}).merge!(inject_persistent_session_id(data)) end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 479e62b23d..d2e5d2e965 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -162,6 +162,7 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase middleware.use "ActionDispatch::Cookies" middleware.use "ActionDispatch::Flash" middleware.use "ActionDispatch::Head" + yield(middleware) if block_given? end end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 4971866e7c..f65eda5c69 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -58,6 +58,17 @@ class CookieTest < ActionController::TestCase head :ok end + def raise_data_overflow + cookies.signed[:foo] = 'bye!' * 1024 + head :ok + end + + def tampered_cookies + cookies[:tampered] = "BAh7BjoIZm9vIghiYXI%3D--123456780" + cookies.signed[:tampered] + head :ok + end + def set_permanent_signed_cookie cookies.permanent.signed[:remember_me] = 100 head :ok @@ -74,7 +85,7 @@ class CookieTest < ActionController::TestCase def setup super - @request.env["action_dispatch.secret_token"] = "thisISverySECRET123" + @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33" @request.host = "www.nextangle.com" end @@ -163,6 +174,48 @@ class CookieTest < ActionController::TestCase assert_equal({"user_name" => "david"}, @response.cookies) end + def test_raise_data_overflow + assert_raise(ActionDispatch::Cookies::CookieOverflow) do + get :raise_data_overflow + end + end + + def test_tampered_cookies + assert_nothing_raised do + get :tampered_cookies + assert_response :success + end + end + + def test_raises_argument_error_if_missing_secret + assert_raise(ArgumentError, nil.inspect) { + @request.env["action_dispatch.secret_token"] = nil + get :set_signed_cookie + } + + assert_raise(ArgumentError, ''.inspect) { + @request.env["action_dispatch.secret_token"] = "" + get :set_signed_cookie + } + end + + def test_raises_argument_error_if_secret_is_probably_insecure + assert_raise(ArgumentError, "password".inspect) { + @request.env["action_dispatch.secret_token"] = "password" + get :set_signed_cookie + } + + assert_raise(ArgumentError, "secret".inspect) { + @request.env["action_dispatch.secret_token"] = "secret" + get :set_signed_cookie + } + + assert_raise(ArgumentError, "12345678901234567890123456789".inspect) { + @request.env["action_dispatch.secret_token"] = "12345678901234567890123456789" + get :set_signed_cookie + } + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index c662ce264b..01c8fd90a5 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -237,10 +237,19 @@ class FlashIntegrationTest < ActionController::IntegrationTest end private + + # Overwrite get to send SessionSecret in env hash + def get(path, parameters = nil, env = {}) + env["action_dispatch.secret_token"] ||= SessionSecret + super + end + def with_test_route_set with_routing do |set| set.draw do |map| - match ':action', :to => ActionDispatch::Session::CookieStore.new(FlashIntegrationTest::TestController, :key => FlashIntegrationTest::SessionKey, :secret => FlashIntegrationTest::SessionSecret) + match ':action', :to => ActionDispatch::Session::CookieStore.new( + FlashIntegrationTest::TestController, :key => SessionKey, :secret => SessionSecret + ) end yield end diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index d2c1758af1..a6cdbf8032 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -55,42 +55,13 @@ class CookieStoreTest < ActionController::IntegrationTest } end - def test_raises_argument_error_if_missing_secret - assert_raise(ArgumentError, nil.inspect) { - ActionDispatch::Session::CookieStore.new(nil, - :key => SessionKey, :secret => nil) - } - - assert_raise(ArgumentError, ''.inspect) { - ActionDispatch::Session::CookieStore.new(nil, - :key => SessionKey, :secret => '') - } - end - - def test_raises_argument_error_if_secret_is_probably_insecure - assert_raise(ArgumentError, "password".inspect) { - ActionDispatch::Session::CookieStore.new(nil, - :key => SessionKey, :secret => "password") - } - - assert_raise(ArgumentError, "secret".inspect) { - ActionDispatch::Session::CookieStore.new(nil, - :key => SessionKey, :secret => "secret") - } - - assert_raise(ArgumentError, "12345678901234567890123456789".inspect) { - ActionDispatch::Session::CookieStore.new(nil, - :key => SessionKey, :secret => "12345678901234567890123456789") - } - end - def test_setting_session_value with_test_route_set do get '/set_session_value' assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", headers['Set-Cookie'] - end + end end def test_getting_session_value @@ -99,7 +70,7 @@ class CookieStoreTest < ActionController::IntegrationTest get '/get_session_value' assert_response :success assert_equal 'foo: "bar"', response.body - end + end end def test_getting_session_id @@ -127,7 +98,7 @@ class CookieStoreTest < ActionController::IntegrationTest def test_close_raises_when_data_overflows with_test_route_set do - assert_raise(ActionDispatch::Session::CookieStore::CookieOverflow) { + assert_raise(ActionDispatch::Cookies::CookieOverflow) { get '/raise_data_overflow' } end @@ -209,30 +180,33 @@ class CookieStoreTest < ActionController::IntegrationTest get '/no_session_access' assert_response :success - # Mystery bug that came up in 2.3 as well. What is this trying to test?! - # assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", - # headers['Set-Cookie'] + assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", + headers['Set-Cookie'] end end private + + # Overwrite get to send SessionSecret in env hash + def get(path, parameters = nil, env = {}) + env["action_dispatch.secret_token"] ||= SessionSecret + super + end + def with_test_route_set(options = {}) with_routing do |set| set.draw do |map| match ':action', :to => ::CookieStoreTest::TestController end - options = {:key => SessionKey, :secret => SessionSecret}.merge(options) - @app = ActionDispatch::Session::CookieStore.new(set, options) + + options = { :key => SessionKey, :secret => SessionSecret }.merge!(options) + + @app = self.class.build_app(set) do |middleware| + middleware.use ActionDispatch::Session::CookieStore, options + middleware.delete "ActionDispatch::ShowExceptions" + end + yield end end - - def unmarshal_session(cookie_string) - session = Rack::Utils.parse_query(cookie_string, ';,').inject({}) {|h,(k,v)| - h[k] = Array === v ? v.first : v - h - }[SessionKey] - verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1') - verifier.verify(session) - end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 8afe423973..1b8af370f7 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -11,7 +11,8 @@ module Rails :encoding, :consider_all_requests_local, :dependency_loading, :filter_parameters, :log_level, :logger, :metals, :plugins, :preload_frameworks, :reload_engines, :reload_plugins, - :secret_token, :serve_static_assets, :time_zone, :whiny_nils + :secret_token, :serve_static_assets, :session_options, + :time_zone, :whiny_nils def initialize(*) super @@ -138,11 +139,6 @@ module Rails end end - def session_options - return @session_options unless @session_store == :cookie_store - @session_options.merge(:secret => @secret_token) - end - protected def default_middleware_stack diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index c08bd2ef22..9928ee2c52 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -196,7 +196,7 @@ module ApplicationTests test "config.secret_token is sent in env" do make_basic_app do |app| - app.config.secret_token = 'ThisIsASECRET123' + app.config.secret_token = 'b3c631c314c0bbca50c1b2843150fe33' app.config.session_store :disabled end @@ -208,7 +208,7 @@ module ApplicationTests end get "/" - assert_equal 'ThisIsASECRET123', last_response.body + assert_equal 'b3c631c314c0bbca50c1b2843150fe33', last_response.body end test "protect from forgery is the default in a new app" do diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index d08f04bddb..617525bf78 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -175,7 +175,10 @@ module ApplicationTests def remote_ip(env = {}) remote_ip = nil - env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false) + env = Rack::MockRequest.env_for("/").merge(env).merge!( + 'action_dispatch.show_exceptions' => false, + 'action_dispatch.secret_token' => 'b3c631c314c0bbca50c1b2843150fe33' + ) endpoint = Proc.new do |e| remote_ip = ActionDispatch::Request.new(e).remote_ip -- cgit v1.2.3 From 0c3cde404ac45d59439c324a4a13ec239c582a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 02:07:59 +0200 Subject: Kill legacy dispatcher. --- actionpack/lib/action_dispatch/railtie.rb | 2 -- railties/lib/rails/dispatcher.rb | 24 ------------------------ 2 files changed, 26 deletions(-) delete mode 100644 railties/lib/rails/dispatcher.rb diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 004c254e55..38da44d7e7 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -10,8 +10,6 @@ module ActionDispatch # Prepare dispatcher callbacks and run 'prepare' callbacks initializer "action_dispatch.prepare_dispatcher" do |app| - # TODO: This used to say unless defined?(Dispatcher). Find out why and fix. - require 'rails/dispatcher' ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed } end end diff --git a/railties/lib/rails/dispatcher.rb b/railties/lib/rails/dispatcher.rb deleted file mode 100644 index 75ee4de140..0000000000 --- a/railties/lib/rails/dispatcher.rb +++ /dev/null @@ -1,24 +0,0 @@ -#-- -# Copyright (c) 2004-2010 David Heinemeier Hansson -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#++ -require 'action_controller/deprecated/dispatcher' -Dispatcher = ActionController::Dispatcher -- cgit v1.2.3 From 26e645fa000b15c335d5356008aac282c232f7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 02:11:50 +0200 Subject: Remove deprecated methods since 2-3-stable. --- .../middleware/session/abstract_store.rb | 40 ++++------------------ .../test/dispatch/session/test_session_test.rb | 12 ------- 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index dddedc832f..977185d754 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -22,13 +22,6 @@ module ActionDispatch @loaded = false end - def session_id - ActiveSupport::Deprecation.warn( - "ActionDispatch::Session::AbstractStore::SessionHash#session_id " + - "has been deprecated. Please use request.session_options[:id] instead.", caller) - @env[ENV_SESSION_OPTIONS_KEY][:id] - end - def [](key) load! unless @loaded super(key.to_s) @@ -45,35 +38,14 @@ module ActionDispatch h end - def update(hash = nil) - if hash.nil? - ActiveSupport::Deprecation.warn('use replace instead', caller) - replace({}) - else - load! unless @loaded - super(hash.stringify_keys) - end - end - - def delete(key = nil) - if key.nil? - ActiveSupport::Deprecation.warn('use clear instead', caller) - clear - else - load! unless @loaded - super(key.to_s) - end - end - - def data - ActiveSupport::Deprecation.warn( - "ActionDispatch::Session::AbstractStore::SessionHash#data " + - "has been deprecated. Please use #to_hash instead.", caller) - to_hash + def update(hash) + load! unless @loaded + super(hash.stringify_keys) end - def close - ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller) + def delete(key) + load! unless @loaded + super(key.to_s) end def inspect diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb index c8dc4ab461..31ce97a25b 100644 --- a/actionpack/test/dispatch/session/test_session_test.rb +++ b/actionpack/test/dispatch/session/test_session_test.rb @@ -2,18 +2,6 @@ require 'abstract_unit' require 'stringio' class ActionController::TestSessionTest < ActiveSupport::TestCase - def test_calling_delete_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session - assert_deprecated(/use clear instead/){ ActionController::TestSession.new.delete } - end - - def test_calling_update_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session - assert_deprecated(/use replace instead/){ ActionController::TestSession.new.update } - end - - def test_calling_close_raises_deprecation_warning - assert_deprecated(/sessions should no longer be closed/){ ActionController::TestSession.new.close } - end - def test_ctor_allows_setting session = ActionController::TestSession.new({:one => 'one', :two => 'two'}) assert_equal('one', session[:one]) -- cgit v1.2.3 From 73f0e1a8423d53370f272841ce29747434de4d9a Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 14:40:56 -0400 Subject: Use assert_respond_to because it has better error messaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4628 state:resolved] Signed-off-by: José Valim --- actionpack/test/abstract/translation_test.rb | 8 ++++---- actionpack/test/controller/integration_test.rb | 4 ++-- actionpack/test/controller/send_file_test.rb | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/actionpack/test/abstract/translation_test.rb b/actionpack/test/abstract/translation_test.rb index 0bf61a6556..09ebfab85e 100644 --- a/actionpack/test/abstract/translation_test.rb +++ b/actionpack/test/abstract/translation_test.rb @@ -9,18 +9,18 @@ class TranslationControllerTest < Test::Unit::TestCase end def test_action_controller_base_responds_to_translate - assert @controller.respond_to?(:translate) + assert_respond_to @controller, :translate end def test_action_controller_base_responds_to_t - assert @controller.respond_to?(:t) + assert_respond_to @controller, :t end def test_action_controller_base_responds_to_localize - assert @controller.respond_to?(:localize) + assert_respond_to @controller, :localize end def test_action_controller_base_responds_to_l - assert @controller.respond_to?(:l) + assert_respond_to @controller, :l end end \ No newline at end of file diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 20dc96d38d..5ee8e2b6ae 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -176,8 +176,8 @@ class IntegrationTestTest < Test::Unit::TestCase session1 = @test.open_session { |sess| } session2 = @test.open_session # implicit session - assert session1.respond_to?(:assert_template), "open_session makes assert_template available" - assert session2.respond_to?(:assert_template), "open_session makes assert_template available" + assert_respond_to session1, :assert_template, "open_session makes assert_template available" + assert_respond_to session2, :assert_template, "open_session makes assert_template available" assert !session1.equal?(session2) end diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 36b8055810..c7c8360ae6 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -55,8 +55,8 @@ class SendFileTest < ActionController::TestCase response = nil assert_nothing_raised { response = process('file') } assert_not_nil response - assert response.body_parts.respond_to?(:each) - assert response.body_parts.respond_to?(:to_path) + assert_respond_to response.body_parts, :each + assert_respond_to response.body_parts, :to_path require 'stringio' output = StringIO.new -- cgit v1.2.3 From 05e3fb45eeacd20f2b8b5691f17d6fdf2fb4582b Mon Sep 17 00:00:00 2001 From: rohit Date: Tue, 18 May 2010 05:54:53 +0530 Subject: Add a valid hex that shouldn't be valid to ActiveModel numericality tests [#4622 state:commited] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activemodel/test/cases/validations/numericality_validation_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 963ad6450b..8e77a0222e 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -18,7 +18,7 @@ class NumericalityValidationTest < ActiveModel::TestCase FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS INTEGERS = [0, 10, -10] + INTEGER_STRINGS BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) } - JUNK = ["not a number", "42 not a number", "0xdeadbeef", "0xinvalidhex", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] + JUNK = ["not a number", "42 not a number", "0xdeadbeef", "0xinvalidhex", "0Xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"] INFINITY = [1.0/0.0] def test_default_validates_numericality_of -- cgit v1.2.3 From 8e3c3b06dc8ff8842f6390efc58eaf4bb1a23060 Mon Sep 17 00:00:00 2001 From: rohit Date: Tue, 18 May 2010 06:09:45 +0530 Subject: Fixed numericality validator in ActiveModel to reject hex numbers for floats completely [#4622 state:commited] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activemodel/lib/active_model/validations/numericality.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index ac8308b0d7..062b4cd17f 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -58,7 +58,7 @@ module ActiveModel def parse_raw_value_as_a_number(raw_value) case raw_value - when /\A0x/ + when /\A0[xX]/ nil else begin -- cgit v1.2.3 From c53683595749dcfa223802669237480ac9ebc17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 03:18:23 +0200 Subject: Cut the fat and make session stores rely on request.cookie_jar and change set_session semantics to return the cookie value instead of a boolean. --- actionpack/CHANGELOG | 2 + .../middleware/session/abstract_store.rb | 82 ++++++++---------- .../middleware/session/cookie_store.rb | 99 ++++------------------ .../middleware/session/mem_cache_store.rb | 4 +- .../test/activerecord/active_record_store_test.rb | 8 +- .../test/dispatch/session/cookie_store_test.rb | 2 +- .../test/dispatch/session/mem_cache_store_test.rb | 7 +- activerecord/lib/active_record/session_store.rb | 2 +- 8 files changed, 72 insertions(+), 134 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 4db9c4b84d..54c7771f4c 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [beta 4/release candidate] (unreleased)* +* Make session stores rely on request.cookie_jar and change set_session semantics to return the cookie value instead of a boolean. [José Valim] + * OAuth 2: HTTP Token Authorization support to complement Basic and Digest Authorization. [Rick Olson] * Fixed inconsistencies in form builder and view helpers #4432 [Neeraj Singh] diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 977185d754..15493cd2eb 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -1,5 +1,6 @@ require 'rack/utils' require 'rack/request' +require 'action_dispatch/middleware/cookies' require 'active_support/core_ext/object/blank' module ActionDispatch @@ -11,9 +12,6 @@ module ActionDispatch ENV_SESSION_KEY = 'rack.session'.freeze ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze - HTTP_COOKIE = 'HTTP_COOKIE'.freeze - SET_COOKIE = 'Set-Cookie'.freeze - class SessionHash < Hash def initialize(by, env) super() @@ -96,30 +94,15 @@ module ActionDispatch } def initialize(app, options = {}) - # Process legacy CGI options - options = options.symbolize_keys - if options.has_key?(:session_path) - options[:path] = options.delete(:session_path) - end - if options.has_key?(:session_key) - options[:key] = options.delete(:session_key) - end - if options.has_key?(:session_http_only) - options[:httponly] = options.delete(:session_http_only) - end - @app = app @default_options = DEFAULT_OPTIONS.merge(options) - @key = @default_options[:key] - @cookie_only = @default_options[:cookie_only] + @key = @default_options.delete(:key).freeze + @cookie_only = @default_options.delete(:cookie_only) + ensure_session_key! end def call(env) - session = SessionHash.new(self, env) - - env[ENV_SESSION_KEY] = session - env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup - + prepare!(env) response = @app.call(env) session_data = env[ENV_SESSION_KEY] @@ -129,53 +112,62 @@ module ActionDispatch session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?) sid = options[:id] || generate_sid + session_data = session_data.to_hash - unless set_session(env, sid, session_data.to_hash) - return response - end + value = set_session(env, sid, session_data) + return response unless value - cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid) - cookie << "; domain=#{options[:domain]}" if options[:domain] - cookie << "; path=#{options[:path]}" if options[:path] - if options[:expire_after] - expiry = Time.now + options[:expire_after] - cookie << "; expires=#{expiry.httpdate}" - end - cookie << "; Secure" if options[:secure] - cookie << "; HttpOnly" if options[:httponly] - - headers = response[1] - unless headers[SET_COOKIE].blank? - headers[SET_COOKIE] << "\n#{cookie}" - else - headers[SET_COOKIE] = cookie + cookie = { :value => value } + unless options[:expire_after].nil? + cookie[:expires] = Time.now + options.delete(:expire_after) end + + request = ActionDispatch::Request.new(env) + set_cookie(request, cookie.merge!(options)) end response end private + + def prepare!(env) + env[ENV_SESSION_KEY] = SessionHash.new(self, env) + env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup + end + def generate_sid ActiveSupport::SecureRandom.hex(16) end + def set_cookie(request, options) + request.cookie_jar[@key] = options + end + def load_session(env) request = Rack::Request.new(env) - sid = request.cookies[@key] - unless @cookie_only - sid ||= request.params[@key] - end + sid = request.cookies[@key] + sid ||= request.params[@key] unless @cookie_only sid, session = get_session(env, sid) [sid, session] end + def ensure_session_key! + if @key.blank? + raise ArgumentError, 'A key is required to write a ' + + 'cookie containing the session data. Use ' + + 'config.session_store SESSION_STORE, { :key => ' + + '"_myapp_session" } in config/application.rb' + end + end + def get_session(env, sid) raise '#get_session needs to be implemented.' end def set_session(env, sid, session_data) - raise '#set_session needs to be implemented.' + raise '#set_session needs to be implemented and should return ' << + 'the value to be stored in the cookie (usually the sid)' end end end diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 0c1712bf84..92a86ee229 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,4 +1,3 @@ -require 'action_dispatch/middleware/cookies' require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/object/blank' @@ -39,18 +38,10 @@ module ActionDispatch # "rake secret" and set the key in config/environment.rb. # # Note that changing digest or secret invalidates all existing sessions! - class CookieStore - DEFAULT_OPTIONS = { - :key => '_session_id', - :domain => nil, - :path => "/", - :expire_after => nil, - :httponly => true - }.freeze - + class CookieStore < AbstractStore class OptionsHash < Hash def initialize(by, env, default_options) - @session_data = env[CookieStore::ENV_SESSION_KEY] + @session_data = env[AbstractStore::ENV_SESSION_KEY] merge!(default_options) end @@ -59,96 +50,38 @@ module ActionDispatch end end - ENV_SESSION_KEY = "rack.session".freeze - ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze - def initialize(app, options = {}) - # Process legacy CGI options - # TODO Refactor and deprecate me - options = options.symbolize_keys - - if options.has_key?(:session_path) - options[:path] = options.delete(:session_path) - end - if options.has_key?(:session_key) - options[:key] = options.delete(:session_key) - end - if options.has_key?(:session_http_only) - options[:httponly] = options.delete(:session_http_only) - end - - @app = app - - # The session_key option is required. - ensure_session_key(options[:key]) - @key = options.delete(:key).freeze - - @default_options = DEFAULT_OPTIONS.merge(options).freeze + super(app, options.merge!(:cookie_only => true)) freeze end - def call(env) - env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env) - env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options) - - status, headers, body = @app.call(env) - - session_data = env[ENV_SESSION_KEY] - options = env[ENV_SESSION_OPTIONS_KEY] - - if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after] - session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?) - session_data = persistent_session_id!(session_data.to_hash) - - cookie = { :value => session_data } - unless options[:expire_after].nil? - cookie[:expires] = Time.now + options.delete(:expire_after) - end + private - request = ActionDispatch::Request.new(env) - request.cookie_jar.signed[@key] = cookie.merge!(options) + def prepare!(env) + env[ENV_SESSION_KEY] = SessionHash.new(self, env) + env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options) end - [status, headers, body] - end - - private - def load_session(env) request = ActionDispatch::Request.new(env) data = request.cookie_jar.signed[@key] - data = persistent_session_id!(data || {}) + data = persistent_session_id!(data) data.stringify_keys! [data["session_id"], data] end - def generate_sid - ActiveSupport::SecureRandom.hex(16) - end - - def ensure_session_key(key) - if key.blank? - raise ArgumentError, 'A key is required to write a ' + - 'cookie containing the session data. Use ' + - 'config.session_store :cookie_store, { :key => ' + - '"_myapp_session" } in config/application.rb' - end - end - - def persistent_session_id!(data) - (data ||= {}).merge!(inject_persistent_session_id(data)) + def set_cookie(request, options) + request.cookie_jar.signed[@key] = options end - def inject_persistent_session_id(data) - requires_session_id?(data) ? { "session_id" => generate_sid } : {} + def set_session(env, sid, session_data) + persistent_session_id!(session_data, sid) end - def requires_session_id?(data) - if data - data.respond_to?(:key?) && !data.key?("session_id") - else - true - end + def persistent_session_id!(data, sid=nil) + data ||= {} + data["session_id"] ||= sid || generate_sid + data end end end diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb index be1d5a43a2..8df8f977e8 100644 --- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb @@ -38,9 +38,9 @@ module ActionDispatch options = env['rack.session.options'] expiry = options[:expire_after] || 0 @pool.set(sid, session_data, expiry) - return true + sid rescue MemCache::MemCacheError, Errno::ECONNREFUSED - return false + false end end end diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 61bee1b66c..6d4b8e1e40 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -152,12 +152,18 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest end private + def with_test_route_set(options = {}) with_routing do |set| set.draw do |map| match ':action', :to => 'active_record_store_test/test' end - @app = ActiveRecord::SessionStore.new(set, options.reverse_merge(:key => '_session_id')) + + @app = self.class.build_app(set) do |middleware| + middleware.use ActiveRecord::SessionStore, options.reverse_merge(:key => '_session_id') + middleware.delete "ActionDispatch::ShowExceptions" + end + yield end end diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index a6cdbf8032..21d11ff31c 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -199,7 +199,7 @@ class CookieStoreTest < ActionController::IntegrationTest match ':action', :to => ::CookieStoreTest::TestController end - options = { :key => SessionKey, :secret => SessionSecret }.merge!(options) + options = { :key => SessionKey }.merge!(options) @app = self.class.build_app(set) do |middleware| middleware.use ActionDispatch::Session::CookieStore, options diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 5a1dcb4dab..8858a398e0 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -114,7 +114,12 @@ class MemCacheStoreTest < ActionController::IntegrationTest set.draw do |map| match ':action', :to => ::MemCacheStoreTest::TestController end - @app = ActionDispatch::Session::MemCacheStore.new(set, :key => '_session_id') + + @app = self.class.build_app(set) do |middleware| + middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id' + middleware.delete "ActionDispatch::ShowExceptions" + end + yield end end diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 9dda3361d8..931872eded 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -307,7 +307,7 @@ module ActiveRecord end end - return true + sid end def get_session_model(env, sid) -- cgit v1.2.3 From 5ddc9049416e8b6093a7bb3ad4341694f7a14d9f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 17 May 2010 15:41:22 +0100 Subject: Remove Model.clear_default_scope --- activerecord/lib/active_record/base.rb | 4 ---- activerecord/test/cases/method_scoping_test.rb | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 18f75af11b..1b76f357e3 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1193,10 +1193,6 @@ module ActiveRecord #:nodoc: self.default_scoping << construct_finder_arel(options, default_scoping.pop) end - def clear_default_scope - self.default_scoping.clear - end - def scoped_methods #:nodoc: key = :"#{self}_scoped_methods" Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 3a6354ec6d..cb599e363f 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -587,18 +587,6 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase end end -class ClearDefaultScopeTest < ActiveRecord::TestCase - fixtures :developers - - def test_should_clear_default_scope - klass = Class.new(DeveloperCalledDavid) - klass.__send__ :clear_default_scope - expected = Developer.all.collect { |dev| dev.name } - actual = klass.all.collect { |dev| dev.name } - assert_equal expected, actual - end -end - class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts -- cgit v1.2.3 From c00f8e49add3f4ab6416e738c4ee2837370b2f3f Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 22:55:02 -0400 Subject: assert should be replaced with assert_equal in a particular test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4636 state:resolved] Signed-off-by: José Valim --- activeresource/test/cases/base_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index 4e21e84596..daf58613c0 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -1048,7 +1048,7 @@ class BaseTest < Test::Unit::TestCase json = joe.to_json Person.format = :xml - assert encode, json + assert_equal encode, json assert_match %r{^\{"person":\{"person":\{}, json assert_match %r{"id":6}, json assert_match %r{"name":"Joe"}, json -- cgit v1.2.3 From 0dab076a08110b87aacc27e2ce5a20173b3d458d Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 22:45:36 -0400 Subject: Better error messages for some of ActiveSupport tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4635 state:resolved] Signed-off-by: José Valim --- activesupport/test/buffered_logger_test.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb index 5b072d4102..850febb959 100644 --- a/activesupport/test/buffered_logger_test.rb +++ b/activesupport/test/buffered_logger_test.rb @@ -69,11 +69,11 @@ class BufferedLoggerTest < Test::Unit::TestCase 4.times do @logger.info 'wait for it..' - assert @output.string.empty?, @output.string + assert @output.string.empty?, "@output.string should be empty but it is #{@output.string}" end @logger.flush - assert !@output.string.empty?, @logger.send(:buffer).size.to_s + assert !@output.string.empty?, "@logger.send(:buffer).size.to_s should not be empty but it is empty" end define_method "test_disabling_auto_flush_with_#{disable.inspect}_should_flush_at_max_buffer_size_as_failsafe" do @@ -82,11 +82,11 @@ class BufferedLoggerTest < Test::Unit::TestCase (Logger::MAX_BUFFER_SIZE - 1).times do @logger.info 'wait for it..' - assert @output.string.empty?, @output.string + assert @output.string.empty?, "@output.string should be empty but is #{@output.string}" end @logger.info 'there it is.' - assert !@output.string.empty?, @logger.send(:buffer).size.to_s + assert !@output.string.empty?, "@logger.send(:buffer).size.to_s should not be empty but it is empty" end end @@ -102,11 +102,11 @@ class BufferedLoggerTest < Test::Unit::TestCase 4.times do @logger.info 'wait for it..' - assert @output.string.empty?, @output.string + assert @output.string.empty?, "@output.string should be empty but it is #{@output.string}" end @logger.info 'there it is.' - assert !@output.string.empty?, @output.string + assert !@output.string.empty?, "@output.string should not be empty but it is empty" end def test_should_create_the_log_directory_if_it_doesnt_exist -- cgit v1.2.3 From d00afeaeed8d23488c319c2fbdbbe8261eebe611 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 11:48:30 -0400 Subject: Use assert_equal correctly in actionmailer test (exposing one as broken) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4626 state:resolved] Signed-off-by: José Valim --- actionmailer/test/old_base/mail_service_test.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index f91e7f893c..f343d32019 100644 --- a/actionmailer/test/old_base/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -1048,8 +1048,9 @@ EOF def test_multipart_with_template_path_with_dots mail = FunkyPathMailer.multipart_with_template_path_with_dots(@recipient) assert_equal 2, mail.parts.length - assert "text/plain", mail.parts[1].mime_type - assert "UTF-8", mail.parts[1].charset + assert_equal "text/plain", mail.parts[0].mime_type + assert_equal "text/html", mail.parts[1].mime_type + assert_equal "UTF-8", mail.parts[1].charset end def test_custom_content_type_attributes -- cgit v1.2.3 From 0ef13afef53bb53f709be7adab3e863ec62eae62 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 16:40:48 -0400 Subject: expected value should come first in assert_equal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4630 state:resolved] Signed-off-by: José Valim --- activerecord/test/cases/pooled_connections_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index 94d6663778..e61960059e 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -34,8 +34,8 @@ class PooledConnectionsTest < ActiveRecord::TestCase if RUBY_VERSION < '1.9' def test_pooled_connection_checkout checkout_connections - assert_equal @connections.length, 2 - assert_equal @timed_out, 2 + assert_equal 2, @connections.length + assert_equal 2, @timed_out end end @@ -137,4 +137,4 @@ class PooledConnectionsTest < ActiveRecord::TestCase def add_record(name) ActiveRecord::Base.connection_pool.with_connection { Project.create! :name => name } end -end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name \ No newline at end of file +end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name -- cgit v1.2.3 From ce20b93606195eff1ea2dfeb2aa311130dd9977e Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 17 May 2010 16:23:43 -0400 Subject: assert_equal should be used instead of assert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4629 state:resolved] Signed-off-by: José Valim --- activerecord/test/cases/modules_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index c924c3dfad..4b635792c7 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -35,7 +35,7 @@ class ModulesTest < ActiveRecord::TestCase def test_module_spanning_has_and_belongs_to_many_associations project = MyApplication::Business::Project.find(:first) project.developers << MyApplication::Business::Developer.create("name" => "John") - assert "John", project.developers.last.name + assert_equal "John", project.developers.last.name end def test_associations_spanning_cross_modules -- cgit v1.2.3 From b439d85a19c02eefab1ee308fff334ac1049524d Mon Sep 17 00:00:00 2001 From: Ian White Date: Tue, 18 May 2010 10:28:26 +0100 Subject: Nested records (re: autosave) are now updated even when the intermediate parent record is unchanged [#4242 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/active_record/autosave_association.rb | 23 ++++++- activerecord/test/cases/nested_attributes_test.rb | 80 ++++++++++++++++++++++ activerecord/test/models/ship.rb | 3 +- activerecord/test/models/ship_part.rb | 2 + 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index fd1082a268..c553e95bad 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -214,6 +214,12 @@ module ActiveRecord @marked_for_destruction end + # Returns whether or not this record has been changed in any way (including whether + # any of its nested autosave associations are likewise changed) + def changed_for_autosave? + new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? + end + private # Returns the record for an association collection that should be validated @@ -223,12 +229,27 @@ module ActiveRecord if new_record association elsif autosave - association.target.find_all { |record| record.new_record? || record.changed? || record.marked_for_destruction? } + association.target.find_all { |record| record.changed_for_autosave? } else association.target.find_all { |record| record.new_record? } end end + # go through nested autosave associations that are loaded in memory (without loading + # any new ones), and return true if is changed for autosave + def nested_records_changed_for_autosave? + self.class.reflect_on_all_autosave_associations.each do |reflection| + if association = association_instance_get(reflection.name) + if [:belongs_to, :has_one].include?(reflection.macro) + return true if association.target && association.target.changed_for_autosave? + else + association.target.each {|record| return true if record.changed_for_autosave? } + end + end + end + false + end + # Validate the association if :validate or :autosave is # turned on for the association specified by +reflection+. def validate_single_association(reflection) diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index fadd62b5a1..57b66fb312 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -1,6 +1,7 @@ require "cases/helper" require "models/pirate" require "models/ship" +require "models/ship_part" require "models/bird" require "models/parrot" require "models/treasure" @@ -732,3 +733,82 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name) end end + +class TestHasOneAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!") + @ship = @pirate.create_ship(:name => "The good ship Dollypop") + @part = @ship.parts.create!(:name => "Mast") + @trinket = @part.trinkets.create!(:name => "Necklace") + end + + test "when great-grandchild changed in memory, saving parent should save great-grandchild" do + @trinket.name = "changed" + @pirate.save + assert_equal "changed", @trinket.reload.name + end + + test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}} + @pirate.save + assert_equal "changed", @trinket.reload.name + end + + test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}} + assert_difference('@part.trinkets.count', -1) { @pirate.save } + end + + test "when great-grandchild added via attributes, saving parent should create great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}} + assert_difference('@part.trinkets.count', 1) { @pirate.save } + end + + test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do + @trinket.name = "changed" + Ship.create!(:pirate => @pirate, :name => "The Black Rock") + ShipPart.create!(:ship => @ship, :name => "Stern") + assert_no_queries { @pirate.valid? } + end +end + +class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @ship = Ship.create!(:name => "The good ship Dollypop") + @part = @ship.parts.create!(:name => "Mast") + @trinket = @part.trinkets.create!(:name => "Necklace") + end + + test "when grandchild changed in memory, saving parent should save grandchild" do + @trinket.name = "changed" + @ship.save + assert_equal "changed", @trinket.reload.name + end + + test "when grandchild changed via attributes, saving parent should save grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]} + @ship.save + assert_equal "changed", @trinket.reload.name + end + + test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]} + assert_difference('@part.trinkets.count', -1) { @ship.save } + end + + test "when grandchild added via attributes, saving parent should create grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]} + assert_difference('@part.trinkets.count', 1) { @ship.save } + end + + test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do + @trinket.name = "changed" + Ship.create!(:name => "The Black Rock") + ShipPart.create!(:ship => @ship, :name => "Stern") + assert_no_queries { @ship.valid? } + end +end diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index 75c792d176..3da031946f 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -3,8 +3,9 @@ class Ship < ActiveRecord::Base belongs_to :pirate belongs_to :update_only_pirate, :class_name => 'Pirate' - has_many :parts, :class_name => 'ShipPart', :autosave => true + has_many :parts, :class_name => 'ShipPart' + accepts_nested_attributes_for :parts, :allow_destroy => true accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } accepts_nested_attributes_for :update_only_pirate, :update_only => true diff --git a/activerecord/test/models/ship_part.rb b/activerecord/test/models/ship_part.rb index 0a606db239..b6a8a506b4 100644 --- a/activerecord/test/models/ship_part.rb +++ b/activerecord/test/models/ship_part.rb @@ -1,5 +1,7 @@ class ShipPart < ActiveRecord::Base belongs_to :ship + has_many :trinkets, :class_name => "Treasure", :as => :looter + accepts_nested_attributes_for :trinkets, :allow_destroy => true validates_presence_of :name end \ No newline at end of file -- cgit v1.2.3 From 03c3d1eb8489fc530e6fac49547a229d386808c1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 May 2010 02:45:06 -0300 Subject: Fixes transaction callbacks tests [#4640 state:committed] Signed-off-by: wycats --- .../test/cases/transaction_callbacks_test.rb | 42 ++++++++++------------ 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 9c74dce965..7469cdb299 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -58,26 +58,24 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @first.save! assert_equal [:commit_on_update], @first.history end def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @first.destroy assert_equal [:commit_on_destroy], @first.history @@ -88,9 +86,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @new_record.after_commit_block(:create){|r| r.history << :commit_on_create} @new_record.after_commit_block(:update){|r| r.history << :commit_on_update} @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create} - @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update} - @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @new_record.save! assert_equal [:commit_on_create], @new_record.history @@ -109,13 +107,12 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @first.save! @@ -126,13 +123,12 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_update} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @first.destroy @@ -147,9 +143,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @new_record.after_commit_block(:create){|r| r.history << :commit_on_create} @new_record.after_commit_block(:update){|r| r.history << :commit_on_update} @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create} - @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update} - @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @new_record.save! @@ -198,7 +194,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase assert_equal 1, @first.commits assert_equal 0, @first.rollbacks - assert_equal 1, @second.commits + assert_equal 0, @second.commits assert_equal 1, @second.rollbacks end -- cgit v1.2.3 From d3e62fc57ce3a0a1df62359f53d217d434c2d2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 18 May 2010 17:45:05 +0200 Subject: Avoid creating a Rack::Response object in the cookie middleware since it may stream the body. --- .../lib/action_dispatch/middleware/cookies.rb | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 1e49a307ed..87e8dd5010 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -52,12 +52,15 @@ module ActionDispatch # * :httponly - Whether this cookie is accessible via scripting or # only HTTP. Defaults to +false+. class Cookies + HTTP_HEADER = "Set-Cookie".freeze + TOKEN_KEY = "action_dispatch.secret_token".freeze + # Raised when storing more than 4K of session data. class CookieOverflow < StandardError; end class CookieJar < Hash #:nodoc: def self.build(request) - secret = request.env["action_dispatch.secret_token"] + secret = request.env[TOKEN_KEY] new(secret).tap do |hash| hash.update(request.cookies) end @@ -137,9 +140,9 @@ module ActionDispatch @signed ||= SignedCookieJar.new(self, @secret) end - def write(response) - @set_cookies.each { |k, v| response.set_cookie(k, v) } - @delete_cookies.each { |k, v| response.delete_cookie(k, v) } + def write(headers) + @set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) } + @delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) } end end @@ -232,12 +235,13 @@ module ActionDispatch status, headers, body = @app.call(env) if cookie_jar = env['action_dispatch.cookies'] - response = Rack::Response.new(body, status, headers) - cookie_jar.write(response) - response.to_a - else - [status, headers, body] + cookie_jar.write(headers) + if headers[HTTP_HEADER].respond_to?(:join) + headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n") + end end + + [status, headers, body] end end end -- cgit v1.2.3 From 3809c80cd55ac2838f050346800889b6f8e041ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?E=CC=81tienne=20Barrie=CC=81?= Date: Sun, 16 May 2010 18:50:25 +0200 Subject: make add_index and remove_index more resilient; new rename_index method; track database limits [#3452 state:committed] Signed-off-by: Jeremy Kemper --- .../abstract/database_limits.rb | 57 ++++++++++++++++++++++ .../abstract/schema_statements.rb | 45 ++++++++++++++--- .../connection_adapters/abstract_adapter.rb | 2 + .../connection_adapters/postgresql_adapter.rb | 9 ++-- .../connection_adapters/sqlite_adapter.rb | 4 +- .../test/cases/active_schema_test_mysql.rb | 5 ++ activerecord/test/cases/migration_test.rb | 34 +++++++++++++ activerecord/test/cases/schema_test_postgresql.rb | 4 +- 8 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb new file mode 100644 index 0000000000..4118ea7b31 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb @@ -0,0 +1,57 @@ +module ActiveRecord + module ConnectionAdapters # :nodoc: + module DatabaseLimits + + # the maximum length of a table alias + def table_alias_length + 255 + end + + # the maximum length of a column name + def column_name_length + 64 + end + + # the maximum length of a table name + def table_name_length + 64 + end + + # the maximum length of an index name + def index_name_length + 64 + end + + # the maximum number of columns per table + def columns_per_table + 1024 + end + + # the maximum number of indexes per table + def indexes_per_table + 16 + end + + # the maximum number of columns in a multicolumn index + def columns_per_multicolumn_index + 16 + end + + # the maximum number of elements in an IN (x,y,z) clause + def in_clause_length + 65535 + end + + # the maximum length of a SQL query + def sql_query_length + 1048575 + end + + # maximum number of joins in a single query + def joins_per_query + 256 + end + + end + end +end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 1255ef09be..d3499cea72 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -10,11 +10,6 @@ module ActiveRecord {} end - # This is the maximum length a table alias can be - def table_alias_length - 255 - end - # Truncates a table alias according to the limits of the current adapter. def table_alias_for(table_name) table_name[0..table_alias_length-1].gsub(/\./, '_') @@ -293,6 +288,14 @@ module ActiveRecord index_type = options end + if index_name.length > index_name_length + @logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.") + return + end + if index_exists?(table_name, index_name, false) + @logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.") + return + end quoted_column_names = quoted_columns_for_index(column_names, options).join(", ") execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})" @@ -309,7 +312,28 @@ module ActiveRecord # Remove the index named by_branch_party in the accounts table. # remove_index :accounts, :name => :by_branch_party def remove_index(table_name, options = {}) - execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{quote_table_name(table_name)}" + index_name = index_name(table_name, options) + unless index_exists?(table_name, index_name, true) + @logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.") + return + end + remove_index!(table_name, index_name) + end + + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}" + end + + # Rename an index. + # + # Rename the index_people_on_last_name index to index_users_on_last_name + # rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name' + def rename_index(table_name, old_name, new_name) + # this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance) + old_index_def = indexes(table_name).detect { |i| i.name == old_name } + return unless old_index_def + remove_index(table_name, :name => old_name) + add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique) end def index_name(table_name, options) #:nodoc: @@ -326,6 +350,15 @@ module ActiveRecord end end + # Verify the existence of an index. + # + # The default argument is returned if the underlying implementation does not define the indexes method, + # as there's no way to determine the correct answer in that case. + def index_exists?(table_name, index_name, default) + return default unless respond_to?(:indexes) + indexes(table_name).detect { |i| i.name == index_name } + end + # Returns a string of CREATE TABLE SQL statement(s) for recreating the # entire structure of the database. def structure_dump diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 28a59c1e62..fecd4d590e 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -11,6 +11,7 @@ require 'active_record/connection_adapters/abstract/quoting' require 'active_record/connection_adapters/abstract/connection_pool' require 'active_record/connection_adapters/abstract/connection_specification' require 'active_record/connection_adapters/abstract/query_cache' +require 'active_record/connection_adapters/abstract/database_limits' module ActiveRecord module ConnectionAdapters # :nodoc: @@ -29,6 +30,7 @@ module ActiveRecord # notably, the instance methods provided by SchemaStatement are very useful. class AbstractAdapter include Quoting, DatabaseStatements, SchemaStatements + include DatabaseLimits include QueryCache include ActiveSupport::Callbacks diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 6389094b8a..34aaff2b49 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -819,9 +819,12 @@ module ActiveRecord execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}" end - # Drops an index from a table. - def remove_index(table_name, options = {}) - execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}" + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_table_name(index_name)}" + end + + def index_name_length + 63 end # Maps logical Rails types to PostgreSQL-specific data types. diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 29225b83c5..e8a45bb3c6 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -217,8 +217,8 @@ module ActiveRecord column ? column['name'] : nil end - def remove_index(table_name, options={}) #:nodoc: - execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}" + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_column_name(index_name)}" end def rename_table(name, new_name) diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index f4d123be15..3526f49afd 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -16,6 +16,10 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_index + # add_index calls index_exists? which can't work since execute is stubbed + ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:define_method, :index_exists?) do |*| + false + end expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)" assert_equal expected, add_index(:people, :last_name, :length => nil) @@ -30,6 +34,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))" assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) + ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:remove_method, :index_exists?) end def test_drop_table diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 768a44f6df..851daa69a5 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -119,6 +119,40 @@ if ActiveRecord::Base.connection.supports_migrations? end end + def test_add_index_length_limit + good_index_name = 'x' * Person.connection.index_name_length + too_long_index_name = good_index_name + 'x' + assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => too_long_index_name) } + assert !Person.connection.index_exists?("people", too_long_index_name, false) + assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => good_index_name) } + assert Person.connection.index_exists?("people", good_index_name, false) + end + + def test_remove_nonexistent_index + # we do this by name, so OpenBase is a wash as noted above + unless current_adapter?(:OpenBaseAdapter) + assert_nothing_raised { Person.connection.remove_index("people", "no_such_index") } + end + end + + def test_rename_index + unless current_adapter?(:OpenBaseAdapter) + # keep the names short to make Oracle and similar behave + Person.connection.add_index('people', [:first_name], :name => 'old_idx') + assert_nothing_raised { Person.connection.rename_index('people', 'old_idx', 'new_idx') } + # if the adapter doesn't support the indexes call, pick defaults that let the test pass + assert !Person.connection.index_exists?('people', 'old_idx', false) + assert Person.connection.index_exists?('people', 'new_idx', true) + end + end + + def test_double_add_index + unless current_adapter?(:OpenBaseAdapter) + Person.connection.add_index('people', [:first_name], :name => 'some_idx') + assert_nothing_raised { Person.connection.add_index('people', [:first_name], :name => 'some_idx') } + end + end + def testing_table_with_only_foo_attribute Person.connection.create_table :testings, :id => false do |t| t.column :foo, :string diff --git a/activerecord/test/cases/schema_test_postgresql.rb b/activerecord/test/cases/schema_test_postgresql.rb index 3ed73786a7..3ed9b1974d 100644 --- a/activerecord/test/cases/schema_test_postgresql.rb +++ b/activerecord/test/cases/schema_test_postgresql.rb @@ -152,11 +152,11 @@ class SchemaTest < ActiveRecord::TestCase def test_with_uppercase_index_name ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" - assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "#{SCHEMA_NAME}.things_Index"} + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"} ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME - assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "things_Index"} + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "things_Index"} ActiveRecord::Base.connection.schema_search_path = "public" end -- cgit v1.2.3 From 223d6415d045e670610603665c21e93b06a01db7 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 18 May 2010 11:02:39 -0700 Subject: Revert "Don't carry default value when changing column for a binary type on MySQL" Broke mysql tests. This reverts commit edec1afe25014749f0e2df86d27477b45586a9e3. Conflicts: activerecord/test/cases/migration_test.rb [#3234 state:open] --- .../lib/active_record/connection_adapters/mysql_adapter.rb | 6 +----- activerecord/test/cases/migration_test.rb | 12 ------------ 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index e12924e63f..ec25bbf18e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -513,7 +513,7 @@ module ActiveRecord def change_column(table_name, column_name, type, options = {}) #:nodoc: column = column_for(table_name, column_name) - if has_default?(type) && !options_include_default?(options) + unless options_include_default?(options) options[:default] = column.default end @@ -675,10 +675,6 @@ module ActiveRecord end column end - - def has_default?(sql_type) - sql_type =~ :binary || sql_type == :text #mysql forbids defaults on blob and text columns - end end end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 851daa69a5..692e4b207f 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -894,18 +894,6 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "Tester", Person.new.first_name end - unless current_adapter?(:PostgreSQLAdapter) - def test_change_column_type_default_should_change - old_columns = Person.connection.columns(Person.table_name, "#{name} Columns") - assert !old_columns.find { |c| c.name == 'data' } - - assert_nothing_raised do - Person.connection.add_column "people", "data", :string, :default => '' - Person.connection.change_column "people", "data", :binary - end - end - end - def test_change_column_quotes_column_names Person.connection.create_table :testings do |t| t.column :select, :string -- cgit v1.2.3 From b753b4a076d7067efccbd1ad384829f77e62a064 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 19 May 2010 00:20:10 +0200 Subject: removes deprecations of last_(month|year) from master, they will be deprecated in 2.3 instead --- activesupport/CHANGELOG | 2 +- .../lib/active_support/core_ext/date/calculations.rb | 11 ----------- .../lib/active_support/core_ext/time/calculations.rb | 11 ----------- activesupport/test/core_ext/date_ext_test.rb | 8 -------- activesupport/test/core_ext/time_ext_test.rb | 8 -------- 5 files changed, 1 insertion(+), 39 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 7d00211ea1..c617a0ec3b 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -2,7 +2,7 @@ * Renames Array#rand -> Array#random_element. [Santiago Pastorino, Rizwan Reza] -* Defines prev_(month|year) in Date and Time, and deprecates last_(month|year). [fxn] +* 1.9 compat: Renames last_(month|year) to prev_(month|year) in Date and Time. [fxn] * Aliases Date#sunday to Date#end_of_week. [fxn] diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 755d96ce91..579079d4f1 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -2,7 +2,6 @@ require 'date' require 'active_support/duration' require 'active_support/core_ext/time/zones' require 'active_support/core_ext/object/acts_like' -require 'active_support/deprecation' class Date if RUBY_VERSION < '1.9' @@ -147,11 +146,6 @@ class Date advance(:years => years) end - def last_year # :nodoc: - ActiveSupport::Deprecation.warn("Date#last_year has been deprecated, please use Date#prev_year instead", caller) - prev_year - end - # Shorthand for years_ago(1) def prev_year years_ago(1) @@ -161,11 +155,6 @@ class Date def next_year years_since(1) end unless method_defined?(:next_year) - - def last_month # :nodoc: - ActiveSupport::Deprecation.warn("Date#last_month has been deprecated, please use Date#prev_month instead", caller) - prev_month - end # Short-hand for months_ago(1) def prev_month diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index e27b08ec2e..3c218d88e5 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -2,7 +2,6 @@ require 'active_support/duration' require 'active_support/core_ext/date/acts_like' require 'active_support/core_ext/date/calculations' require 'active_support/core_ext/date_time/conversions' -require 'active_support/deprecation' class Time COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] @@ -133,11 +132,6 @@ class Time advance(:years => years) end - def last_year # :nodoc: - ActiveSupport::Deprecation.warn("Time#last_year has been deprecated, please use Time#prev_year instead", caller) - prev_year - end - # Short-hand for years_ago(1) def prev_year years_ago(1) @@ -148,11 +142,6 @@ class Time years_since(1) end - def last_month # :nodoc: - ActiveSupport::Deprecation.warn("Time#last_month has been deprecated, please use Time#prev_month instead", caller) - prev_month - end - # Short-hand for months_ago(1) def prev_month months_ago(1) diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index 1bf118e3b7..a3a2f13436 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -145,10 +145,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(2005,2,28), Date.new(2004,2,29).years_since(1) # 1 year since leap day end - def test_last_year_is_deprecated - assert_deprecated { Date.today.last_year } - end - def test_prev_year assert_equal Date.new(2004,6,5), Date.new(2005,6,5).prev_year end @@ -229,10 +225,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(2005, 9, 30), Date.new(2005, 8, 31).next_month end - def test_last_month_is_deprecated - assert_deprecated { Date.today.last_month } - end - def test_prev_month_on_31st assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).prev_month end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 30ee1d1652..1cf84df386 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -166,10 +166,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase # assert_equal Time.local(2182,6,5,10), Time.local(2005,6,5,10,0,0).years_since(177) end - def test_last_year_is_deprecated - assert_deprecated { Time.now.last_year } - end - def test_prev_year assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).prev_year end @@ -619,10 +615,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month end - def test_last_month_is_deprecated - assert_deprecated { Time.now.last_month } - end - def test_prev_month_on_31st assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).prev_month end -- cgit v1.2.3 From b4629528866446aa59f663a1162edbdacee85600 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 18 May 2010 21:47:24 -0400 Subject: Use better assertion methods for testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4645 state:resolved] Signed-off-by: José Valim --- actionmailer/test/base_test.rb | 4 +- actionmailer/test/old_base/asset_host_test.rb | 8 ++-- actionmailer/test/old_base/mail_render_test.rb | 2 +- actionmailer/test/old_base/mail_service_test.rb | 22 +++++----- actionmailer/test/test_helper_test.rb | 4 +- actionpack/test/controller/filters_test.rb | 14 +++--- .../test/controller/new_base/bare_metal_test.rb | 4 +- activemodel/test/cases/attribute_methods_test.rb | 2 +- activemodel/test/cases/callbacks_test.rb | 2 +- activemodel/test/cases/dirty_test.rb | 4 +- .../serializeration/xml_serialization_test.rb | 2 +- activerecord/test/cases/aggregations_test.rb | 20 ++++----- .../associations/belongs_to_associations_test.rb | 4 +- .../eager_load_includes_full_sti_class_test.rb | 2 +- activerecord/test/cases/associations/eager_test.rb | 2 +- .../associations/has_many_associations_test.rb | 13 ++---- .../has_many_through_associations_test.rb | 4 +- .../associations/has_one_associations_test.rb | 8 ++-- .../associations/inverse_associations_test.rb | 18 ++++---- .../test/cases/associations/join_model_test.rb | 4 +- activerecord/test/cases/attribute_methods_test.rb | 2 +- .../test/cases/autosave_association_test.rb | 8 ++-- activerecord/test/cases/base_test.rb | 50 +++++++++++----------- activerecord/test/cases/column_definition_test.rb | 6 +-- activerecord/test/cases/defaults_test.rb | 4 +- activerecord/test/cases/dirty_test.rb | 4 +- activerecord/test/cases/finder_respond_to_test.rb | 22 +++++----- 27 files changed, 116 insertions(+), 123 deletions(-) diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 5506d62d6a..54bf3de6af 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -491,8 +491,8 @@ class BaseTest < ActiveSupport::TestCase # Class level API with method missing test "should respond to action methods" do - assert BaseMailer.respond_to?(:welcome) - assert BaseMailer.respond_to?(:implicit_multipart) + assert_respond_to BaseMailer, :welcome + assert_respond_to BaseMailer, :implicit_multipart assert !BaseMailer.respond_to?(:mail) assert !BaseMailer.respond_to?(:headers) end diff --git a/actionmailer/test/old_base/asset_host_test.rb b/actionmailer/test/old_base/asset_host_test.rb index 0ec0242f55..cc13c8a4d7 100644 --- a/actionmailer/test/old_base/asset_host_test.rb +++ b/actionmailer/test/old_base/asset_host_test.rb @@ -26,7 +26,7 @@ class AssetHostTest < Test::Unit::TestCase def test_asset_host_as_string mail = AssetHostMailer.email_with_asset - assert_equal "\"Somelogo\"", mail.body.to_s.strip + assert_equal %Q{Somelogo}, mail.body.to_s.strip end def test_asset_host_as_one_arguement_proc @@ -38,7 +38,7 @@ class AssetHostTest < Test::Unit::TestCase end } mail = AssetHostMailer.email_with_asset - assert_equal "\"Somelogo\"", mail.body.to_s.strip + assert_equal %Q{Somelogo}, mail.body.to_s.strip end def test_asset_host_as_two_arguement_proc @@ -51,6 +51,6 @@ class AssetHostTest < Test::Unit::TestCase } mail = nil assert_nothing_raised { mail = AssetHostMailer.email_with_asset } - assert_equal "\"Somelogo\"", mail.body.to_s.strip + assert_equal %Q{Somelogo}, mail.body.to_s.strip end -end \ No newline at end of file +end diff --git a/actionmailer/test/old_base/mail_render_test.rb b/actionmailer/test/old_base/mail_render_test.rb index 405d43d7d3..08951833a5 100644 --- a/actionmailer/test/old_base/mail_render_test.rb +++ b/actionmailer/test/old_base/mail_render_test.rb @@ -117,7 +117,7 @@ class RenderHelperTest < Test::Unit::TestCase def test_rxml_template mail = RenderMailer.rxml_template.deliver - assert_equal "\n", mail.body.to_s.strip + assert_equal %(\n), mail.body.to_s.strip end def test_included_subtemplate diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb index f343d32019..7054e8052a 100644 --- a/actionmailer/test/old_base/mail_service_test.rb +++ b/actionmailer/test/old_base/mail_service_test.rb @@ -281,7 +281,7 @@ class TestMailer < ActionMailer::Base from "One: Two " cc "Three: Four " bcc "Five: Six " - body "testing" + body "testing" end def custom_content_type_attributes @@ -289,7 +289,7 @@ class TestMailer < ActionMailer::Base subject "custom content types" from "some.one@somewhere.test" content_type "text/plain; format=flowed" - body "testing" + body "testing" end def return_path @@ -297,7 +297,7 @@ class TestMailer < ActionMailer::Base subject "return path test" from "some.one@somewhere.test" headers["return-path"] = "another@somewhere.test" - body "testing" + body "testing" end def subject_with_i18n(recipient) @@ -417,7 +417,7 @@ class ActionMailerTest < Test::Unit::TestCase end def test_custom_template - expected = new_mail + expected = new_mail expected.to = @recipient expected.subject = "[Signed up] Welcome #{@recipient}" expected.body = "Hello there, \n\nMr. #{@recipient}" @@ -436,7 +436,7 @@ class ActionMailerTest < Test::Unit::TestCase assert ActionView::Template.template_handler_extensions.include?("haml"), "haml extension was not registered" # N.b., custom_templating_extension.text.plain.haml is expected to be in fixtures/test_mailer directory - expected = new_mail + expected = new_mail expected.to = @recipient expected.subject = "[Signed up] Welcome #{@recipient}" expected.body = "Hello there, \n\nMr. #{@recipient}" @@ -453,7 +453,7 @@ class ActionMailerTest < Test::Unit::TestCase end def test_cancelled_account - expected = new_mail + expected = new_mail expected.to = @recipient expected.subject = "[Cancelled] Goodbye #{@recipient}" expected.body = "Goodbye, Mr. #{@recipient}" @@ -477,7 +477,7 @@ class ActionMailerTest < Test::Unit::TestCase end def test_cc_bcc - expected = new_mail + expected = new_mail expected.to = @recipient expected.subject = "testing bcc/cc" expected.body = "Nothing to see here." @@ -602,7 +602,7 @@ class ActionMailerTest < Test::Unit::TestCase def test_unencoded_subject TestMailer.delivery_method = :test - expected = new_mail + expected = new_mail expected.to = @recipient expected.subject = "testing unencoded subject" expected.body = "Nothing to see here." @@ -1151,15 +1151,15 @@ class RespondToTest < Test::Unit::TestCase end def test_should_respond_to_new - assert RespondToMailer.respond_to?(:new) + assert_respond_to RespondToMailer, :new end def test_should_respond_to_create_with_template_suffix - assert RespondToMailer.respond_to?(:create_any_old_template) + assert_respond_to RespondToMailer, :create_any_old_template end def test_should_respond_to_deliver_with_template_suffix - assert RespondToMailer.respond_to?(:deliver_any_old_template) + assert_respond_to RespondToMailer, :deliver_any_old_template end def test_should_not_respond_to_new_with_template_suffix diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 440fb868c8..8ff604c2c7 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -18,7 +18,7 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_setup_creates_the_expected_mailer - assert @expected.is_a?(Mail::Message) + assert_kind_of Mail::Message, @expected assert_equal "1.0", @expected.mime_version assert_equal "text/plain", @expected.mime_type end @@ -121,7 +121,7 @@ class AnotherTestHelperMailerTest < ActionMailer::TestCase end def test_setup_shouldnt_conflict_with_mailer_setup - assert @expected.is_a?(Mail::Message) + assert_kind_of Mail::Message, @expected assert_equal 'a value', @test_var end end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index ea740f7233..d5704eba78 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -515,7 +515,7 @@ class FilterTest < ActionController::TestCase assert assigns["ran_proc_filter2"] test_process(AnomolousYetValidConditionController, "show_without_filter") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] assert !assigns["ran_class_filter"] assert !assigns["ran_proc_filter1"] assert !assigns["ran_proc_filter2"] @@ -530,16 +530,16 @@ class FilterTest < ActionController::TestCase test_process(ConditionalCollectionFilterController) assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(ConditionalCollectionFilterController, "show_without_filter") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] test_process(ConditionalCollectionFilterController, "another_action") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] end def test_running_only_condition_filters test_process(OnlyConditionSymController) assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(OnlyConditionSymController, "show_without_filter") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] test_process(OnlyConditionProcController) assert assigns["ran_proc_filter"] @@ -556,7 +556,7 @@ class FilterTest < ActionController::TestCase test_process(ExceptConditionSymController) assert_equal %w( ensure_login ), assigns["ran_filter"] test_process(ExceptConditionSymController, "show_without_filter") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] test_process(ExceptConditionProcController) assert assigns["ran_proc_filter"] @@ -573,7 +573,7 @@ class FilterTest < ActionController::TestCase test_process(BeforeAndAfterConditionController) assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"] test_process(BeforeAndAfterConditionController, "show_without_filter") - assert_equal nil, assigns["ran_filter"] + assert_nil assigns["ran_filter"] end def test_around_filter @@ -674,7 +674,7 @@ class FilterTest < ActionController::TestCase def test_changing_the_requirements test_process(ChangingTheRequirementsController, "go_wild") - assert_equal nil, assigns['ran_filter'] + assert_nil assigns['ran_filter'] end def test_a_rescuing_around_filter diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb index df4b39a103..8a06e8d2a0 100644 --- a/actionpack/test/controller/new_base/bare_metal_test.rb +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -18,10 +18,10 @@ module BareMetalTest string << part end - assert headers.is_a?(Hash), "Headers must be a Hash" + assert_kind_of Hash, headers, "Headers must be a Hash" assert headers["Content-Type"], "Content-Type must exist" assert_equal "Hello world", string end end -end \ No newline at end of file +end diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index 5659dcbc48..c60caf90d7 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -31,7 +31,7 @@ class AttributeMethodsTest < ActiveModel::TestCase ModelWithAttributes.define_attribute_methods([:foo]) assert ModelWithAttributes.attribute_methods_generated? - assert ModelWithAttributes.new.respond_to?(:foo) + assert_respond_to ModelWithAttributes.new, :foo assert_equal "value of foo", ModelWithAttributes.new.foo end diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb index b996f51d6b..9675b5d450 100644 --- a/activemodel/test/cases/callbacks_test.rb +++ b/activemodel/test/cases/callbacks_test.rb @@ -65,6 +65,6 @@ class CallbacksTest < ActiveModel::TestCase test "only selects which types of callbacks should be created" do assert !ModelCallbacks.respond_to?(:before_initialize) assert !ModelCallbacks.respond_to?(:around_initialize) - assert ModelCallbacks.respond_to?(:after_initialize) + assert_respond_to ModelCallbacks, :after_initialize end end diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb index c910cb43d4..e1a35be384 100644 --- a/activemodel/test/cases/dirty_test.rb +++ b/activemodel/test/cases/dirty_test.rb @@ -22,8 +22,8 @@ class DirtyTest < ActiveModel::TestCase test "changes accessible through both strings and symbols" do model = DirtyModel.new model.name = "David" - assert !model.changes[:name].nil? - assert !model.changes['name'].nil? + assert_not_nil model.changes[:name] + assert_not_nil model.changes['name'] end end diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb index 4e8e4efa25..7b9ef3e21f 100644 --- a/activemodel/test/cases/serializeration/xml_serialization_test.rb +++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb @@ -69,7 +69,7 @@ class XmlSerializationTest < ActiveModel::TestCase test "should allow skipped types" do @xml = @contact.to_xml :skip_types => true - assert %r{25}.match(@xml) + assert_match %r{25}, @xml end test "should include yielded additions" do diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 8b6ec04018..e5fc1a2046 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -58,36 +58,36 @@ class AggregationsTest < ActiveRecord::TestCase end def test_gps_equality - assert GpsLocation.new('39x110') == GpsLocation.new('39x110') + assert_equal GpsLocation.new('39x110'), GpsLocation.new('39x110') end def test_gps_inequality - assert GpsLocation.new('39x110') != GpsLocation.new('39x111') + assert_not_equal GpsLocation.new('39x110'), GpsLocation.new('39x111') end def test_allow_nil_gps_is_nil - assert_equal nil, customers(:zaphod).gps_location + assert_nil customers(:zaphod).gps_location end def test_allow_nil_gps_set_to_nil customers(:david).gps_location = nil customers(:david).save customers(:david).reload - assert_equal nil, customers(:david).gps_location + assert_nil customers(:david).gps_location end def test_allow_nil_set_address_attributes_to_nil customers(:zaphod).address = nil - assert_equal nil, customers(:zaphod).attributes[:address_street] - assert_equal nil, customers(:zaphod).attributes[:address_city] - assert_equal nil, customers(:zaphod).attributes[:address_country] + assert_nil customers(:zaphod).attributes[:address_street] + assert_nil customers(:zaphod).attributes[:address_city] + assert_nil customers(:zaphod).attributes[:address_country] end def test_allow_nil_address_set_to_nil customers(:zaphod).address = nil customers(:zaphod).save customers(:zaphod).reload - assert_equal nil, customers(:zaphod).address + assert_nil customers(:zaphod).address end def test_nil_raises_error_when_allow_nil_is_false @@ -104,9 +104,9 @@ class AggregationsTest < ActiveRecord::TestCase def test_nil_assignment_results_in_nil customers(:david).gps_location = GpsLocation.new('39x111') - assert_not_equal nil, customers(:david).gps_location + assert_not_nil customers(:david).gps_location customers(:david).gps_location = nil - assert_equal nil, customers(:david).gps_location + assert_nil customers(:david).gps_location end def test_custom_constructor diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index be77ee4bf3..9258c987ef 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -403,7 +403,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal saved_member.id, sponsor.sponsorable_id sponsor.sponsorable = new_member - assert_equal nil, sponsor.sponsorable_id + assert_nil sponsor.sponsorable_id end def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records @@ -415,7 +415,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal saved_writer.name, essay.writer_id essay.writer = new_writer - assert_equal nil, essay.writer_id + assert_nil essay.writer_id end def test_belongs_to_proxy_should_not_respond_to_private_methods diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index 7c470616a5..b124a2bfc3 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -29,7 +29,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase ActiveRecord::Base.store_full_sti_class = true post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) - assert_equal 'Tagging', post.tagging.class.name + assert_instance_of Tagging, post.tagging ensure ActiveRecord::Base.store_full_sti_class = old end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 79e5ecf4ce..445e6889c0 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -110,7 +110,7 @@ class EagerAssociationTest < ActiveRecord::TestCase author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments author.posts_with_comments.each do |post_with_comments| assert_equal post_with_comments.comments.length, post_with_comments.comments.count - assert_equal nil, post_with_comments.comments.uniq! + assert_nil post_with_comments.comments.uniq! end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 6e47967696..8e5bc56008 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -175,14 +175,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase c = Client.new assert_nil c.firm - if c.firm - assert false, "belongs_to failed if check" - end - - unless c.firm - else - assert false, "belongs_to failed unless check" - end + flunk "belongs_to failed if check" if c.firm end def test_find_ids @@ -620,7 +613,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], Client.destroyed_client_ids[firm.id] # Should be destroyed since the association is exclusively dependent. - assert Client.find_by_id(client_id).nil? + assert_nil Client.find_by_id(client_id) end def test_dependent_association_respects_optional_conditions_on_delete @@ -669,7 +662,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase old_record = firm.clients_using_primary_key_with_delete_all.first firm = Firm.find(:first) firm.destroy - assert Client.find_by_id(old_record.id).nil? + assert_nil Client.find_by_id(old_record.id) end def test_creation_respects_hash_condition diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index ff799191c2..e4dd810732 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -63,8 +63,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_queries(1) { posts(:thinking) } assert_queries(0) do - posts(:thinking).people.build(:first_name=>"Bob") - posts(:thinking).people.new(:first_name=>"Ted") + posts(:thinking).people.build(:first_name => "Bob") + posts(:thinking).people.new(:first_name => "Ted") end # Should only need to load the association once diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 8f5540950e..469a21b9bf 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -149,7 +149,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase num_accounts = Account.count firm = Firm.find(1) - assert !firm.account.nil? + assert_not_nil firm.account account_id = firm.account.id assert_equal [], Account.destroyed_account_ids[firm.id] @@ -162,7 +162,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase num_accounts = Account.count firm = ExclusivelyDependentFirm.find(9) - assert !firm.account.nil? + assert_not_nil firm.account account_id = firm.account.id assert_equal [], Account.destroyed_account_ids[firm.id] @@ -181,7 +181,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase firm = RestrictedFirm.new(:name => 'restrict') firm.save! account = firm.create_account(:credit_limit => 10) - assert !firm.account.nil? + assert_not_nil firm.account assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } end @@ -246,7 +246,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_dependence_with_missing_association Account.destroy_all firm = Firm.find(1) - assert firm.account.nil? + assert_nil firm.account firm.destroy end diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 1d7604f52b..34d24a2948 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -23,39 +23,39 @@ class InverseAssociationTests < ActiveRecord::TestCase def test_should_be_able_to_ask_a_reflection_if_it_has_an_inverse has_one_with_inverse_ref = Man.reflect_on_association(:face) - assert has_one_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_one_with_inverse_ref, :has_inverse? assert has_one_with_inverse_ref.has_inverse? has_many_with_inverse_ref = Man.reflect_on_association(:interests) - assert has_many_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_many_with_inverse_ref, :has_inverse? assert has_many_with_inverse_ref.has_inverse? belongs_to_with_inverse_ref = Face.reflect_on_association(:man) - assert belongs_to_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to belongs_to_with_inverse_ref, :has_inverse? assert belongs_to_with_inverse_ref.has_inverse? has_one_without_inverse_ref = Club.reflect_on_association(:sponsor) - assert has_one_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_one_without_inverse_ref, :has_inverse? assert !has_one_without_inverse_ref.has_inverse? has_many_without_inverse_ref = Club.reflect_on_association(:memberships) - assert has_many_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_many_without_inverse_ref, :has_inverse? assert !has_many_without_inverse_ref.has_inverse? belongs_to_without_inverse_ref = Sponsor.reflect_on_association(:sponsor_club) - assert belongs_to_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to belongs_to_without_inverse_ref, :has_inverse? assert !belongs_to_without_inverse_ref.has_inverse? end def test_should_be_able_to_ask_a_reflection_what_it_is_the_inverse_of has_one_ref = Man.reflect_on_association(:face) - assert has_one_ref.respond_to?(:inverse_of) + assert_respond_to has_one_ref, :inverse_of has_many_ref = Man.reflect_on_association(:interests) - assert has_many_ref.respond_to?(:inverse_of) + assert_respond_to has_many_ref, :inverse_of belongs_to_ref = Face.reflect_on_association(:man) - assert belongs_to_ref.respond_to?(:inverse_of) + assert_respond_to belongs_to_ref, :inverse_of end def test_inverse_of_method_should_supply_the_actual_reflection_instance_it_is_the_inverse_of diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index dca72be4fd..447fe4d275 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -280,12 +280,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_find_conditions assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'") - assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'") + assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'") end def test_has_many_class_methods_called_by_method_missing assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first - assert_equal nil, authors(:david).categories.find_by_name('Technology') + assert_nil authors(:david).categories.find_by_name('Technology') end def test_has_many_array_methods_called_by_method_missing diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 055590da0a..d59fa0a632 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -310,7 +310,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end assert !@target.instance_method_already_implemented?(:title) topic = @target.new - assert_equal nil, topic.title + assert_nil topic.title Object.send(:undef_method, :title) # remove test method from object end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 5cc5dff633..063f0f0fb2 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1236,11 +1236,11 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for has_many associations" do - assert @pirate.respond_to?(:validate_associated_records_for_birds) + assert_respond_to @pirate, :validate_associated_records_for_birds end test "should generate validation methods for has_one associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_ship) + assert_respond_to @pirate, :validate_associated_records_for_ship end test "should not generate validation methods for has_one associations without :validate => true" do @@ -1248,7 +1248,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for belongs_to associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_parrot) + assert_respond_to @pirate, :validate_associated_records_for_parrot end test "should not generate validation methods for belongs_to associations without :validate => true" do @@ -1256,7 +1256,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for HABTM associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_parrots) + assert_respond_to @pirate, :validate_associated_records_for_parrots end test "should not generate validation methods for HABTM associations without :validate => true" do diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 7c4d92f3f8..0c7723c0e6 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -111,14 +111,14 @@ class BasicsTest < ActiveRecord::TestCase def test_respond_to? topic = Topic.find(1) - assert topic.respond_to?("title") - assert topic.respond_to?("title?") - assert topic.respond_to?("title=") - assert topic.respond_to?(:title) - assert topic.respond_to?(:title?) - assert topic.respond_to?(:title=) - assert topic.respond_to?("author_name") - assert topic.respond_to?("attribute_names") + assert_respond_to topic, "title" + assert_respond_to topic, "title?" + assert_respond_to topic, "title=" + assert_respond_to topic, :title + assert_respond_to topic, :title? + assert_respond_to topic, :title= + assert_respond_to topic, "author_name" + assert_respond_to topic, "attribute_names" assert !topic.respond_to?("nothingness") assert !topic.respond_to?(:nothingness) end @@ -1038,9 +1038,9 @@ class BasicsTest < ActiveRecord::TestCase def test_mass_assignment_protection_against_class_attribute_writers [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method| - assert Task.respond_to?(method) - assert Task.respond_to?("#{method}=") - assert Task.new.respond_to?(method) + assert_respond_to Task, method + assert_respond_to Task, "#{method}=" + assert_respond_to Task.new, method assert !Task.new.respond_to?("#{method}=") end end @@ -1369,37 +1369,37 @@ class BasicsTest < ActiveRecord::TestCase end def test_new_record_returns_boolean - assert_equal Topic.new.new_record?, true - assert_equal Topic.find(1).new_record?, false + assert_equal true, Topic.new.new_record? + assert_equal false, Topic.find(1).new_record? end def test_destroyed_returns_boolean developer = Developer.first - assert_equal developer.destroyed?, false + assert_equal false, developer.destroyed? developer.destroy - assert_equal developer.destroyed?, true + assert_equal true, developer.destroyed? developer = Developer.last - assert_equal developer.destroyed?, false + assert_equal false, developer.destroyed? developer.delete - assert_equal developer.destroyed?, true + assert_equal true, developer.destroyed? end def test_persisted_returns_boolean developer = Developer.new(:name => "Jose") - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? developer.save! - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer = Developer.first - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer.destroy - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? developer = Developer.last - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer.delete - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? end def test_clone @@ -1427,7 +1427,7 @@ class BasicsTest < ActiveRecord::TestCase # test if saved clone object differs from original cloned_topic.save assert !cloned_topic.new_record? - assert cloned_topic.id != topic.id + assert_not_equal cloned_topic.id, topic.id end def test_clone_with_aggregate_of_same_name_as_attribute @@ -1447,7 +1447,7 @@ class BasicsTest < ActiveRecord::TestCase assert clone.save assert !clone.new_record? - assert clone.id != dev.id + assert_not_equal clone.id, dev.id end def test_clone_preserves_subtype diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 8b6c019d50..b5767344cd 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -71,17 +71,17 @@ class ColumnDefinitionTest < ActiveRecord::TestCase if current_adapter?(:PostgreSQLAdapter) def test_bigint_column_should_map_to_integer bigint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "bigint") - assert_equal bigint_column.type, :integer + assert_equal :integer, bigint_column.type end def test_smallint_column_should_map_to_integer smallint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "smallint") - assert_equal smallint_column.type, :integer + assert_equal :integer, smallint_column.type end def test_uuid_column_should_map_to_string uuid_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('unique_id', nil, "uuid") - assert_equal uuid_column.type, :string + assert_equal :string, uuid_column.type end end end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index bba216ae19..39aafa1ec7 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -67,8 +67,8 @@ if current_adapter?(:MysqlAdapter) assert_equal '', klass.columns_hash['non_null_blob'].default assert_equal '', klass.columns_hash['non_null_text'].default - assert_equal nil, klass.columns_hash['null_blob'].default - assert_equal nil, klass.columns_hash['null_text'].default + assert_nil klass.columns_hash['null_blob'].default + assert_nil klass.columns_hash['null_text'].default assert_nothing_raised do instance = klass.create! diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 3ea2948f62..75f7453aa9 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -103,7 +103,7 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.created_on_changed? # kind_of does not work because # ActiveSupport::TimeWithZone.name == 'Time' - assert_equal Time, pirate.created_on_was.class + assert_instance_of Time, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was end end @@ -132,7 +132,7 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.created_on_changed? # kind_of does not work because # ActiveSupport::TimeWithZone.name == 'Time' - assert_equal Time, pirate.created_on_was.class + assert_instance_of Time, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was end diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index 4e6fecf11a..235805a67c 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -7,53 +7,53 @@ class FinderRespondToTest < ActiveRecord::TestCase def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { } - assert Topic.respond_to?(:method_added_for_finder_respond_to_test) + assert_respond_to Topic, :method_added_for_finder_respond_to_test ensure class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test) end def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method - assert Topic.respond_to?(:to_s) + assert_respond_to Topic, :to_s end def test_should_respond_to_find_by_one_attribute_before_caching ensure_topic_method_is_not_cached(:find_by_title) - assert Topic.respond_to?(:find_by_title) + assert_respond_to Topic, :find_by_title end def test_should_respond_to_find_all_by_one_attribute ensure_topic_method_is_not_cached(:find_all_by_title) - assert Topic.respond_to?(:find_all_by_title) + assert_respond_to Topic, :find_all_by_title end def test_should_respond_to_find_all_by_two_attributes ensure_topic_method_is_not_cached(:find_all_by_title_and_author_name) - assert Topic.respond_to?(:find_all_by_title_and_author_name) + assert_respond_to Topic, :find_all_by_title_and_author_name end def test_should_respond_to_find_by_two_attributes ensure_topic_method_is_not_cached(:find_by_title_and_author_name) - assert Topic.respond_to?(:find_by_title_and_author_name) + assert_respond_to Topic, :find_by_title_and_author_name end def test_should_respond_to_find_or_initialize_from_one_attribute ensure_topic_method_is_not_cached(:find_or_initialize_by_title) - assert Topic.respond_to?(:find_or_initialize_by_title) + assert_respond_to Topic, :find_or_initialize_by_title end def test_should_respond_to_find_or_initialize_from_two_attributes ensure_topic_method_is_not_cached(:find_or_initialize_by_title_and_author_name) - assert Topic.respond_to?(:find_or_initialize_by_title_and_author_name) + assert_respond_to Topic, :find_or_initialize_by_title_and_author_name end def test_should_respond_to_find_or_create_from_one_attribute ensure_topic_method_is_not_cached(:find_or_create_by_title) - assert Topic.respond_to?(:find_or_create_by_title) + assert_respond_to Topic, :find_or_create_by_title end def test_should_respond_to_find_or_create_from_two_attributes ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name) - assert Topic.respond_to?(:find_or_create_by_title_and_author_name) + assert_respond_to Topic, :find_or_create_by_title_and_author_name end def test_should_not_respond_to_find_by_one_missing_attribute @@ -73,4 +73,4 @@ class FinderRespondToTest < ActiveRecord::TestCase class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.any? { |m| m.to_s == method_id.to_s } end -end \ No newline at end of file +end -- cgit v1.2.3 From 59c7b0c23a58b2499c911d8907ecd936b73b0172 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 May 2010 18:19:49 -0300 Subject: Avoid instance variable @output_buffer not initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_view/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 4ac2ee52d6..735398d972 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -201,7 +201,7 @@ module ActionView #:nodoc: end def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc: - @config = nil + @config = nil @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @helpers = self.class.helpers || Module.new @@ -212,6 +212,7 @@ module ActionView #:nodoc: @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller && controller.respond_to?(:config) @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new } @_virtual_path = nil + @output_buffer = nil @lookup_context = lookup_context.is_a?(ActionView::LookupContext) ? lookup_context : ActionView::LookupContext.new(lookup_context) -- cgit v1.2.3 From 715f7c0b7c27a0fc4a6ec1619a0e4ccdce4fe85f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 May 2010 22:14:51 -0300 Subject: Fixes a test on transaction_callbacks_test.rb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/test/cases/transaction_callbacks_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 7469cdb299..ebc16653cb 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -202,8 +202,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end def @first.commits(i=0); @commits ||= 0; @commits += i if i; end - @second.after_rollback_block{|r| r.rollbacks(1)} - @second.after_commit_block{|r| r.commits(1)} + @first.after_rollback_block{|r| r.rollbacks(1)} + @first.after_commit_block{|r| r.commits(1)} Topic.transaction do @first.save -- cgit v1.2.3 From 5573ab2047b07c3de08d40566de8a8fc80a676cf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 18 May 2010 22:15:28 -0300 Subject: Enable ruby-debug only for MRI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index e94afc828e..1d0f0f7c58 100644 --- a/Gemfile +++ b/Gemfile @@ -11,10 +11,10 @@ group :mri do gem 'yajl-ruby' gem "nokogiri", ">= 1.4.0" - if RUBY_VERSION < '1.9' + if !defined?(RUBY_ENGINE) && RUBY_VERSION < '1.9' gem "system_timer" gem "ruby-debug", ">= 0.10.3" - elsif RUBY_VERSION < '1.9.2' && !ENV['CI'] + elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION < '1.9.2' && !ENV['CI'] gem "ruby-debug19" end end -- cgit v1.2.3 From bdb2871df7fb0a1eeceadb31aaba4d160df508aa Mon Sep 17 00:00:00 2001 From: Anil Wadghule Date: Wed, 19 May 2010 16:25:21 +0530 Subject: Fix xml serialization test [#4650 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activemodel/test/cases/serializeration/xml_serialization_test.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb index 7b9ef3e21f..ff786658b7 100644 --- a/activemodel/test/cases/serializeration/xml_serialization_test.rb +++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb @@ -17,6 +17,9 @@ module Admin end end +class Customer < Struct.new(:name) +end + class XmlSerializationTest < ActiveModel::TestCase def setup @contact = Contact.new @@ -24,7 +27,7 @@ class XmlSerializationTest < ActiveModel::TestCase @contact.age = 25 @contact.created_at = Time.utc(2006, 8, 1) @contact.awesome = false - customer = OpenStruct.new + customer = Customer.new customer.name = "John" @contact.preferences = customer end @@ -104,7 +107,7 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should serialize yaml" do - assert_match %r{--- !ruby/object:OpenStruct \ntable:\s*:name: John\n}, @contact.to_xml + assert_match %r{--- !ruby/struct:Customer \nname: John\n}, @contact.to_xml end test "should call proc on object" do -- cgit v1.2.3 From 39a246f545a714b21c669e2f6eda4012526c3874 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 19 May 2010 15:14:51 -0400 Subject: Final iteration of use better testing methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#4652 state:resolved] Signed-off-by: José Valim --- activerecord/test/cases/finder_test.rb | 2 +- activerecord/test/cases/inheritance_test.rb | 14 +++++++------- activerecord/test/cases/method_scoping_test.rb | 2 +- activerecord/test/cases/migration_test.rb | 2 +- activerecord/test/cases/pk_test.rb | 4 ++-- activerecord/test/cases/query_cache_test.rb | 2 +- activerecord/test/cases/relations_test.rb | 6 +++--- activerecord/test/cases/reserved_word_test_mysql.rb | 2 +- activerecord/test/cases/timestamp_test.rb | 16 ++++++++-------- activeresource/test/cases/base/schema_test.rb | 12 ++++++------ activeresource/test/cases/base_test.rb | 10 +++++----- activesupport/test/callbacks_test.rb | 2 +- .../test/core_ext/class/attribute_accessor_test.rb | 8 ++++---- .../core_ext/class/class_inheritable_attributes_test.rb | 4 ++-- .../test/core_ext/class/delegating_attributes_test.rb | 8 ++++---- activesupport/test/core_ext/date_time_ext_test.rb | 4 ++-- activesupport/test/core_ext/duration_test.rb | 4 ++-- .../test/core_ext/module/attribute_accessor_test.rb | 8 ++++---- .../test/core_ext/module/synchronization_test.rb | 6 +++--- activesupport/test/core_ext/module_test.rb | 10 +++++----- activesupport/test/core_ext/string_ext_test.rb | 14 +++++++------- activesupport/test/core_ext/time_with_zone_test.rb | 12 ++++++------ activesupport/test/multibyte_chars_test.rb | 6 +++--- activesupport/test/time_zone_test.rb | 2 +- railties/test/application/rackup_test.rb | 4 ++-- 25 files changed, 82 insertions(+), 82 deletions(-) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index c73ad50a71..860d330a7f 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -255,7 +255,7 @@ class FinderTest < ActiveRecord::TestCase assert !topic.attribute_present?("title") #assert !topic.respond_to?("title") assert topic.attribute_present?("author_name") - assert topic.respond_to?("author_name") + assert_respond_to topic, "author_name" end def test_find_on_blank_conditions diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 0672fb938b..c1c8f01e46 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -72,10 +72,10 @@ class InheritanceTest < ActiveRecord::TestCase end def test_inheritance_find - assert Company.find(1).kind_of?(Firm), "37signals should be a firm" - assert Firm.find(1).kind_of?(Firm), "37signals should be a firm" - assert Company.find(2).kind_of?(Client), "Summit should be a client" - assert Client.find(2).kind_of?(Client), "Summit should be a client" + assert_kind_of Firm, Company.find(1), "37signals should be a firm" + assert_kind_of Firm, Firm.find(1), "37signals should be a firm" + assert_kind_of Client, Company.find(2), "Summit should be a client" + assert_kind_of Client, Client.find(2), "Summit should be a client" end def test_alt_inheritance_find @@ -86,8 +86,8 @@ class InheritanceTest < ActiveRecord::TestCase def test_inheritance_find_all companies = Company.find(:all, :order => 'id') - assert companies[0].kind_of?(Firm), "37signals should be a firm" - assert companies[1].kind_of?(Client), "Summit should be a client" + assert_kind_of Firm, companies[0], "37signals should be a firm" + assert_kind_of Client, companies[1], "Summit should be a client" end def test_alt_inheritance_find_all @@ -102,7 +102,7 @@ class InheritanceTest < ActiveRecord::TestCase firm.save next_angle = Company.find(firm.id) - assert next_angle.kind_of?(Firm), "Next Angle should be a firm" + assert_kind_of Firm, next_angle, "Next Angle should be a firm" end def test_alt_inheritance_save diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index cb599e363f..e93f22bede 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -622,7 +622,7 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal ['salary DESC'], klass.scoped.order_values # Parent should still have the original scope - assert_equal nil, DeveloperOrderedBySalary.scoped.limit_value + assert_nil DeveloperOrderedBySalary.scoped.limit_value assert_equal ['salary DESC'], DeveloperOrderedBySalary.scoped.order_values end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 692e4b207f..b5fa258f7b 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -525,7 +525,7 @@ if ActiveRecord::Base.connection.supports_migrations? end end - assert_equal TrueClass, bob.male?.class + assert_instance_of TrueClass, bob.male? assert_kind_of BigDecimal, bob.wealth end diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb index 33ad5992de..73f4b3848c 100644 --- a/activerecord/test/cases/pk_test.rb +++ b/activerecord/test/cases/pk_test.rb @@ -18,7 +18,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_to_key_with_customized_primary_key keyboard = Keyboard.new - assert keyboard.to_key.nil? + assert_nil keyboard.to_key keyboard.save assert_equal keyboard.to_key, [keyboard.id] end @@ -37,7 +37,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase topic = Topic.new topic.title = "New Topic" - assert_equal(nil, topic.id) + assert_nil topic.id assert_nothing_raised { topic.save! } id = topic.id diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 91349689bc..68abca70b3 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -58,7 +58,7 @@ class QueryCacheTest < ActiveRecord::TestCase Task.cache do # Oracle adapter returns count() as Fixnum or Float if current_adapter?(:OracleAdapter) - assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric) + assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") elsif current_adapter?(:SQLite3Adapter) && SQLite3::Version::VERSION > '1.2.5' # Future versions of the sqlite3 adapter will return numeric assert_instance_of Fixnum, diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 7b9e680c02..b6815af67e 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -145,7 +145,7 @@ class RelationTest < ActiveRecord::TestCase relation = Topic.scoped ["map", "uniq", "sort", "insert", "delete", "update"].each do |method| - assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}" + assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}" end end @@ -160,7 +160,7 @@ class RelationTest < ActiveRecord::TestCase relation = Topic.scoped ["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method| - assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}" + assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}" end end @@ -238,7 +238,7 @@ class RelationTest < ActiveRecord::TestCase def test_default_scope_with_conditions_string assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort - assert_equal nil, DeveloperCalledDavid.create!.name + assert_nil DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash diff --git a/activerecord/test/cases/reserved_word_test_mysql.rb b/activerecord/test/cases/reserved_word_test_mysql.rb index ce1622bb20..90d8b0d923 100644 --- a/activerecord/test/cases/reserved_word_test_mysql.rb +++ b/activerecord/test/cases/reserved_word_test_mysql.rb @@ -115,7 +115,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase create_test_fixtures :select, :distinct, :group, :values, :distincts_selects v = nil assert_nothing_raised { v = Group.find(1).values } - assert_equal v.id, 2 + assert_equal 2, v.id end # belongs_to association with reserved-word table name diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index 24b237a72b..549c4af6b1 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -15,26 +15,26 @@ class TimestampTest < ActiveRecord::TestCase @developer.name = "Jack Bauer" @developer.save! - assert @previously_updated_at != @developer.updated_at + assert_not_equal @previously_updated_at, @developer.updated_at end def test_saving_a_unchanged_record_doesnt_update_its_timestamp @developer.save! - assert @previously_updated_at == @developer.updated_at + assert_equal @previously_updated_at, @developer.updated_at end def test_touching_a_record_updates_its_timestamp @developer.touch - assert @previously_updated_at != @developer.updated_at + assert_not_equal @previously_updated_at, @developer.updated_at end def test_touching_a_different_attribute previously_created_at = @developer.created_at @developer.touch(:created_at) - assert previously_created_at != @developer.created_at + assert_not_equal previously_created_at, @developer.created_at end def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at @@ -45,7 +45,7 @@ class TimestampTest < ActiveRecord::TestCase pet.name = "Fluffy the Third" pet.save - assert previously_owner_updated_at != pet.owner.updated_at + assert_not_equal previously_owner_updated_at, pet.owner.updated_at end def test_destroying_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at @@ -55,7 +55,7 @@ class TimestampTest < ActiveRecord::TestCase pet.destroy - assert previously_owner_updated_at != pet.owner.updated_at + assert_not_equal previously_owner_updated_at, pet.owner.updated_at end def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute @@ -68,8 +68,8 @@ class TimestampTest < ActiveRecord::TestCase pet.name = "Fluffy the Third" pet.save - assert previously_owner_happy_at != pet.owner.happy_at + assert_not_equal previously_owner_happy_at, pet.owner.happy_at ensure Pet.belongs_to :owner, :touch => true end -end \ No newline at end of file +end diff --git a/activeresource/test/cases/base/schema_test.rb b/activeresource/test/cases/base/schema_test.rb index d9dc679941..136c827926 100644 --- a/activeresource/test/cases/base/schema_test.rb +++ b/activeresource/test/cases/base/schema_test.rb @@ -185,7 +185,7 @@ class SchemaTest < ActiveModel::TestCase #### test "should be able to use schema" do - assert Person.respond_to?(:schema), "should at least respond to the schema method" + assert_respond_to Person, :schema, "should at least respond to the schema method" assert_nothing_raised("Should allow the schema to take a block") do Person.schema { } @@ -199,7 +199,7 @@ class SchemaTest < ActiveModel::TestCase s = self attribute :foo, :string end - assert s.respond_to?(:attrs), "should return attributes in theory" + assert_respond_to s, :attrs, "should return attributes in theory" assert_equal({'foo' => 'string' }, s.attrs, "should return attributes in practice") end end @@ -308,8 +308,8 @@ class SchemaTest < ActiveModel::TestCase Person.schema { string new_attr_name_two } end - assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}" - assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}" + assert_respond_to Person.new, new_attr_name, "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}" + assert_respond_to Person.new, new_attr_name_two, "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}" end test "should not care about ordering of schema definitions" do @@ -326,8 +326,8 @@ class SchemaTest < ActiveModel::TestCase Person.schema = {new_attr_name.to_s => 'string'} end - assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}" - assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}" + assert_respond_to Person.new, new_attr_name, "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}" + assert_respond_to Person.new, new_attr_name_two, "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}" end # method_missing effects diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index daf58613c0..d5ee7659af 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -671,9 +671,9 @@ class BaseTest < Test::Unit::TestCase ######################################################################## def test_respond_to matz = Person.find(1) - assert matz.respond_to?(:name) - assert matz.respond_to?(:name=) - assert matz.respond_to?(:name?) + assert_respond_to matz, :name + assert_respond_to matz, :name= + assert_respond_to matz, :name? assert !matz.respond_to?(:super_scalable_stuff) end @@ -708,7 +708,7 @@ class BaseTest < Test::Unit::TestCase def test_id_from_response_without_location p = Person.new resp = {} - assert_equal nil, p.__send__(:id_from_response, resp) + assert_nil p.__send__(:id_from_response, resp) end def test_create_with_custom_prefix @@ -775,7 +775,7 @@ class BaseTest < Test::Unit::TestCase mock.post "/people.xml", {}, nil, 201 end person = Person.create(:name => 'Rick') - assert_equal nil, person.id + assert_nil person.id end def test_clone diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 49d9de63b0..70a2950f9b 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -521,7 +521,7 @@ module CallbacksTest def test_save obj = HyphenatedCallbacks.new obj.save - assert_equal obj.stuff, "ACTION" + assert_equal "ACTION", obj.stuff end end end diff --git a/activesupport/test/core_ext/class/attribute_accessor_test.rb b/activesupport/test/core_ext/class/attribute_accessor_test.rb index 0f579d12e5..2c896d0cdb 100644 --- a/activesupport/test/core_ext/class/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/class/attribute_accessor_test.rb @@ -25,14 +25,14 @@ class ClassAttributeAccessorTest < Test::Unit::TestCase end def test_should_not_create_instance_writer - assert @class.respond_to?(:foo) - assert @class.respond_to?(:foo=) - assert @object.respond_to?(:bar) + assert_respond_to @class, :foo + assert_respond_to @class, :foo= + assert_respond_to @object, :bar assert !@object.respond_to?(:bar=) end def test_should_not_create_instance_reader - assert @class.respond_to?(:shaq) + assert_respond_to @class, :shaq assert !@object.respond_to?(:shaq) end end diff --git a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb index eeda468d9c..63ea46b564 100644 --- a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb +++ b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb @@ -219,7 +219,7 @@ class ClassInheritableAttributesTest < Test::Unit::TestCase @klass.reset_inheritable_attributes @sub = eval("class NotInheriting < @klass; end; NotInheriting") - assert_equal nil, @klass.a - assert_equal nil, @sub.a + assert_nil @klass.a + assert_nil @sub.a end end diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb index 6d6cb61571..cbfb290c48 100644 --- a/activesupport/test/core_ext/class/delegating_attributes_test.rb +++ b/activesupport/test/core_ext/class/delegating_attributes_test.rb @@ -32,16 +32,16 @@ class DelegatingAttributesTest < Test::Unit::TestCase single_class.superclass_delegating_accessor :both # Class should have accessor and mutator # the instance should have an accessor only - assert single_class.respond_to?(:both) - assert single_class.respond_to?(:both=) + assert_respond_to single_class, :both + assert_respond_to single_class, :both= assert single_class.public_instance_methods.map(&:to_s).include?("both") assert !single_class.public_instance_methods.map(&:to_s).include?("both=") end def test_simple_accessor_declaration_with_instance_reader_false single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false - assert single_class.respond_to?(:no_instance_reader) - assert single_class.respond_to?(:no_instance_reader=) + assert_respond_to single_class, :no_instance_reader + assert_respond_to single_class, :no_instance_reader= assert !single_class.public_instance_methods.map(&:to_s).include?("no_instance_reader") end diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 4780760a19..eba8170cda 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -275,12 +275,12 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase end def test_current_without_time_zone - assert DateTime.current.is_a?(DateTime) + assert_kind_of DateTime, DateTime.current end def test_current_with_time_zone with_env_tz 'US/Eastern' do - assert DateTime.current.is_a?(DateTime) + assert_kind_of DateTime, DateTime.current end end diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 6530de1ef4..05f529dc7d 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -5,8 +5,8 @@ class DurationTest < ActiveSupport::TestCase def test_is_a d = 1.day assert d.is_a?(ActiveSupport::Duration) - assert d.is_a?(Numeric) - assert d.is_a?(Fixnum) + assert_kind_of Numeric, d + assert_kind_of Fixnum, d assert !d.is_a?(Hash) k = Class.new diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index 263e78feaa..67fcd437d0 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -27,14 +27,14 @@ class ModuleAttributeAccessorTest < Test::Unit::TestCase end def test_should_not_create_instance_writer - assert @module.respond_to?(:foo) - assert @module.respond_to?(:foo=) - assert @object.respond_to?(:bar) + assert_respond_to @module, :foo + assert_respond_to @module, :foo= + assert_respond_to @object, :bar assert !@object.respond_to?(:bar=) end def test_should_not_create_instance_reader - assert @module.respond_to?(:shaq) + assert_respond_to @module, :shaq assert !@object.respond_to?(:shaq) end end diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb index 43d65ab249..eb850893f0 100644 --- a/activesupport/test/core_ext/module/synchronization_test.rb +++ b/activesupport/test/core_ext/module/synchronization_test.rb @@ -16,8 +16,8 @@ class SynchronizationTest < Test::Unit::TestCase attr_accessor :value synchronize :value, :with => :mutex end - assert @instance.respond_to?(:value_with_synchronization) - assert @instance.respond_to?(:value_without_synchronization) + assert_respond_to @instance, :value_with_synchronization + assert_respond_to @instance, :value_without_synchronization end def test_synchronize_does_not_change_behavior @@ -81,7 +81,7 @@ class SynchronizationTest < Test::Unit::TestCase class << @target synchronize :to_s, :with => :mutex end - assert @target.respond_to?(:to_s_without_synchronization) + assert_respond_to @target, :to_s_without_synchronization assert_nothing_raised { @target.to_s; @target.to_s } assert_equal 2, @target.mutex.sync_count end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 1712b0649b..39ee0ac748 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -225,7 +225,7 @@ class MethodAliasingTest < Test::Unit::TestCase FooClassWithBarMethod.class_eval { include BarMethodAliaser } feature_aliases.each do |method| - assert @instance.respond_to?(method) + assert_respond_to @instance, method end assert_equal 'bar_with_baz', @instance.bar @@ -242,7 +242,7 @@ class MethodAliasingTest < Test::Unit::TestCase include BarMethodAliaser alias_method_chain :quux!, :baz end - assert @instance.respond_to?(:quux_with_baz!) + assert_respond_to @instance, :quux_with_baz! assert_equal 'quux_with_baz', @instance.quux! assert_equal 'quux', @instance.quux_without_baz! @@ -260,9 +260,9 @@ class MethodAliasingTest < Test::Unit::TestCase assert !@instance.respond_to?(:quux_with_baz=) FooClassWithBarMethod.class_eval { include BarMethodAliaser } - assert @instance.respond_to?(:quux_with_baz!) - assert @instance.respond_to?(:quux_with_baz?) - assert @instance.respond_to?(:quux_with_baz=) + assert_respond_to @instance, :quux_with_baz! + assert_respond_to @instance, :quux_with_baz? + assert_respond_to @instance, :quux_with_baz= FooClassWithBarMethod.alias_method_chain :quux!, :baz diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 09ce39bae2..ea21e445e2 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -117,7 +117,7 @@ class StringInflectionsTest < Test::Unit::TestCase assert_equal Time.local(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time(:local) assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time assert_equal Time.local_time(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time(:local) - assert_equal nil, "".to_time + assert_nil "".to_time end def test_string_to_datetime @@ -125,12 +125,12 @@ class StringInflectionsTest < Test::Unit::TestCase assert_equal 0, "2039-02-27 23:50".to_datetime.offset # use UTC offset assert_equal ::Date::ITALY, "2039-02-27 23:50".to_datetime.start # use Ruby's default start value assert_equal DateTime.civil(2039, 2, 27, 23, 50, 19 + Rational(275038, 1000000), "-04:00"), "2039-02-27T23:50:19.275038-04:00".to_datetime - assert_equal nil, "".to_datetime + assert_nil "".to_datetime end def test_string_to_date assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date - assert_equal nil, "".to_date + assert_nil "".to_date end def test_access @@ -224,7 +224,7 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase BYTE_STRING = "\270\236\010\210\245" def test_core_ext_adds_mb_chars - assert UNICODE_STRING.respond_to?(:mb_chars) + assert_respond_to UNICODE_STRING, :mb_chars end def test_string_should_recognize_utf8_strings @@ -236,20 +236,20 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase if RUBY_VERSION < '1.9' def test_mb_chars_returns_self_when_kcode_not_set with_kcode('none') do - assert UNICODE_STRING.mb_chars.kind_of?(String) + assert_kind_of String, UNICODE_STRING.mb_chars end end def test_mb_chars_returns_an_instance_of_the_chars_proxy_when_kcode_utf8 with_kcode('UTF8') do - assert UNICODE_STRING.mb_chars.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert_kind_of ActiveSupport::Multibyte.proxy_class, UNICODE_STRING.mb_chars end end end if RUBY_VERSION >= '1.9' def test_mb_chars_returns_string - assert UNICODE_STRING.mb_chars.kind_of?(String) + assert_kind_of String, UNICODE_STRING.mb_chars end end end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index a808a25821..77b1893f77 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -279,13 +279,13 @@ class TimeWithZoneTest < Test::Unit::TestCase def test_to_f result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_f assert_equal 946684800.0, result - assert result.is_a?(Float) + assert_kind_of Float, result end def test_to_i result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_i assert_equal 946684800, result - assert result.is_a?(Integer) + assert_kind_of Integer, result end def test_to_i_with_wrapped_datetime @@ -324,9 +324,9 @@ class TimeWithZoneTest < Test::Unit::TestCase end def test_is_a - assert @twz.is_a?(Time) - assert @twz.kind_of?(Time) - assert @twz.is_a?(ActiveSupport::TimeWithZone) + assert_kind_of Time, @twz + assert_kind_of Time, @twz + assert ActiveSupport::TimeWithZone, @twz end def test_class_name @@ -830,7 +830,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase assert_raise(TZInfo::InvalidTimezoneIdentifier) { Time.zone.utc_offset } Time.zone = -15.hours - assert_equal nil, Time.zone + assert_nil Time.zone end def test_current_returns_time_now_when_zone_default_not_set diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index caf50aa1c9..f15b1351f7 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -31,12 +31,12 @@ class MultibyteCharsTest < Test::Unit::TestCase end def test_forwarded_method_calls_should_return_new_chars_instance - assert @chars.__method_for_multibyte_testing.kind_of?(@proxy_class) + assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing assert_not_equal @chars.object_id, @chars.__method_for_multibyte_testing.object_id end def test_forwarded_bang_method_calls_should_return_the_original_chars_instance - assert @chars.__method_for_multibyte_testing!.kind_of?(@proxy_class) + assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing! assert_equal @chars.object_id, @chars.__method_for_multibyte_testing!.object_id end @@ -114,7 +114,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase if RUBY_VERSION < '1.9' def test_split_should_return_an_array_of_chars_instances @chars.split(//).each do |character| - assert character.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert_kind_of ActiveSupport::Multibyte.proxy_class, character end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 516da7a14c..620623b389 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -22,7 +22,7 @@ class TimeZoneTest < Test::Unit::TestCase ActiveSupport::TimeZone::MAPPING.keys.each do |name| define_method("test_map_#{name.downcase.gsub(/[^a-z]/, '_')}_to_tzinfo") do zone = ActiveSupport::TimeZone[name] - assert zone.tzinfo.respond_to?(:period_for_local) + assert_respond_to zone.tzinfo, :period_for_local end end diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb index f909c1b282..3790de721c 100644 --- a/railties/test/application/rackup_test.rb +++ b/railties/test/application/rackup_test.rb @@ -28,14 +28,14 @@ module ApplicationTests test "Rails.application is available after config.ru has been racked up" do rackup - assert Rails.application.is_a?(Rails::Application) + assert_kind_of Rails::Application, Rails.application end # Passenger still uses AC::Dispatcher, so we need to # keep it working for now test "deprecated ActionController::Dispatcher still works" do rackup - assert ActionController::Dispatcher.new.is_a?(Rails::Application) + assert_kind_of? Rails::Application, ActionController::Dispatcher.new end test "the config object is available on the application object" do -- cgit v1.2.3 From 61001e766de974a8864c0bc2cf915888d277a0ea Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 19 May 2010 11:24:51 -0300 Subject: group :mri deleted in favor of RUBY_ENGINE and RUBY_VERSION usage. Allow use json, yajl-ruby and nokogiri on MRI and Rubinius only. jruby-debug added only for jruby platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- Gemfile | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 1d0f0f7c58..23e76d225c 100644 --- a/Gemfile +++ b/Gemfile @@ -6,17 +6,18 @@ gem "rails", :path => File.dirname(__FILE__) gem "rake", ">= 0.8.7" gem "mocha", ">= 0.9.8" -group :mri do +mri = !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" +if mri && RUBY_VERSION < '1.9' + gem "system_timer" + gem "ruby-debug", ">= 0.10.3" +end + +if mri || RUBY_ENGINE == "rbx" gem 'json' gem 'yajl-ruby' gem "nokogiri", ">= 1.4.0" - - if !defined?(RUBY_ENGINE) && RUBY_VERSION < '1.9' - gem "system_timer" - gem "ruby-debug", ">= 0.10.3" - elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION < '1.9.2' && !ENV['CI'] - gem "ruby-debug19" - end +elsif RUBY_ENGINE == "jruby" + gem "jruby-debug" end # AR -- cgit v1.2.3