From d56984c01696348913b298bb65483534035304f0 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 13 Oct 2009 17:47:18 -0700 Subject: Make rails configuration's path object's root lazy --- railties/lib/rails/paths.rb | 11 +++++++---- railties/test/paths_test.rb | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 3899b744b0..308d067701 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -19,14 +19,15 @@ module Rails class Root include PathParent - attr_reader :path + attr_accessor :path + def initialize(path) - raise unless path.is_a?(String) + raise if path.is_a?(Array) @children = {} # TODO: Move logic from set_root_path initializer - @path = File.expand_path(path) + @path = path @root = self @all_paths = [] end @@ -123,8 +124,10 @@ module Rails end def paths + raise "You need to set a path root" unless @root.path + @paths.map do |path| - path.index('/') == 0 ? path : File.join(@root.path, path) + path.index('/') == 0 ? path : File.expand_path(File.join(@root.path, path)) end end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index d50882110f..c724799d64 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -12,11 +12,32 @@ class PathsTest < ActiveSupport::TestCase assert_equal "/fiz/baz", root.path end + test "the paths object can be initialized with nil" do + assert_nothing_raised do + Rails::Application::Root.new(nil) + end + end + + test "a paths object initialized with nil can be updated" do + root = Rails::Application::Root.new(nil) + root.app = "app" + root.path = "/root" + assert_equal ["/root/app"], root.app.to_a + end + test "creating a root level path" do @root.app = "/foo/bar" assert_equal ["/foo/bar"], @root.app.to_a end + test "raises exception if root path never set" do + root = Rails::Application::Root.new(nil) + root.app = "app" + assert_raises RuntimeError do + root.app.to_a + end + end + test "creating a root level path without assignment" do @root.app "/foo/bar" assert_equal ["/foo/bar"], @root.app.to_a -- cgit v1.2.3 From 5ffb877d3a5d7fd2266b58495de435dd9c33d4e1 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 13 Oct 2009 17:52:20 -0700 Subject: Add Gemfile to the rails application generator --- railties/lib/rails/generators/rails/app/app_generator.rb | 1 + railties/lib/rails/generators/rails/app/templates/Gemfile | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 railties/lib/rails/generators/rails/app/templates/Gemfile diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 78b4b057ae..bd7af25bd5 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -54,6 +54,7 @@ module Rails::Generators copy_file "Rakefile" copy_file "README" copy_file "config.ru" + template "Gemfile" end def create_app_files diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile new file mode 100644 index 0000000000..bcbaa432b7 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -0,0 +1,10 @@ +# Gemfile is where you list all of your application's dependencies +# +gem "rails", "<%= Rails::VERSION::STRING %>" +# +# Bundling edge rails: +# gem "rails", "<%= Rails::VERSION::STRING %>", :git => "git://github.com/rails/rails.git" + +# You can list more dependencies here +# gem "nokogiri" +# gem "merb" # ;) \ No newline at end of file -- cgit v1.2.3 From ff8be66f249d49e82c8e1d04cb8cfbbc128deabe Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 8 Oct 2009 18:12:28 -0700 Subject: Finish porting over the initializers to the app object and fix all the tests --- .../lib/active_support/testing/isolation.rb | 2 - railties/Rakefile | 1 + railties/lib/rails/configuration.rb | 173 ++++++++++----------- railties/test/application/configuration_test.rb | 17 ++ railties/test/application/generators_test.rb | 2 +- railties/test/generators/generators_test_helper.rb | 9 +- 6 files changed, 109 insertions(+), 95 deletions(-) create mode 100644 railties/test/application/configuration_test.rb diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index bec303f6ab..c75b59c284 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/load_error' - module ActiveSupport module Testing class ProxyTestResult diff --git a/railties/Rakefile b/railties/Rakefile index 23f9603b65..0ba5ca10c2 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -28,6 +28,7 @@ task :default => :test task :test do dir = ENV["TEST_DIR"] || "**" Dir["test/#{dir}/*_test.rb"].all? do |file| + next true if file.include?("fixtures") ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) system(ruby, '-Itest', "-I#{File.dirname(__FILE__)}/../activesupport/lib", file) end or raise "Failures" diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 4a70a4800e..b5ac0e3ddc 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,6 +1,9 @@ +require 'rails/plugin/loader' +require 'rails/plugin/locator' + module Rails class Configuration - attr_accessor :cache_classes, :load_paths, :eager_load_paths, :framework_paths, + attr_accessor :cache_classes, :load_paths, :load_once_paths, :gems_dependencies_loaded, :after_initialize_blocks, :frameworks, :framework_root_path, :root_path, :plugin_paths, :plugins, :plugin_loader, :plugin_locators, :gems, :loaded_plugins, :reload_plugins, @@ -15,29 +18,13 @@ module Rails def initialize set_root_path! - @framework_paths = [] @load_once_paths = [] @after_initialize_blocks = [] @loaded_plugins = [] @dependency_loading = true - @eager_load_paths = default_eager_load_paths - @load_paths = default_load_paths - @plugin_paths = default_plugin_paths - @frameworks = default_frameworks - @plugin_loader = default_plugin_loader - @plugin_locators = default_plugin_locators - @gems = default_gems - @i18n = default_i18n - @log_path = default_log_path - @log_level = default_log_level - @cache_store = default_cache_store - @view_path = default_view_path - @controller_paths = default_controller_paths - @routes_configuration_file = default_routes_configuration_file - @database_configuration_file = default_database_configuration_file - @serve_static_assets = default_serve_static_assets - - for framework in default_frameworks + @serve_static_assets = true + + for framework in frameworks self.send("#{framework}=", Rails::OrderedOptions.new) end self.active_support = Rails::OrderedOptions.new @@ -121,34 +108,38 @@ module Rails YAML::load(ERB.new(IO.read(database_configuration_file)).result) end - def default_routes_configuration_file - File.join(root_path, 'config', 'routes.rb') + def routes_configuration_file + @routes_configuration_file ||= File.join(root_path, 'config', 'routes.rb') end - def default_controller_paths - paths = [File.join(root_path, 'app', 'controllers')] - paths.concat builtin_directories - paths + def controller_paths + @controller_paths ||= begin + paths = [File.join(root_path, 'app', 'controllers')] + paths.concat builtin_directories + paths + end end - def default_cache_store - if File.exist?("#{root_path}/tmp/cache/") - [ :file_store, "#{root_path}/tmp/cache/" ] - else - :memory_store + def cache_store + @cache_store ||= begin + if File.exist?("#{root_path}/tmp/cache/") + [ :file_store, "#{root_path}/tmp/cache/" ] + else + :memory_store + end end end - def default_database_configuration_file - File.join(root_path, 'config', 'database.yml') + def database_configuration_file + @database_configuration_file ||= File.join(root_path, 'config', 'database.yml') end - def default_view_path - File.join(root_path, 'app', 'views') + def view_path + @view_path ||= File.join(root_path, 'app', 'views') end - def default_eager_load_paths - %w( + def eager_load_paths + @eager_load_paths ||= %w( app/metal app/models app/controllers @@ -156,28 +147,30 @@ module Rails ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } end - def default_load_paths - paths = [] - - # Add the old mock paths only if the directories exists - paths.concat(Dir["#{root_path}/test/mocks/#{RAILS_ENV}"]) if File.exists?("#{root_path}/test/mocks/#{RAILS_ENV}") - - # Add the app's controller directory - paths.concat(Dir["#{root_path}/app/controllers/"]) - - # Followed by the standard includes. - paths.concat %w( - app - app/metal - app/models - app/controllers - app/helpers - app/services - lib - vendor - ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } - - paths.concat builtin_directories + def load_paths + @load_paths ||= begin + paths = [] + + # Add the old mock paths only if the directories exists + paths.concat(Dir["#{root_path}/test/mocks/#{RAILS_ENV}"]) if File.exists?("#{root_path}/test/mocks/#{RAILS_ENV}") + + # Add the app's controller directory + paths.concat(Dir["#{root_path}/app/controllers/"]) + + # Followed by the standard includes. + paths.concat %w( + app + app/metal + app/models + app/controllers + app/helpers + app/services + lib + vendor + ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } + + paths.concat builtin_directories + end end def builtin_directories @@ -185,48 +178,48 @@ module Rails (RAILS_ENV == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : [] end - def default_log_path - File.join(root_path, 'log', "#{RAILS_ENV}.log") + def log_path + @log_path ||= File.join(root_path, 'log', "#{RAILS_ENV}.log") end - def default_log_level - RAILS_ENV == 'production' ? :info : :debug + def log_level + @log_level ||= RAILS_ENV == 'production' ? :info : :debug end - def default_frameworks - [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ] + def frameworks + @frameworks ||= [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ] end - def default_plugin_paths - ["#{root_path}/vendor/plugins"] + def plugin_paths + @plugin_paths ||= ["#{root_path}/vendor/plugins"] end - def default_plugin_loader - require 'rails/plugin/loader' - Plugin::Loader + def plugin_loader + @plugin_loader ||= begin + Plugin::Loader + end end - def default_plugin_locators - require 'rails/plugin/locator' - locators = [] - locators << Plugin::GemLocator if defined? Gem - locators << Plugin::FileSystemLocator + def plugin_locators + @plugin_locators ||= begin + locators = [] + locators << Plugin::GemLocator if defined? Gem + locators << Plugin::FileSystemLocator + end end - def default_i18n - i18n = Rails::OrderedOptions.new - i18n.load_path = [] + def i18n + @i18n ||= begin + i18n = Rails::OrderedOptions.new + i18n.load_path = [] - if File.exist?(File.join(RAILS_ROOT, 'config', 'locales')) - i18n.load_path << Dir[File.join(RAILS_ROOT, 'config', 'locales', '*.{rb,yml}')] - i18n.load_path.flatten! - end - - i18n - end + if File.exist?(File.join(RAILS_ROOT, 'config', 'locales')) + i18n.load_path << Dir[File.join(RAILS_ROOT, 'config', 'locales', '*.{rb,yml}')] + i18n.load_path.flatten! + end - def default_serve_static_assets - true + i18n + end end # Adds a single Gem dependency to the rails application. By default, it will require @@ -241,11 +234,11 @@ module Rails # # config.gem 'qrp', :version => '0.4.1', :lib => false def gem(name, options = {}) - @gems << Rails::GemDependency.new(name, options) + gems << Rails::GemDependency.new(name, options) end - def default_gems - [] + def gems + @gems ||= [] end def environment_path diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb new file mode 100644 index 0000000000..1bf59c2b8e --- /dev/null +++ b/railties/test/application/configuration_test.rb @@ -0,0 +1,17 @@ +require "isolation/abstract_unit" + +module ApplicationTests + class InitializerTest < Test::Unit::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + boot_rails + end + + test "the application root is set correctly" do + # require "#{app_path}/config/environment" + # assert_equal app_path, Rails.application.root + end + end +end \ No newline at end of file diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 0d6eb4147a..0edb29483d 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -5,9 +5,9 @@ module ApplicationTests include ActiveSupport::Testing::Isolation def setup - require "rails/generators" build_app boot_rails + require "rails/generators" end test "generators default values" do diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index d917812383..7599bda8a2 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -8,12 +8,17 @@ else RAILS_ROOT = fixtures end +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../activemodel/lib" +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../activerecord/lib" +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../actionpack/lib" $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib" +# TODO: Fix this RAILS_ENV stuff +RAILS_ENV = 'test' +require "rails/core" require 'rails/generators' require 'rubygems' -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../activerecord/lib" -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../actionpack/lib" + require 'active_record' require 'action_dispatch' -- cgit v1.2.3 From a8dc9fd27b845193fd209a249e084f993a10c19d Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Wed, 14 Oct 2009 00:26:53 -0400 Subject: CookieJar#delete should return the key's value, consistent with a Hash Signed-off-by: Jeremy Kemper --- actionpack/lib/action_controller/metal/cookies.rb | 3 ++- actionpack/test/controller/cookie_test.rb | 7 +++++++ actionpack/test/dispatch/session/test_session_test.rb | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb index d4806623c3..c328db8beb 100644 --- a/actionpack/lib/action_controller/metal/cookies.rb +++ b/actionpack/lib/action_controller/metal/cookies.rb @@ -87,8 +87,9 @@ module ActionController #:nodoc: def delete(key, options = {}) options.symbolize_keys! options[:path] = "/" unless options.has_key?(:path) - super(key.to_s) + value = super(key.to_s) @controller.response.delete_cookie(key, options) + value end end end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 7199da3441..b429cbf0e6 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -118,6 +118,13 @@ class CookieTest < ActionController::TestCase assert_equal %w{1 2 3}, jar["pages"] end + def test_cookiejar_delete_removes_item_and_returns_its_value + @request.cookies["user_name"] = "david" + @controller.response = @response + jar = ActionController::CookieJar.new(@controller) + assert_equal "david", jar.delete("user_name") + end + def test_delete_cookie_with_path get :delete_cookie_with_path assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT" diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb index 0ff93f1c5d..c8dc4ab461 100644 --- a/actionpack/test/dispatch/session/test_session_test.rb +++ b/actionpack/test/dispatch/session/test_session_test.rb @@ -26,11 +26,11 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase assert_equal('value', session[:key]) end - def test_calling_delete_removes_item + def test_calling_delete_removes_item_and_returns_its_value session = ActionController::TestSession.new session[:key] = 'value' assert_equal('value', session[:key]) - session.delete(:key) + assert_equal('value', session.delete(:key)) assert_nil(session[:key]) end -- cgit v1.2.3 From a41c6c35cadf75bfd4bf0a17113ae37d628896e8 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Wed, 14 Oct 2009 11:59:00 -0700 Subject: Start adding configuration to ActionView instead of using constants. By using config rather than hardcoded constants, we can evolve the configuration system over time (we'd just need to update the config method with more robust capabilities and all consumers would get the capabilities with no code changes) --- actionpack/lib/action_view/base.rb | 2 +- .../lib/action_view/helpers/asset_tag_helper.rb | 28 +++++++++-------- actionpack/test/template/asset_tag_helper_test.rb | 10 +++++++ actionpack/test/template/form_tag_helper_test.rb | 3 ++ actionpack/test/template/url_helper_test.rb | 3 ++ activesupport/lib/active_support/autoload.rb | 2 ++ activesupport/lib/active_support/configurable.rb | 35 ++++++++++++++++++++++ 7 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 activesupport/lib/active_support/configurable.rb diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 31e9c5ef9d..5f28ba6ccb 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -167,7 +167,7 @@ module ActionView #:nodoc: module Subclasses end - include Helpers, Rendering, Partials, ::ERB::Util + include Helpers, Rendering, Partials, ::ERB::Util, ActiveSupport::Configurable extend ActiveSupport::Memoizable diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index faa7f2e2e9..15b70ecff5 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -133,9 +133,13 @@ module ActionView # change. You can use something like Live HTTP Headers for Firefox to verify # that the cache is indeed working. module AssetTagHelper - ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public" - JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts" - STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets" + assets_dir = defined?(Rails.public_path) ? Rails.public_path : "public" + ActionView::DEFAULT_CONFIG = { + :assets_dir => assets_dir, + :javascripts_dir => "#{assets_dir}/javascripts", + :stylesheets_dir => "#{assets_dir}/stylesheets", + } + JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES) # Returns a link tag that browsers and news readers can use to auto-detect @@ -280,7 +284,7 @@ module ActionView if concat || (ActionController::Base.perform_caching && cache) joined_javascript_name = (cache == true ? "all" : cache) + ".js" - joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : JAVASCRIPTS_DIR, joined_javascript_name) + joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.javascripts_dir, joined_javascript_name) unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path) write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) @@ -431,7 +435,7 @@ module ActionView if concat || (ActionController::Base.perform_caching && cache) joined_stylesheet_name = (cache == true ? "all" : cache) + ".css" - joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : STYLESHEETS_DIR, joined_stylesheet_name) + joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.stylesheets_dir, joined_stylesheet_name) unless ActionController::Base.perform_caching && File.exists?(joined_stylesheet_path) write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) @@ -630,11 +634,11 @@ module ActionView # Prefix with /dir/ if lacking a leading +/+. Account for relative URL # roots. Rewrite the asset path for cache-busting asset ids. Include # asset host, if configured, with the correct request protocol. - def compute_public_path(source, dir, ext = nil, include_host = true) + def compute_public_path(source, dir, ext = nil, include_host = true) has_request = @controller.respond_to?(:request) source_ext = File.extname(source)[1..-1] - if ext && !is_uri?(source) && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")))) + if ext && !is_uri?(source) && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}")))) source += ".#{ext}" end @@ -700,7 +704,7 @@ module ActionView if @@cache_asset_timestamps && (asset_id = @@asset_timestamps_cache[source]) asset_id else - path = File.join(ASSETS_DIR, source) + path = File.join(config.assets_dir, source) asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : '' if @@cache_asset_timestamps @@ -743,20 +747,20 @@ module ActionView def expand_javascript_sources(sources, recursive = false) if sources.include?(:all) - all_javascript_files = collect_asset_files(JAVASCRIPTS_DIR, ('**' if recursive), '*.js') + all_javascript_files = collect_asset_files(config.javascripts_dir, ('**' if recursive), '*.js') ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq else expanded_sources = sources.collect do |source| determine_source(source, @@javascript_expansions) end.flatten - expanded_sources << "application" if sources.include?(:defaults) && File.exist?(File.join(JAVASCRIPTS_DIR, "application.js")) + expanded_sources << "application" if sources.include?(:defaults) && File.exist?(File.join(config.javascripts_dir, "application.js")) expanded_sources end end def expand_stylesheet_sources(sources, recursive) if sources.first == :all - collect_asset_files(STYLESHEETS_DIR, ('**' if recursive), '*.css') + collect_asset_files(config.stylesheets_dir, ('**' if recursive), '*.css') else sources.collect do |source| determine_source(source, @@stylesheet_expansions) @@ -803,7 +807,7 @@ module ActionView end def asset_file_path(path) - File.join(ASSETS_DIR, path.split('?').first) + File.join(config.assets_dir, path.split('?').first) end def asset_file_path!(path) diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index d94135b04b..57802ebf42 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -3,6 +3,13 @@ require 'abstract_unit' class AssetTagHelperTest < ActionView::TestCase tests ActionView::Helpers::AssetTagHelper + DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG.merge( + :assets_dir => File.dirname(__FILE__) + "/../fixtures/public", + :javascripts_dir => File.dirname(__FILE__) + "/../fixtures/public/javascripts", + :stylesheets_dir => File.dirname(__FILE__) + "/../fixtures/public/stylesheets") + + include ActiveSupport::Configurable + def setup super silence_warnings do @@ -872,6 +879,9 @@ end class AssetTagHelperNonVhostTest < ActionView::TestCase tests ActionView::Helpers::AssetTagHelper + DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG + include ActiveSupport::Configurable + def setup super ActionController::Base.relative_url_root = "/collaboration/hieraki" diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index d64b9492e2..47462b1237 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -3,6 +3,9 @@ require 'abstract_unit' class FormTagHelperTest < ActionView::TestCase tests ActionView::Helpers::FormTagHelper + include ActiveSupport::Configurable + DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG + def setup super @controller = Class.new do diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 7f6ebc56b7..111a7619b5 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -5,6 +5,9 @@ require 'controller/fake_controllers' RequestMock = Struct.new("Request", :request_uri, :protocol, :host_with_port, :env) class UrlHelperTest < ActionView::TestCase + include ActiveSupport::Configurable + DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG + def setup super @controller = Class.new do diff --git a/activesupport/lib/active_support/autoload.rb b/activesupport/lib/active_support/autoload.rb index 47a17687bf..f3a68b482f 100644 --- a/activesupport/lib/active_support/autoload.rb +++ b/activesupport/lib/active_support/autoload.rb @@ -7,6 +7,8 @@ module ActiveSupport autoload :Callbacks, 'active_support/callbacks' autoload :Concern, 'active_support/concern' autoload :ConcurrentHash, 'active_support/concurrent_hash' + autoload :Configurable, 'active_support/configurable' + autoload :DependencyModule, 'active_support/dependency_module' autoload :DeprecatedCallbacks, 'active_support/deprecated_callbacks' autoload :Deprecation, 'active_support/deprecation' autoload :Gzip, 'active_support/gzip' diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb new file mode 100644 index 0000000000..890f465ce1 --- /dev/null +++ b/activesupport/lib/active_support/configurable.rb @@ -0,0 +1,35 @@ +require "active_support/concern" + +module ActiveSupport + module Configurable + extend ActiveSupport::Concern + + module ClassMethods + def get_config + module_parts = name.split("::") + modules = [Object] + module_parts.each {|name| modules.push modules.last.const_get(name) } + modules.reverse_each do |mod| + return mod.const_get(:DEFAULT_CONFIG) if const_defined?(:DEFAULT_CONFIG) + end + {} + end + + def config + self.config = get_config unless @config + @config + end + + def config=(hash) + @config = ActiveSupport::OrderedOptions.new + hash.each do |key, value| + @config[key] = value + end + end + end + + def config + self.class.config + end + end +end \ No newline at end of file -- cgit v1.2.3 From 1b3195b63ca44f0a70b61b75fcf4991cb2fbb944 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 7 Oct 2009 14:49:38 -0400 Subject: ActionView.url_for doesn't escape by default ActionView::Helpers::UrlHelper#url_for used to escape the URLs it generated by default. This was most commonly seen when generating a path with multiple query parameters, e.g. url_for(:controller => :foo, :action => :bar, :this => 123, :that => 456) would return http://example.com/foo/bar?that=456&this=123 escaping an ampersand that shouldn't be escaped. This is both wrong and inconsistent with the behavior of ActionController#url_for, and is changed. Signed-off-by: Michael Koziarski --- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/test/template/url_helper_test.rb | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index e651bc17a9..44e7073227 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -83,7 +83,7 @@ module ActionView options when Hash options = { :only_path => options[:host].nil? }.update(options.symbolize_keys) - escape = options.key?(:escape) ? options.delete(:escape) : true + escape = options.key?(:escape) ? options.delete(:escape) : false @controller.send(:url_for, options) when :back escape = false diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 111a7619b5..cc3b2455d7 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -22,7 +22,7 @@ class UrlHelperTest < ActionView::TestCase def test_url_for_escapes_urls @controller.url = "http://www.example.com?a=b&c=d" - assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd') + assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd') assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => true) assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => false) end @@ -42,6 +42,16 @@ class UrlHelperTest < ActionView::TestCase assert_equal 'javascript:history.back()', url_for(:back) end + def test_url_for_from_hash_doesnt_escape_ampersand + @controller = TestController.new + @view = ActionView::Base.new + @view.controller = @controller + + path = @view.url_for(:controller => :cheeses, :foo => :bar, :baz => :quux) + + assert_equal '/cheeses?baz=quux&foo=bar', path + end + # todo: missing test cases def test_button_to_with_straight_url assert_dom_equal "
", button_to("Hello", "http://www.example.com") @@ -298,7 +308,7 @@ class UrlHelperTest < ActionView::TestCase @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1") @controller.url = "http://www.example.com/weblog/show?order=desc&page=1" assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog", :order=>'desc', :page=>'1' }) - assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1") + assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1") assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=1") @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc") @@ -308,7 +318,7 @@ class UrlHelperTest < ActionView::TestCase @controller.request = RequestMock.new("http://www.example.com/weblog/show?order=desc&page=1") @controller.url = "http://www.example.com/weblog/show?order=desc&page=2" - assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" }) + assert_equal "Showing", link_to_unless_current("Showing", { :action => "show", :controller => "weblog" }) assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/weblog/show?order=desc&page=2") -- cgit v1.2.3 From 5d5e34fa52183566968cb22f7c49544a7361a130 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 15 Oct 2009 09:58:17 +1300 Subject: Use ERB::Util.h over CGI.escapeHTML as the former is safety aware and the latter isn't --- actionpack/lib/action_controller/metal/redirector.rb | 2 +- actionpack/lib/action_view/safe_buffer.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb index f79fd54acd..b55f5e7bfc 100644 --- a/actionpack/lib/action_controller/metal/redirector.rb +++ b/actionpack/lib/action_controller/metal/redirector.rb @@ -16,7 +16,7 @@ module ActionController logger.info("Redirected to #{url}") if logger && logger.info? self.status = status self.location = url.gsub(/[\r\n]/, '') - self.response_body = "You are being redirected." + self.response_body = "You are being redirected." end end end diff --git a/actionpack/lib/action_view/safe_buffer.rb b/actionpack/lib/action_view/safe_buffer.rb index 8ba9cd80d6..09f44ab26f 100644 --- a/actionpack/lib/action_view/safe_buffer.rb +++ b/actionpack/lib/action_view/safe_buffer.rb @@ -5,7 +5,7 @@ module ActionView #:nodoc: if value.html_safe? super(value) else - super(CGI.escapeHTML(value)) + super(ERB::Util.h(value)) end end -- cgit v1.2.3 From 1d01bad3cedfd690c6d125cac6d4504baa9409e5 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 15 Oct 2009 09:58:35 +1300 Subject: Make sure non-escaped urls aren't considered safe --- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/test/template/url_helper_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 44e7073227..5b136d4f54 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -93,7 +93,7 @@ module ActionView polymorphic_path(options) end - (escape ? escape_once(url) : url).html_safe! + escape ? escape_once(url).html_safe! : url end # Creates a link tag of the given +name+ using a URL created by the set diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index cc3b2455d7..cec53e479c 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -26,6 +26,11 @@ class UrlHelperTest < ActionView::TestCase assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => true) assert_equal "http://www.example.com?a=b&c=d", url_for(:a => 'b', :c => 'd', :escape => false) end + + def test_url_for_escaping_is_safety_aware + assert url_for(:a => 'b', :c => 'd', :escape => true).html_safe?, "escaped urls should be html_safe?" + assert !url_for(:a => 'b', :c => 'd', :escape => false).html_safe?, "non-escaped urls shouldn't be safe" + end def test_url_for_escapes_url_once @controller.url = "http://www.example.com?a=b&c=d" -- cgit v1.2.3 From 945d999aadc9df41487e675fa0a863396cb54e31 Mon Sep 17 00:00:00 2001 From: pivotal Date: Fri, 2 Oct 2009 13:57:31 -0700 Subject: Digest auth option for ActiveResource. Signed-off-by: Michael Koziarski --- activeresource/lib/active_resource/base.rb | 12 ++ activeresource/lib/active_resource/connection.rb | 90 ++++++++++-- activeresource/test/cases/authorization_test.rb | 170 +++++++++++++++++++---- activeresource/test/cases/base_test.rb | 6 + activeresource/test/connection_test.rb | 15 ++ 5 files changed, 258 insertions(+), 35 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index b21d8db613..ae627c365d 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -326,6 +326,17 @@ module ActiveResource @password = password end + def auth_type + if defined?(@auth_type) + @auth_type + end + end + + def auth_type=(auth_type) + @connection = nil + @auth_type = auth_type + end + # Sets the format that attributes are sent and received in from a mime type reference: # # Person.format = :json @@ -397,6 +408,7 @@ module ActiveResource @connection.proxy = proxy if proxy @connection.user = user if user @connection.password = password if password + @connection.auth_type = auth_type if auth_type @connection.timeout = timeout if timeout @connection.ssl_options = ssl_options if ssl_options @connection diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb index 9d551f04e7..98cb1a932b 100644 --- a/activeresource/lib/active_resource/connection.rb +++ b/activeresource/lib/active_resource/connection.rb @@ -17,7 +17,7 @@ module ActiveResource :head => 'Accept' } - attr_reader :site, :user, :password, :timeout, :proxy, :ssl_options + attr_reader :site, :user, :password, :auth_type, :timeout, :proxy, :ssl_options attr_accessor :format class << self @@ -57,6 +57,11 @@ module ActiveResource @password = password end + # Sets the auth type for remote service. + def auth_type=(auth_type) + @auth_type = legitimize_auth_type(auth_type) + end + # Sets the number of seconds after which HTTP requests to the remote service should time out. def timeout=(timeout) @timeout = timeout @@ -70,31 +75,31 @@ module ActiveResource # Executes a GET request. # Used to get (find) resources. def get(path, headers = {}) - format.decode(request(:get, path, build_request_headers(headers, :get)).body) + with_auth { format.decode(request(:get, path, build_request_headers(headers, :get, self.site.merge(path))).body) } end # Executes a DELETE request (see HTTP protocol documentation if unfamiliar). # Used to delete resources. def delete(path, headers = {}) - request(:delete, path, build_request_headers(headers, :delete)) + with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) } end # Executes a PUT request (see HTTP protocol documentation if unfamiliar). # Used to update resources. def put(path, body = '', headers = {}) - request(:put, path, body.to_s, build_request_headers(headers, :put)) + with_auth { request(:put, path, body.to_s, build_request_headers(headers, :put, self.site.merge(path))) } end # Executes a POST request. # Used to create new resources. def post(path, body = '', headers = {}) - request(:post, path, body.to_s, build_request_headers(headers, :post)) + with_auth { request(:post, path, body.to_s, build_request_headers(headers, :post, self.site.merge(path))) } end # Executes a HEAD request. # Used to obtain meta-information about resources, such as whether they exist and their size (via response headers). def head(path, headers = {}) - request(:head, path, build_request_headers(headers, :head)) + with_auth { request(:head, path, build_request_headers(headers, :head, self.site.merge(path))) } end @@ -198,13 +203,70 @@ module ActiveResource end # Builds headers for request to remote service. - def build_request_headers(headers, http_method=nil) - authorization_header.update(default_header).update(http_format_header(http_method)).update(headers) + def build_request_headers(headers, http_method, uri) + authorization_header(http_method, uri).update(default_header).update(http_format_header(http_method)).update(headers) + end + + def response_auth_header + @response_auth_header ||= "" + end + + def with_auth + retried ||= false + yield + rescue UnauthorizedAccess => e + raise if retried || auth_type != :digest + @response_auth_header = e.response['WWW-Authenticate'] + retried = true + retry + end + + def authorization_header(http_method, uri) + if @user || @password + if auth_type == :digest + { 'Authorization' => digest_auth_header(http_method, uri) } + else + { 'Authorization' => 'Basic ' + ["#{@user}:#{@password}"].pack('m').delete("\r\n") } + end + else + {} + end end - # Sets authorization header - def authorization_header - (@user || @password ? { 'Authorization' => 'Basic ' + ["#{@user}:#{ @password}"].pack('m').delete("\r\n") } : {}) + def digest_auth_header(http_method, uri) + params = extract_params_from_response + + ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}") + ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{uri.path}") + + params.merge!('cnonce' => client_nonce) + request_digest = Digest::MD5.hexdigest([ha1, params['nonce'], "0", params['cnonce'], params['qop'], ha2].join(":")) + "Digest #{auth_attributes_for(uri, request_digest, params)}" + end + + def client_nonce + Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))) + end + + def extract_params_from_response + params = {} + if response_auth_header =~ /^(\w+) (.*)/ + $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 } + end + params + end + + def auth_attributes_for(uri, request_digest, params) + [ + %Q(username="#{@user}"), + %Q(realm="#{params['realm']}"), + %Q(qop="#{params['qop']}"), + %Q(uri="#{uri.path}"), + %Q(nonce="#{params['nonce']}"), + %Q(nc="0"), + %Q(cnonce="#{params['cnonce']}"), + %Q(opaque="#{params['opaque']}"), + %Q(response="#{request_digest}")].join(", ") end def http_format_header(http_method) @@ -214,5 +276,11 @@ module ActiveResource def logger #:nodoc: Base.logger end + + def legitimize_auth_type(auth_type) + return :basic if auth_type.nil? + auth_type = auth_type.to_sym + [:basic, :digest].include?(auth_type) ? auth_type : :basic + end end end diff --git a/activeresource/test/cases/authorization_test.rb b/activeresource/test/cases/authorization_test.rb index ca25f437e3..1a7c9ec8a4 100644 --- a/activeresource/test/cases/authorization_test.rb +++ b/activeresource/test/cases/authorization_test.rb @@ -8,46 +8,75 @@ class AuthorizationTest < Test::Unit::TestCase @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person') @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person') @authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost") - @authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' } + @basic_authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' } + + @nonce = "MTI0OTUxMzc4NzpjYWI3NDM3NDNmY2JmODU4ZjQ2ZjcwNGZkMTJiMjE0NA==" ActiveResource::HttpMock.respond_to do |mock| - mock.get "/people/2.xml", @authorization_request_header, @david - mock.put "/people/2.xml", @authorization_request_header, nil, 204 - mock.delete "/people/2.xml", @authorization_request_header, nil, 200 - mock.post "/people/2/addresses.xml", @authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5' + mock.get "/people/2.xml", @basic_authorization_request_header, @david + mock.get "/people/1.xml", @basic_authorization_request_header, nil, 401, { 'WWW-Authenticate' => 'i_should_be_ignored' } + mock.put "/people/2.xml", @basic_authorization_request_header, nil, 204 + mock.delete "/people/2.xml", @basic_authorization_request_header, nil, 200 + mock.post "/people/2/addresses.xml", @basic_authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5' + mock.head "/people/2.xml", @basic_authorization_request_header, nil, 200 + + mock.get "/people/2.xml", { 'Authorization' => blank_digest_auth_header("/people/2.xml", "a10c9bd131c9d4d7755b8f4706fd04af") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header } + mock.get "/people/2.xml", { 'Authorization' => request_digest_auth_header("/people/2.xml", "912c7a643f18cda562b8d9662c47b6f5") }, @david, 200 + mock.get "/people/1.xml", { 'Authorization' => request_digest_auth_header("/people/1.xml", "d76e675c0ecfa2bb1abe01491b068a06") }, @matz, 200 + + mock.put "/people/2.xml", { 'Authorization' => blank_digest_auth_header("/people/2.xml", "7de8a265a5be3c4c2d3a246562ecd6bd") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header } + mock.put "/people/2.xml", { 'Authorization' => request_digest_auth_header("/people/2.xml", "3fb3b33d9d0b869cc75815aa11faacd9") }, nil, 204 + + mock.delete "/people/2.xml", { 'Authorization' => blank_digest_auth_header("/people/2.xml", "07dfc32769a34ea3510d3a77d64ca495") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header } + mock.delete "/people/2.xml", { 'Authorization' => request_digest_auth_header("/people/2.xml", "5d438610de7ec163b29096c9afcbb254") }, nil, 200 + + mock.post "/people/2/addresses.xml", { 'Authorization' => blank_digest_auth_header("/people/2/addresses.xml", "966dab13620421f928d051f2b9d7b9af") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header } + mock.post "/people/2/addresses.xml", { 'Authorization' => request_digest_auth_header("/people/2/addresses.xml", "ed540d032c63f8ee34959116c090ec45") }, nil, 201, 'Location' => '/people/1/addresses/5' + + mock.head "/people/2.xml", { 'Authorization' => blank_digest_auth_header("/people/2.xml", "2854eeb92cce2aed29350ea0ce7ba1e2") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header } + mock.head "/people/2.xml", { 'Authorization' => request_digest_auth_header("/people/2.xml", "07cd4d247e9c130f92ba2501a080b328") }, nil, 200 + end + + # Make client nonce deterministic + class << @authenticated_conn + private + + def client_nonce + 'i-am-a-client-nonce' + end end end def test_authorization_header - authorization_header = @authenticated_conn.__send__(:authorization_header) - assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization'] + authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) + assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization'] authorization = authorization_header["Authorization"].to_s.split - + assert_equal "Basic", authorization[0] assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1] end - + def test_authorization_header_with_username_but_no_password @conn = ActiveResource::Connection.new("http://david:@localhost") - authorization_header = @conn.__send__(:authorization_header) + authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) authorization = authorization_header["Authorization"].to_s.split - + assert_equal "Basic", authorization[0] assert_equal ["david"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1] end - + def test_authorization_header_with_password_but_no_username @conn = ActiveResource::Connection.new("http://:test123@localhost") - authorization_header = @conn.__send__(:authorization_header) + authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) authorization = authorization_header["Authorization"].to_s.split - + assert_equal "Basic", authorization[0] assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1] end - + def test_authorization_header_with_decoded_credentials_from_url @conn = ActiveResource::Connection.new("http://my%40email.com:%31%32%33@localhost") - authorization_header = @conn.__send__(:authorization_header) + authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) authorization = authorization_header["Authorization"].to_s.split assert_equal "Basic", authorization[0] @@ -58,8 +87,8 @@ class AuthorizationTest < Test::Unit::TestCase @authenticated_conn = ActiveResource::Connection.new("http://@localhost") @authenticated_conn.user = 'david' @authenticated_conn.password = 'test123' - authorization_header = @authenticated_conn.__send__(:authorization_header) - assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization'] + authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) + assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization'] authorization = authorization_header["Authorization"].to_s.split assert_equal "Basic", authorization[0] @@ -69,7 +98,7 @@ class AuthorizationTest < Test::Unit::TestCase def test_authorization_header_explicitly_setting_username_but_no_password @conn = ActiveResource::Connection.new("http://@localhost") @conn.user = "david" - authorization_header = @conn.__send__(:authorization_header) + authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) authorization = authorization_header["Authorization"].to_s.split assert_equal "Basic", authorization[0] @@ -79,38 +108,119 @@ class AuthorizationTest < Test::Unit::TestCase def test_authorization_header_explicitly_setting_password_but_no_username @conn = ActiveResource::Connection.new("http://@localhost") @conn.password = "test123" - authorization_header = @conn.__send__(:authorization_header) + authorization_header = @conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) authorization = authorization_header["Authorization"].to_s.split assert_equal "Basic", authorization[0] assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1] end + def test_authorization_header_if_credentials_supplied_and_auth_type_is_basic + @authenticated_conn.auth_type = :basic + authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) + assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization'] + authorization = authorization_header["Authorization"].to_s.split + + assert_equal "Basic", authorization[0] + assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1] + end + + def test_authorization_header_if_credentials_supplied_and_auth_type_is_digest + @authenticated_conn.auth_type = :digest + authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.xml')) + assert_equal blank_digest_auth_header("/people/2.xml", "a10c9bd131c9d4d7755b8f4706fd04af"), authorization_header['Authorization'] + end + def test_get david = @authenticated_conn.get("/people/2.xml") assert_equal "David", david["name"] end - + def test_post response = @authenticated_conn.post("/people/2/addresses.xml") assert_equal "/people/1/addresses/5", response["Location"] end - + def test_put response = @authenticated_conn.put("/people/2.xml") assert_equal 204, response.code end - + def test_delete response = @authenticated_conn.delete("/people/2.xml") assert_equal 200, response.code end + def test_head + response = @authenticated_conn.head("/people/2.xml") + assert_equal 200, response.code + end + + def test_get_with_digest_auth_handles_initial_401_response_and_retries + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.get("/people/2.xml") + assert_equal "David", response["name"] + end + + def test_post_with_digest_auth_handles_initial_401_response_and_retries + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.post("/people/2/addresses.xml") + assert_equal "/people/1/addresses/5", response["Location"] + assert_equal 201, response.code + end + + def test_put_with_digest_auth_handles_initial_401_response_and_retries + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.put("/people/2.xml") + assert_equal 204, response.code + end + + def test_delete_with_digest_auth_handles_initial_401_response_and_retries + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.delete("/people/2.xml") + assert_equal 200, response.code + end + + def test_head_with_digest_auth_handles_initial_401_response_and_retries + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.head("/people/2.xml") + assert_equal 200, response.code + end + + def test_get_with_digest_auth_caches_nonce + @authenticated_conn.auth_type = :digest + response = @authenticated_conn.get("/people/2.xml") + assert_equal "David", response["name"] + + # There is no mock for this request with a non-cached nonce. + response = @authenticated_conn.get("/people/1.xml") + assert_equal "Matz", response["name"] + end + + def test_retry_on_401_only_happens_with_digest_auth + assert_raise(ActiveResource::UnauthorizedAccess) { @authenticated_conn.get("/people/1.xml") } + assert_equal "", @authenticated_conn.send(:response_auth_header) + end + def test_raises_invalid_request_on_unauthorized_requests - assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.xml") } + end + + def test_raises_invalid_request_on_unauthorized_requests_with_digest_auth + @conn.auth_type = :digest + assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.xml") } assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.xml") } assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.xml") } assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.xml") } + assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.xml") } + end + + def test_client_nonce_is_not_nil + assert_not_nil ActiveResource::Connection.new("http://david:test123@localhost").send(:client_nonce) end protected @@ -119,4 +229,16 @@ class AuthorizationTest < Test::Unit::TestCase @conn.__send__(:handle_response, Response.new(code)) end end + + def blank_digest_auth_header(uri, response) + %Q(Digest username="david", realm="", qop="", uri="#{uri}", nonce="", nc="0", cnonce="i-am-a-client-nonce", opaque="", response="#{response}") + end + + def request_digest_auth_header(uri, response) + %Q(Digest username="david", realm="RailsTestApp", qop="auth", uri="#{uri}", nonce="#{@nonce}", nc="0", cnonce="i-am-a-client-nonce", opaque="ef6dfb078ba22298d366f99567814ffb", response="#{response}") + end + + def response_digest_auth_header + %Q(Digest realm="RailsTestApp", qop="auth", algorithm=MD5, nonce="#{@nonce}", opaque="ef6dfb078ba22298d366f99567814ffb") + end end diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index 1593e25595..1d3f7891ec 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -163,6 +163,12 @@ class BaseTest < Test::Unit::TestCase assert_equal('test123', Forum.connection.password) end + def test_should_accept_setting_auth_type + Forum.auth_type = :digest + assert_equal(:digest, Forum.auth_type) + assert_equal(:digest, Forum.connection.auth_type) + end + def test_should_accept_setting_timeout Forum.timeout = 5 assert_equal(5, Forum.timeout) diff --git a/activeresource/test/connection_test.rb b/activeresource/test/connection_test.rb index 2a3e04272a..a2744d7531 100644 --- a/activeresource/test/connection_test.rb +++ b/activeresource/test/connection_test.rb @@ -225,6 +225,21 @@ class ConnectionTest < Test::Unit::TestCase assert_raise(ActiveResource::SSLError) { @conn.get('/people/1.xml') } end + def test_auth_type_can_be_string + @conn.auth_type = 'digest' + assert_equal(:digest, @conn.auth_type) + end + + def test_auth_type_defaults_to_basic + @conn.auth_type = nil + assert_equal(:basic, @conn.auth_type) + end + + def test_auth_type_ignores_nonsensical_values + @conn.auth_type = :wibble + assert_equal(:basic, @conn.auth_type) + end + protected def assert_response_raises(klass, code) assert_raise(klass, "Expected response code #{code} to raise #{klass}") do -- cgit v1.2.3 From d39f397dc6726b27cc2c60a6e24e15cb1944ec58 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 15 Oct 2009 10:42:18 +1300 Subject: Missing requires --- activesupport/lib/active_support/callbacks.rb | 1 + activesupport/lib/active_support/testing/setup_and_teardown.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 67e9b0103f..0856e4f568 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/class/inheritable_attributes' require 'active_support/core_ext/kernel/reporting' +require 'active_support/concern' module ActiveSupport # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index b738ef334c..137e2629ff 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,3 +1,4 @@ +require 'active_support/callbacks' module ActiveSupport module Testing module SetupAndTeardown -- cgit v1.2.3 From 3e62503903bec17f418a1c4e28d3cf119a520458 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 14 Oct 2009 14:47:00 -0700 Subject: Fix tests --- activeresource/test/abstract_unit.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb index 05efac79cf..6a33040243 100644 --- a/activeresource/test/abstract_unit.rb +++ b/activeresource/test/abstract_unit.rb @@ -1,5 +1,6 @@ require 'rubygems' require 'test/unit' +require 'active_support' require 'active_support/test_case' $:.unshift "#{File.dirname(__FILE__)}/../lib" -- cgit v1.2.3 From 3fa7e2fc98235fdb6abba1d0e703464e880aa2af Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 14 Oct 2009 14:48:43 -0700 Subject: Revert "Missing requires" These rely on constant autoloads. This reverts commit d39f397dc6726b27cc2c60a6e24e15cb1944ec58. --- activesupport/lib/active_support/callbacks.rb | 1 - activesupport/lib/active_support/testing/setup_and_teardown.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 0856e4f568..67e9b0103f 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,7 +1,6 @@ require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/class/inheritable_attributes' require 'active_support/core_ext/kernel/reporting' -require 'active_support/concern' module ActiveSupport # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 137e2629ff..b738ef334c 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,4 +1,3 @@ -require 'active_support/callbacks' module ActiveSupport module Testing module SetupAndTeardown -- cgit v1.2.3 From fc46c9b2207c62d4b029c2c891c61fc660c0b627 Mon Sep 17 00:00:00 2001 From: Jacob Lauemoeller Date: Fri, 2 Oct 2009 16:34:28 +0200 Subject: Added CDATA support to the XmlMini LibXML engine, adjusted whitespace handling to closer match that of the REXML engine, and added a LibXML engine test Signed-off-by: Michael Koziarski --- .../lib/active_support/xml_mini/libxml.rb | 13 +- activesupport/test/xml_mini/libxml_engine_test.rb | 194 +++++++++++++++++++++ 2 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 activesupport/test/xml_mini/libxml_engine_test.rb diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index 2ae22c35fb..0f7ba1918b 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -13,8 +13,6 @@ module ActiveSupport data = StringIO.new(data || '') end - LibXML::XML.default_keep_blanks = false - char = data.getc if char.nil? {} @@ -44,9 +42,9 @@ module LibXML #:nodoc: # hash:: # Hash to merge the converted element into. def to_hash(hash={}) - if text? - raise LibXML::XML::Error if content.length >= LIB_XML_LIMIT - hash[CONTENT_ROOT] = content + if text? || cdata? + raise LibXML::XML::Error if hash[CONTENT_ROOT].to_s.length + content.length >= LIB_XML_LIMIT + hash[CONTENT_ROOT] = hash[CONTENT_ROOT].to_s + content else sub_hash = insert_name_into_hash(hash, name) attributes_to_hash(sub_hash) @@ -88,6 +86,11 @@ module LibXML #:nodoc: # Hash to merge the children into. def children_to_hash(hash={}) each { |child| child.to_hash(hash) } + + if hash.length > 1 && hash[CONTENT_ROOT].blank? + hash.delete(CONTENT_ROOT) + end + attributes_to_hash(hash) hash end diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb new file mode 100644 index 0000000000..900c8052d6 --- /dev/null +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -0,0 +1,194 @@ +require 'abstract_unit' +require 'active_support/xml_mini' +require 'active_support/core_ext/hash/conversions' + +begin + require 'libxml' +rescue LoadError + # Skip libxml tests +else + +class LibxmlEngineTest < Test::Unit::TestCase + include ActiveSupport + + def setup + @default_backend = XmlMini.backend + XmlMini.backend = 'LibXML' + + LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do + end + + def teardown + XmlMini.backend = @default_backend + end + + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = %{ + + + + + + + + ]> + + &a; + + } + Hash.from_xml(attack_xml) + end + end + + def test_setting_libxml_as_backend + XmlMini.backend = 'LibXML' + assert_equal XmlMini_LibXML, XmlMini.backend + end + + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse('')) + end + + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) + + + a post + another post + + + eoxml + end + + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + + eoxml + end + + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + + eoxml + end + + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) + + + + eoxml + end + + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) + + + + + eoxml + end + + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) + + hello world + + eoxml + end + + def test_children_with_children + assert_equal_rexml(<<-eoxml) + + + + + + eoxml + end + + def test_children_with_text + assert_equal_rexml(<<-eoxml) + + + hello everyone + + + eoxml + end + + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) + + good + + hello everyone + + morning + + eoxml + end + + def test_parse_from_io + io = StringIO.new(<<-eoxml) + + good + + hello everyone + + morning + + eoxml + XmlMini.parse(io) + end + + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) + + + + + + eoxml + end + + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) + + + + + + eoxml + end + + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) + + + hello + morning + + + eoxml + end + + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) + + + + eoxml + end + + private + def assert_equal_rexml(xml) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } + assert_equal(hash, XmlMini.parse(xml)) + end +end + +end -- cgit v1.2.3 From 316f4704eaa8aaba11e7ecebc1da9aa926fdd2d0 Mon Sep 17 00:00:00 2001 From: Craig Smith Date: Fri, 5 Jun 2009 14:58:38 +0100 Subject: Test cases should see all the cookies, not just cookies that have been set in the controller. Previously this example would always pass, even when cookies.delete was not called. @request.cookies['foo'] = 'bar' get :delete_cookie assert_nil cookies['foo'] Signed-off-by: Michael Koziarski [#2768 state:committed] --- actionpack/lib/action_controller/testing/process.rb | 2 +- actionpack/test/controller/test_test.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index bbc7f3c8f9..323cce6a2f 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -35,7 +35,7 @@ module ActionController #:nodoc: end def cookies - @response.cookies + @request.cookies.merge(@response.cookies) end def redirect_to_url diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 73870a56bb..375878b755 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -108,6 +108,11 @@ XML head :created, :location => 'created resource' end + def delete_cookie + cookies.delete("foo") + render :nothing => true + end + private def rescue_action(e) raise e @@ -512,6 +517,18 @@ XML assert @request.params[:foo].blank? end + def test_should_have_knowledge_of_client_side_cookie_state_even_if_they_are_not_set + @request.cookies['foo'] = 'bar' + get :no_op + assert_equal 'bar', cookies['foo'] + end + + def test_should_detect_if_cookie_is_deleted + @request.cookies['foo'] = 'bar' + get :delete_cookie + assert_nil cookies['foo'] + end + %w(controller response request).each do |variable| %w(get post put delete head process).each do |method| define_method("test_#{variable}_missing_for_#{method}_raises_error") do -- cgit v1.2.3 From 3de8b44b26ecb64dc73661deb8dde1c5de92b496 Mon Sep 17 00:00:00 2001 From: George Ogata Date: Sun, 30 Aug 2009 23:46:48 -0400 Subject: Make IntegrationTest::Runner propagate method_missing to ancestors. Fixes RSpec integration example groups, which mixes its Matchers module into ActiveSupport::TestCase. Signed-off-by: Michael Koziarski --- actionpack/lib/action_dispatch/testing/integration.rb | 8 ++++++-- actionpack/test/controller/integration_test.rb | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 2c4a3a356d..58ebe94a5b 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -396,8 +396,12 @@ module ActionDispatch # Delegate unhandled messages to the current session instance. def method_missing(sym, *args, &block) reset! unless @integration_session - returning @integration_session.__send__(sym, *args, &block) do - copy_session_variables! + if @integration_session.respond_to?(sym) + returning @integration_session.__send__(sym, *args, &block) do + copy_session_variables! + end + else + super end end end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 508364d0b5..fe95fb5750 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -199,6 +199,24 @@ class IntegrationTestTest < Test::Unit::TestCase assert_equal ::ActionController::Integration::Session, session2.class assert_not_equal session1, session2 end + + # RSpec mixes Matchers (which has a #method_missing) into + # IntegrationTest's superclass. Make sure IntegrationTest does not + # try to delegate these methods to the session object. + def test_does_not_prevent_method_missing_passing_up_to_ancestors + mixin = Module.new do + def method_missing(name, *args) + name.to_s == 'foo' ? 'pass' : super + end + end + @test.class.superclass.__send__(:include, mixin) + begin + assert_equal 'pass', @test.foo + ensure + # leave other tests as unaffected as possible + mixin.__send__(:remove_method, :method_missing) + end + end end # Tests that integration tests don't call Controller test methods for processing. -- cgit v1.2.3 From d5d242660c6f772548366cf2440b70d2ceca8b46 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 15 Oct 2009 11:21:53 +1300 Subject: Avoid warning spam by flipping to the new callbacks mechanism. These callbacks are actually never called by rails itself, merely there for plugins --- activerecord/lib/active_record/connection_adapters/abstract_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index cdf0aebfee..694e1e561c 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -32,7 +32,7 @@ module ActiveRecord class AbstractAdapter include Quoting, DatabaseStatements, SchemaStatements include QueryCache - include ActiveSupport::DeprecatedCallbacks + include ActiveSupport::Callbacks define_callbacks :checkout, :checkin @@row_even = true -- cgit v1.2.3 From efdc06245470fa7caf2a14f2cb59e8bf8c76de5e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 14 Oct 2009 16:12:09 -0700 Subject: Revert "Rewrite AS::TestCase setup/teardown as a single callback chain" This reverts commit 610e94c097fcc41aaf11bf5ddd45898718aeeb55. --- .../active_support/testing/setup_and_teardown.rb | 57 ++++++++++------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index b738ef334c..97773dc2c0 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -6,7 +6,7 @@ module ActiveSupport extend ClassMethods include ActiveSupport::Callbacks - define_callbacks :test + define_callbacks :setup, :teardown if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions include ForMiniTest @@ -18,15 +18,11 @@ module ActiveSupport module ClassMethods def setup(*args, &block) - set_callback(:test, :before, *args, &block) + set_callback(:setup, *args, &block) end def teardown(*args, &block) - set_callback(:test, :after, *args, &block) - end - - def wrap(*args, &block) - set_callback(:test, :around, *args, &block) + set_callback(:teardown, *args, &block) end end @@ -34,15 +30,16 @@ module ActiveSupport def run(runner) result = '.' begin - run_callbacks :test do - begin - result = super - rescue Exception => e - result = runner.puke(self.class, self.name, e) - end - end + run_callbacks :setup + result = super rescue Exception => e result = runner.puke(self.class, self.name, e) + ensure + begin + run_callbacks :teardown, :enumerator => :reverse_each + rescue Exception => e + result = runner.puke(self.class, self.name, e) + end end result end @@ -70,27 +67,27 @@ module ActiveSupport @_result = result begin begin - run_callbacks :test do - begin - setup - __send__(@method_name) - mocha_verify(assertion_counter) if using_mocha - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue Exception => e - raise if PASSTHROUGH_EXCEPTIONS.include?(e.class) - add_error(e) - ensure - teardown - end - end + run_callbacks :setup + setup + __send__(@method_name) + mocha_verify(assertion_counter) if using_mocha + rescue Mocha::ExpectationError => e + add_failure(e.message, e.backtrace) rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) rescue Exception => e raise if PASSTHROUGH_EXCEPTIONS.include?(e.class) add_error(e) + ensure + begin + teardown + run_callbacks :teardown, :enumerator => :reverse_each + rescue Test::Unit::AssertionFailedError => e + add_failure(e.message, e.backtrace) + rescue Exception => e + raise if PASSTHROUGH_EXCEPTIONS.include?(e.class) + add_error(e) + end end ensure mocha_teardown if using_mocha -- cgit v1.2.3 From 00eb09e016837e361fb9dcf6a46d1715ec59beca Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 14 Oct 2009 16:12:19 -0700 Subject: Revert "Get AS TestCase off deprecated callbacks" This reverts commit 29b280666b6a8216a46b8349fa76c85f5b5dcc55. --- .../active_support/testing/setup_and_teardown.rb | 14 +----- activesupport/test/test_test.rb | 52 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 97773dc2c0..7952eb50c3 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -3,9 +3,7 @@ module ActiveSupport module SetupAndTeardown def self.included(base) base.class_eval do - extend ClassMethods - - include ActiveSupport::Callbacks + include ActiveSupport::DeprecatedCallbacks define_callbacks :setup, :teardown if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions @@ -16,16 +14,6 @@ module ActiveSupport end end - module ClassMethods - def setup(*args, &block) - set_callback(:setup, *args, &block) - end - - def teardown(*args, &block) - set_callback(:teardown, *args, &block) - end - end - module ForMiniTest def run(runner) result = '.' diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb index 7a45dab60b..5cbffb81fc 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_test.rb @@ -95,3 +95,55 @@ end class AlsoDoingNothingTest < ActiveSupport::TestCase end + +# Setup and teardown callbacks. +class SetupAndTeardownTest < ActiveSupport::TestCase + setup :reset_callback_record, :foo + teardown :foo, :sentinel, :foo + + def test_inherited_setup_callbacks + assert_equal [:reset_callback_record, :foo], self.class.setup_callback_chain.map(&:method) + assert_equal [:foo], @called_back + assert_equal [:foo, :sentinel, :foo], self.class.teardown_callback_chain.map(&:method) + end + + def setup + end + + def teardown + end + + protected + def reset_callback_record + @called_back = [] + end + + def foo + @called_back << :foo + end + + def sentinel + assert_equal [:foo, :foo], @called_back + end +end + + +class SubclassSetupAndTeardownTest < SetupAndTeardownTest + setup :bar + teardown :bar + + def test_inherited_setup_callbacks + assert_equal [:reset_callback_record, :foo, :bar], self.class.setup_callback_chain.map(&:method) + assert_equal [:foo, :bar], @called_back + assert_equal [:foo, :sentinel, :foo, :bar], self.class.teardown_callback_chain.map(&:method) + end + + protected + def bar + @called_back << :bar + end + + def sentinel + assert_equal [:foo, :bar, :bar, :foo], @called_back + end +end -- cgit v1.2.3 From bf9819f73d74e19052b7b8a7a9885972a27e8876 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 14 Oct 2009 16:13:45 -0700 Subject: Have Rails.root be based off of config.ru --- railties/lib/rails/application.rb | 10 ++- railties/lib/rails/configuration.rb | 114 ++++++++++++++---------- railties/lib/rails/paths.rb | 1 - railties/test/application/configuration_test.rb | 36 +++++++- railties/test/isolation/abstract_unit.rb | 10 ++- 5 files changed, 116 insertions(+), 55 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d54120f850..a0e5d6a5a5 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -18,6 +18,10 @@ module Rails @plugin_loader ||= config.plugin_loader.new(self) end + def root + config.root + end + def routes ActionController::Routing::Routes end @@ -102,7 +106,7 @@ module Rails # Create tmp directories initializer :ensure_tmp_directories_exist do %w(cache pids sessions sockets).each do |dir_to_make| - FileUtils.mkdir_p(File.join(config.root_path, 'tmp', dir_to_make)) + FileUtils.mkdir_p(File.join(config.root, 'tmp', dir_to_make)) end end @@ -346,7 +350,7 @@ module Rails # Loads all plugins in config.plugin_paths. plugin_paths # defaults to vendor/plugins but may also be set to a list of # paths, such as - # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"] + # config.plugin_paths = ["#{config.root}/lib/plugins", "#{config.root}/vendor/plugins"] # # In the default implementation, as each plugin discovered in plugin_paths is initialized: # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory) @@ -394,7 +398,7 @@ module Rails initializer :load_application_initializers do if config.gems_dependencies_loaded - Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer| + Dir["#{configuration.root}/config/initializers/**/*.rb"].sort.each do |initializer| load(initializer) end end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index b5ac0e3ddc..322590f108 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -5,7 +5,7 @@ module Rails class Configuration attr_accessor :cache_classes, :load_paths, :load_once_paths, :gems_dependencies_loaded, :after_initialize_blocks, - :frameworks, :framework_root_path, :root_path, :plugin_paths, :plugins, + :frameworks, :framework_root_path, :root, :plugin_paths, :plugins, :plugin_loader, :plugin_locators, :gems, :loaded_plugins, :reload_plugins, :i18n, :gems, :whiny_nils, :consider_all_requests_local, :action_controller, :active_record, :action_view, :active_support, @@ -16,8 +16,6 @@ module Rails :eager_load_paths, :dependency_loading, :paths, :serve_static_assets def initialize - set_root_path! - @load_once_paths = [] @after_initialize_blocks = [] @loaded_plugins = [] @@ -34,38 +32,60 @@ module Rails @after_initialize_blocks << blk if blk end - def set_root_path! - raise 'RAILS_ROOT is not set' unless defined?(RAILS_ROOT) - raise 'RAILS_ROOT is not a directory' unless File.directory?(RAILS_ROOT) + def root + @root ||= begin + if defined?(RAILS_ROOT) + root = RAILS_ROOT + else + call_stack = caller.map { |p| p.split(':').first } + root_path = call_stack.detect { |p| p !~ %r[railties/lib/rails] } + root_path = File.dirname(root_path) - self.root_path = - # Pathname is incompatible with Windows, but Windows doesn't have - # real symlinks so File.expand_path is safe. - if RUBY_PLATFORM =~ /(:?mswin|mingw)/ - File.expand_path(RAILS_ROOT) + while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/config.ru") + parent = File.dirname(root_path) + root_path = parent != root_path && parent + end - # Otherwise use Pathname#realpath which respects symlinks. - else - Pathname.new(RAILS_ROOT).realpath.to_s + Object.class_eval("RAILS_ROOT = ''") + + root = File.exist?("#{root_path}/config.ru") ? root_path : Dir.pwd end - @paths = Rails::Application::Root.new(root_path) - @paths.app "app", :load_path => true - @paths.app.metals "app/metal", :eager_load => true - @paths.app.models "app/models", :eager_load => true - @paths.app.controllers "app/controllers", builtin_directories, :eager_load => true - @paths.app.helpers "app/helpers", :eager_load => true - @paths.app.services "app/services", :load_path => true - @paths.lib "lib", :load_path => true - @paths.vendor "vendor", :load_path => true - @paths.vendor.plugins "vendor/plugins" - @paths.tmp "tmp" - @paths.tmp.cache "tmp/cache" - @paths.config "config" - @paths.config.locales "config/locales" - @paths.config.environments "config/environments", :glob => "#{RAILS_ENV}.rb" - - RAILS_ROOT.replace root_path + root = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? + Pathname.new(root).expand_path.to_s : + Pathname.new(root).realpath.to_s + + # TODO: Remove RAILS_ROOT + RAILS_ROOT.replace(root) + root + end + end + + def root=(root) + Object.class_eval("RAILS_ROOT = ''") unless defined?(RAILS_ROOT) + RAILS_ROOT.replace(root) + @root = root + end + + def paths + @paths ||= begin + paths = Rails::Application::Root.new(root) + paths.app "app", :load_path => true + paths.app.metals "app/metal", :eager_load => true + paths.app.models "app/models", :eager_load => true + paths.app.controllers "app/controllers", builtin_directories, :eager_load => true + paths.app.helpers "app/helpers", :eager_load => true + paths.app.services "app/services", :load_path => true + paths.lib "lib", :load_path => true + paths.vendor "vendor", :load_path => true + paths.vendor.plugins "vendor/plugins" + paths.tmp "tmp" + paths.tmp.cache "tmp/cache" + paths.config "config" + paths.config.locales "config/locales" + paths.config.environments "config/environments", :glob => "#{RAILS_ENV}.rb" + paths + end end # Enable threaded mode. Allows concurrent requests to controller actions and @@ -92,7 +112,7 @@ module Rails end def framework_root_path - defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root_path}/vendor/rails" + defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root}/vendor/rails" end def middleware @@ -109,12 +129,12 @@ module Rails end def routes_configuration_file - @routes_configuration_file ||= File.join(root_path, 'config', 'routes.rb') + @routes_configuration_file ||= File.join(root, 'config', 'routes.rb') end def controller_paths @controller_paths ||= begin - paths = [File.join(root_path, 'app', 'controllers')] + paths = [File.join(root, 'app', 'controllers')] paths.concat builtin_directories paths end @@ -122,8 +142,8 @@ module Rails def cache_store @cache_store ||= begin - if File.exist?("#{root_path}/tmp/cache/") - [ :file_store, "#{root_path}/tmp/cache/" ] + if File.exist?("#{root}/tmp/cache/") + [ :file_store, "#{root}/tmp/cache/" ] else :memory_store end @@ -131,11 +151,11 @@ module Rails end def database_configuration_file - @database_configuration_file ||= File.join(root_path, 'config', 'database.yml') + @database_configuration_file ||= File.join(root, 'config', 'database.yml') end def view_path - @view_path ||= File.join(root_path, 'app', 'views') + @view_path ||= File.join(root, 'app', 'views') end def eager_load_paths @@ -144,7 +164,7 @@ module Rails app/models app/controllers app/helpers - ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } + ).map { |dir| "#{root}/#{dir}" }.select { |dir| File.directory?(dir) } end def load_paths @@ -152,10 +172,10 @@ module Rails paths = [] # Add the old mock paths only if the directories exists - paths.concat(Dir["#{root_path}/test/mocks/#{RAILS_ENV}"]) if File.exists?("#{root_path}/test/mocks/#{RAILS_ENV}") + paths.concat(Dir["#{root}/test/mocks/#{RAILS_ENV}"]) if File.exists?("#{root}/test/mocks/#{RAILS_ENV}") # Add the app's controller directory - paths.concat(Dir["#{root_path}/app/controllers/"]) + paths.concat(Dir["#{root}/app/controllers/"]) # Followed by the standard includes. paths.concat %w( @@ -167,7 +187,7 @@ module Rails app/services lib vendor - ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } + ).map { |dir| "#{root}/#{dir}" }.select { |dir| File.directory?(dir) } paths.concat builtin_directories end @@ -179,7 +199,7 @@ module Rails end def log_path - @log_path ||= File.join(root_path, 'log', "#{RAILS_ENV}.log") + @log_path ||= File.join(root, 'log', "#{RAILS_ENV}.log") end def log_level @@ -191,7 +211,7 @@ module Rails end def plugin_paths - @plugin_paths ||= ["#{root_path}/vendor/plugins"] + @plugin_paths ||= ["#{root}/vendor/plugins"] end def plugin_loader @@ -213,8 +233,8 @@ module Rails i18n = Rails::OrderedOptions.new i18n.load_path = [] - if File.exist?(File.join(RAILS_ROOT, 'config', 'locales')) - i18n.load_path << Dir[File.join(RAILS_ROOT, 'config', 'locales', '*.{rb,yml}')] + if File.exist?(File.join(root, 'config', 'locales')) + i18n.load_path << Dir[File.join(root, 'config', 'locales', '*.{rb,yml}')] i18n.load_path.flatten! end @@ -242,7 +262,7 @@ module Rails end def environment_path - "#{root_path}/config/environments/#{RAILS_ENV}.rb" + "#{root}/config/environments/#{RAILS_ENV}.rb" end def reload_plugins? diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 308d067701..0f24106353 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -26,7 +26,6 @@ module Rails @children = {} - # TODO: Move logic from set_root_path initializer @path = path @root = self @all_paths = [] diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 1bf59c2b8e..d90582d3db 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -7,11 +7,43 @@ module ApplicationTests def setup build_app boot_rails + Object.send(:remove_const, :RAILS_ROOT) end test "the application root is set correctly" do - # require "#{app_path}/config/environment" - # assert_equal app_path, Rails.application.root + require "#{app_path}/config/environment" + assert_equal app_path, Rails.application.root + end + + test "the application root can be set" do + FileUtils.mkdir_p("#{app_path}/hello") + add_to_config <<-RUBY + config.frameworks = [] + config.root = '#{app_path}/hello' + RUBY + require "#{app_path}/config/environment" + assert_equal "#{app_path}/hello", Rails.application.root + end + + test "the application root is detected as where config.ru is located" do + add_to_config <<-RUBY + config.frameworks = [] + RUBY + FileUtils.mv "#{app_path}/config.ru", "#{app_path}/config/config.ru" + require "#{app_path}/config/environment" + assert_equal "#{app_path}/config", Rails.application.root + end + + test "the application root is Dir.pwd if there is no config.ru" do + File.delete("#{app_path}/config.ru") + add_to_config <<-RUBY + config.frameworks = [] + RUBY + + Dir.chdir("#{app_path}/app") do + require "#{app_path}/config/environment" + assert_equal "#{app_path}/app", Rails.application.root + end end end end \ No newline at end of file diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index f83e0151a4..245577e8c0 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -25,8 +25,10 @@ module TestHelpers module Paths module_function + TMP_PATH = File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. tmp])) + def tmp_path(*args) - File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. tmp] + args)) + File.join(TMP_PATH, *args) end def app_path(*args) @@ -88,10 +90,14 @@ module TestHelpers end end + add_to_config 'config.action_controller.session = { :key => "_myapp_session", :secret => "bac838a849c1d5c4de2e6a50af826079" }' + end + + def add_to_config(str) environment = File.read("#{app_path}/config/environment.rb") if environment =~ /(\n\s*end\s*)\Z/ File.open("#{app_path}/config/environment.rb", 'w') do |f| - f.puts $` + %'\nconfig.action_controller.session = { :key => "_myapp_session", :secret => "bac838a849c1d5c4de2e6a50af826079" }\n' + $1 + f.puts $` + "\n#{str}\n" + $1 end end end -- cgit v1.2.3