diff options
Diffstat (limited to 'railties/test')
59 files changed, 3112 insertions, 500 deletions
diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 491faf4af9..0749615d03 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -8,11 +8,46 @@ require 'fileutils' require 'active_support' require 'action_controller' +require 'action_view' require 'rails/all' module TestApp class Application < Rails::Application config.root = File.dirname(__FILE__) - config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + end +end + +# Skips the current run on Rubinius using Minitest::Assertions#skip +def rubinius_skip(message = '') + skip message if RUBY_ENGINE == 'rbx' +end +# Skips the current run on JRuby using Minitest::Assertions#skip +def jruby_skip(message = '') + skip message if defined?(JRUBY_VERSION) +end + +class ActiveSupport::TestCase + # FIXME: we have tests that depend on run order, we should fix that and + # remove this method call. + self.test_order = :sorted + + private + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) end end diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb index ceae78ae80..d4885447e6 100644 --- a/railties/test/app_rails_loader_test.rb +++ b/railties/test/app_rails_loader_test.rb @@ -3,13 +3,27 @@ require 'abstract_unit' require 'rails/app_rails_loader' class AppRailsLoaderTest < ActiveSupport::TestCase + def loader + @loader ||= Class.new do + extend Rails::AppRailsLoader + + def self.exec_arguments + @exec_arguments + end + + def self.exec(*args) + @exec_arguments = args + end + end + end + def write(filename, contents=nil) FileUtils.mkdir_p(File.dirname(filename)) File.write(filename, contents) end def expects_exec(exe) - Rails::AppRailsLoader.expects(:exec).with(Rails::AppRailsLoader::RUBY, exe) + assert_equal [Rails::AppRailsLoader::RUBY, exe], loader.exec_arguments end setup do @@ -22,24 +36,30 @@ class AppRailsLoaderTest < ActiveSupport::TestCase exe = "#{script_dir}/rails" test "is not in a Rails application if #{exe} is not found in the current or parent directories" do - File.stubs(:exists?).with('bin/rails').returns(false) - File.stubs(:exists?).with('script/rails').returns(false) + def loader.find_executables; end + + assert !loader.exec_app_rails + end - assert !Rails::AppRailsLoader.exec_app_rails + test "is not in a Rails application if #{exe} exists but is a folder" do + FileUtils.mkdir_p(exe) + + assert !loader.exec_app_rails end ['APP_PATH', 'ENGINE_PATH'].each do |keyword| test "is in a Rails application if #{exe} exists and contains #{keyword}" do write exe, keyword + loader.exec_app_rails + expects_exec exe - Rails::AppRailsLoader.exec_app_rails end test "is not in a Rails application if #{exe} exists but doesn't contain #{keyword}" do write exe - assert !Rails::AppRailsLoader.exec_app_rails + assert !loader.exec_app_rails end test "is in a Rails application if parent directory has #{exe} containing #{keyword} and chdirs to the root directory" do @@ -48,8 +68,9 @@ class AppRailsLoaderTest < ActiveSupport::TestCase Dir.chdir('foo/bar') + loader.exec_app_rails + expects_exec exe - Rails::AppRailsLoader.exec_app_rails # Compare the realpath in case either of them has symlinks. # diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 4de8fcaa38..8f091cfdbf 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -37,7 +37,7 @@ module ApplicationTests end def assert_no_file_exists(filename) - assert !File.exists?(filename), "#{filename} does exist" + assert !File.exist?(filename), "#{filename} does exist" end test "assets routes have higher priority" do @@ -50,6 +50,8 @@ module ApplicationTests end RUBY + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" get "/assets/demo.js" @@ -189,7 +191,6 @@ module ApplicationTests end test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do - add_to_config "config.assets.digest = true" add_to_config "config.action_controller.perform_caching = false" ENV["RAILS_ENV"] = "production" @@ -199,10 +200,9 @@ module ApplicationTests end test "precompile creates a manifest file with all the assets listed" do + app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" app_file "app/assets/javascripts/application.js", "alert();" - # digest is default in false, we must enable it for test environment - add_to_config "config.assets.digest = true" precompile! manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first @@ -214,8 +214,6 @@ module ApplicationTests test "the manifest file should be saved by default in the same assets folder" do app_file "app/assets/javascripts/application.js", "alert();" - # digest is default in false, we must enable it for test environment - add_to_config "config.assets.digest = true" add_to_config "config.assets.prefix = '/x'" precompile! @@ -248,7 +246,6 @@ module ApplicationTests test "precompile properly refers files referenced with asset_path and runs in the provided RAILS_ENV" do app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - # digest is default in false, we must enable it for test environment add_to_env_config "test", "config.assets.digest = true" precompile!('RAILS_ENV=test') @@ -260,7 +257,7 @@ module ApplicationTests test "precompile shouldn't use the digests present in manifest.json" do app_file "app/assets/images/rails.png", "notactuallyapng" - app_file "app/assets/stylesheets/application.css.erb", "//= depend_on rails.png\np { url: <%= asset_path('rails.png') %> }" + app_file "app/assets/stylesheets/application.css.erb", "p { url: <%= asset_path('rails.png') %> }" ENV["RAILS_ENV"] = "production" precompile! @@ -280,12 +277,9 @@ module ApplicationTests test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - add_to_config "config.assets.compile = true" - add_to_config "config.assets.digest = true" - - ENV["RAILS_ENV"] = nil - precompile!('RAILS_GROUPS=assets') + ENV["RAILS_ENV"] = "production" + precompile! file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) @@ -293,7 +287,7 @@ module ApplicationTests test "precompile should handle utf8 filenames" do filename = "レイルズ.png" - app_file "app/assets/images/#{filename}", "not a image really" + app_file "app/assets/images/#{filename}", "not an image really" add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]" precompile! @@ -305,7 +299,7 @@ module ApplicationTests require "#{app_path}/config/environment" get "/assets/#{URI.parser.escape(asset_path)}" - assert_match "not a image really", last_response.body + assert_match "not an image really", last_response.body assert_file_exists("#{app_path}/public/assets/#{asset_path}") end @@ -341,6 +335,8 @@ module ApplicationTests end RUBY + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" class ::OmgController < ActionController::Base @@ -365,6 +361,8 @@ module ApplicationTests app_file "app/assets/javascripts/demo.js", "alert();" + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" get "/assets/demo.js" @@ -394,7 +392,6 @@ module ApplicationTests app_file "app/assets/javascripts/application.js", "//= require_tree ." app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>" - add_to_config "config.assets.digest = false" precompile! assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first) end @@ -414,7 +411,6 @@ module ApplicationTests test "digested assets are not mistakenly removed" do app_file "app/assets/application.js", "alert();" add_to_config "config.assets.compile = true" - add_to_config "config.assets.digest = true" precompile! @@ -437,6 +433,7 @@ module ApplicationTests test "asset urls should use the request's protocol by default" do app_with_assets_in_view add_to_config "config.asset_host = 'example.com'" + add_to_env_config "development", "config.assets.digest = false" require "#{app_path}/config/environment" class ::PostsController < ActionController::Base; end @@ -448,23 +445,24 @@ module ApplicationTests test "asset urls should be protocol-relative if no request is in scope" do app_file "app/assets/images/rails.png", "notreallyapng" - app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";' - add_to_config "config.assets.precompile = %w{image_loader.js}" + app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';" + add_to_config "config.assets.precompile = %w{rails.png image_loader.js}" add_to_config "config.asset_host = 'example.com'" + add_to_env_config "development", "config.assets.digest = false" precompile! - assert_match 'src="//example.com/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) + assert_match "src='//example.com/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) end test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri" app_file "app/assets/images/rails.png", "notreallyapng" - - app_file "app/assets/javascripts/app.js.erb", 'var src="<%= image_path("rails.png") %>";' - add_to_config "config.assets.precompile = %w{app.js}" + app_file "app/assets/javascripts/app.js.erb", "var src='<%= image_path('rails.png') %>';" + add_to_config "config.assets.precompile = %w{rails.png app.js}" + add_to_env_config "development", "config.assets.digest = false" precompile! - assert_match 'src="/sub/uri/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/app-*.js"].first) + assert_match "src='/sub/uri/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/app-*.js"].first) end test "assets:cache:clean should clean cache" do diff --git a/railties/test/application/configuration/base_test.rb b/railties/test/application/configuration/base_test.rb new file mode 100644 index 0000000000..d6a82b139d --- /dev/null +++ b/railties/test/application/configuration/base_test.rb @@ -0,0 +1,37 @@ +require 'isolation/abstract_unit' +require 'rack/test' +require 'env_helpers' + +module ApplicationTests + module ConfigurationTests + class BaseTest < ActiveSupport::TestCase + def setup + build_app + boot_rails + FileUtils.rm_rf("#{app_path}/config/environments") + end + + def teardown + teardown_app + FileUtils.rm_rf(new_app) if File.directory?(new_app) + end + + private + def new_app + File.expand_path("#{app_path}/../new_app") + end + + def copy_app + FileUtils.cp_r(app_path, new_app) + end + + def app + @app ||= Rails.application + end + + def require_environment + require "#{app_path}/config/environment" + end + end + end +end
\ No newline at end of file diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb new file mode 100644 index 0000000000..f8d22f6d97 --- /dev/null +++ b/railties/test/application/configuration/custom_test.rb @@ -0,0 +1,22 @@ +require 'application/configuration/base_test' + +class ApplicationTests::ConfigurationTests::CustomTest < ApplicationTests::ConfigurationTests::BaseTest + test 'access custom configuration point' do + add_to_config <<-RUBY + config.x.payment_processing.schedule = :daily + config.x.payment_processing.retries = 3 + config.x.super_debugger = true + config.x.hyper_debugger = false + config.x.nil_debugger = nil + RUBY + require_environment + + x = Rails.configuration.x + assert_equal :daily, x.payment_processing.schedule + assert_equal 3, x.payment_processing.retries + assert_equal true, x.super_debugger + assert_equal false, x.hyper_debugger + assert_equal nil, x.nil_debugger + assert_nil x.i_do_not_exist.zomg + end +end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index c51488e0e1..f8b4ee30d8 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -8,6 +8,12 @@ end class ::MyOtherMailInterceptor < ::MyMailInterceptor; end +class ::MyPreviewMailInterceptor + def self.previewing_email(email); email; end +end + +class ::MyOtherPreviewMailInterceptor < ::MyPreviewMailInterceptor; end + class ::MyMailObserver def self.delivered_email(email); email; end end @@ -60,13 +66,25 @@ module ApplicationTests config.action_dispatch.show_exceptions = true RUBY + app_file 'db/migrate/20140708012246_create_user.rb', <<-RUBY + class CreateUser < ActiveRecord::Migration + def change + create_table :users + end + end + RUBY + require "#{app_path}/config/environment" - ActiveRecord::Migrator.stubs(:needs_migration?).returns(true) - ActiveRecord::NullMigration.any_instance.stubs(:mtime).returns(1) - get "/foo" - assert_equal 500, last_response.status - assert_match "ActiveRecord::PendingMigrationError", last_response.body + ActiveRecord::Migrator.migrations_paths = ["#{app_path}/db/migrate"] + + begin + get "/foo" + assert_equal 500, last_response.status + assert_match "ActiveRecord::PendingMigrationError", last_response.body + ensure + ActiveRecord::Migrator.migrations_paths = nil + end end test "Rails.groups returns available groups" do @@ -100,7 +118,7 @@ module ApplicationTests test "Rails::Application responds to paths" do require "#{app_path}/config/environment" assert_respond_to AppTemplate::Application, :paths - assert_equal AppTemplate::Application.paths["app/views"].expanded, ["#{app_path}/app/views"] + assert_equal ["#{app_path}/app/views"], AppTemplate::Application.paths["app/views"].expanded end test "the application root is set correctly" do @@ -250,7 +268,7 @@ module ApplicationTests test "Use key_generator when secret_key_base is set" do make_basic_app do |app| - app.config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' app.config.session_store :disabled end @@ -268,6 +286,82 @@ module ApplicationTests assert_equal 'some_value', verifier.verify(last_response.body) end + test "application verifier can be used in the entire application" do + make_basic_app do |app| + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.config.session_store :disabled + end + + message = app.message_verifier(:sensitive_value).generate("some_value") + + assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message) + + secret = app.key_generator.generate_key('sensitive_value') + verifier = ActiveSupport::MessageVerifier.new(secret) + assert_equal 'some_value', verifier.verify(message) + end + + test "application verifier can build different verifiers" do + make_basic_app do |app| + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.config.session_store :disabled + end + + default_verifier = app.message_verifier(:sensitive_value) + text_verifier = app.message_verifier(:text) + + message = text_verifier.generate('some_value') + + assert_equal 'some_value', text_verifier.verify(message) + assert_raises ActiveSupport::MessageVerifier::InvalidSignature do + default_verifier.verify(message) + end + + assert_equal default_verifier.object_id, app.message_verifier(:sensitive_value).object_id + assert_not_equal default_verifier.object_id, text_verifier.object_id + end + + test "secrets.secret_key_base is used when config/secrets.yml is present" do + app_file 'config/secrets.yml', <<-YAML + development: + secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 + YAML + + require "#{app_path}/config/environment" + assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + end + + test "secret_key_base is copied from config to secrets when not set" do + remove_file "config/secrets.yml" + app_file 'config/initializers/secret_token.rb', <<-RUBY + Rails.application.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c3" + RUBY + + require "#{app_path}/config/environment" + assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + end + + test "custom secrets saved in config/secrets.yml are loaded in app secrets" do + app_file 'config/secrets.yml', <<-YAML + development: + secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 + aws_access_key_id: myamazonaccesskeyid + aws_secret_access_key: myamazonsecretaccesskey + YAML + + require "#{app_path}/config/environment" + assert_equal 'myamazonaccesskeyid', app.secrets.aws_access_key_id + assert_equal 'myamazonsecretaccesskey', app.secrets.aws_secret_access_key + end + + test "blank config/secrets.yml does not crash the loading process" do + app_file 'config/secrets.yml', <<-YAML + YAML + require "#{app_path}/config/environment" + + assert_nil app.secrets.not_defined + end + test "protect from forgery is the default in a new app" do make_basic_app @@ -284,12 +378,14 @@ module ApplicationTests test "default method for update can be changed" do app_file 'app/models/post.rb', <<-RUBY class Post - extend ActiveModel::Naming + include ActiveModel::Model def to_key; [1]; end def persisted?; true; end end RUBY + token = "cf50faa3fe97702ca1ae" + app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ApplicationController def show @@ -299,6 +395,10 @@ module ApplicationTests def update render text: "update" end + + private + + def form_authenticity_token; token; end # stub the authenticy token end RUBY @@ -310,8 +410,6 @@ module ApplicationTests require "#{app_path}/config/environment" - token = "cf50faa3fe97702ca1ae" - PostsController.any_instance.stubs(:form_authenticity_token).returns(token) params = {authenticity_token: token} get "/posts/1" @@ -342,7 +440,7 @@ module ApplicationTests end get "/" - assert last_response.body =~ /_xsrf_token_here/ + assert_match "_xsrf_token_here", last_response.body end test "sets ActionDispatch.test_app" do @@ -384,6 +482,32 @@ module ApplicationTests assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") end + test "registers preview interceptors with ActionMailer" do + add_to_config <<-RUBY + config.action_mailer.preview_interceptors = MyPreviewMailInterceptor + RUBY + + require "#{app_path}/config/environment" + require "mail" + + _ = ActionMailer::Base + + assert_equal [::MyPreviewMailInterceptor], ActionMailer::Base.preview_interceptors + end + + test "registers multiple preview interceptors with ActionMailer" do + add_to_config <<-RUBY + config.action_mailer.preview_interceptors = [MyPreviewMailInterceptor, "MyOtherPreviewMailInterceptor"] + RUBY + + require "#{app_path}/config/environment" + require "mail" + + _ = ActionMailer::Base + + assert_equal [MyPreviewMailInterceptor, MyOtherPreviewMailInterceptor], ActionMailer::Base.preview_interceptors + end + test "registers observers with ActionMailer" do add_to_config <<-RUBY config.action_mailer.observers = MyMailObserver @@ -413,7 +537,7 @@ module ApplicationTests test "valid timezone is setup correctly" do add_to_config <<-RUBY config.root = "#{app_path}" - config.time_zone = "Wellington" + config.time_zone = "Wellington" RUBY require "#{app_path}/config/environment" @@ -424,7 +548,7 @@ module ApplicationTests test "raises when an invalid timezone is defined in the config" do add_to_config <<-RUBY config.root = "#{app_path}" - config.time_zone = "That big hill over yonder hill" + config.time_zone = "That big hill over yonder hill" RUBY assert_raise(ArgumentError) do @@ -435,7 +559,7 @@ module ApplicationTests test "valid beginning of week is setup correctly" do add_to_config <<-RUBY config.root = "#{app_path}" - config.beginning_of_week = :wednesday + config.beginning_of_week = :wednesday RUBY require "#{app_path}/config/environment" @@ -446,7 +570,7 @@ module ApplicationTests test "raises when an invalid beginning of week is defined in the config" do add_to_config <<-RUBY config.root = "#{app_path}" - config.beginning_of_week = :invalid + config.beginning_of_week = :invalid RUBY assert_raise(ArgumentError) do @@ -459,7 +583,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert ActionView::Resolver.caching? + assert_equal true, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading without cache_classes default" do @@ -467,7 +591,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert !ActionView::Resolver.caching? + assert_equal false, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading = false" do @@ -478,7 +602,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert !ActionView::Resolver.caching? + assert_equal false, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading = true" do @@ -489,7 +613,21 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert ActionView::Resolver.caching? + assert_equal true, ActionView::Resolver.caching? + end + + test "config.action_view.cache_template_loading with cache_classes in an environment" do + build_app(initializers: true) + add_to_env_config "development", "config.cache_classes = false" + + # These requires are to emulate an engine loading Action View before the application + require 'action_view' + require 'action_view/railtie' + require 'action_view/base' + + require "#{app_path}/config/environment" + + assert_equal false, ActionView::Resolver.caching? end test "config.action_dispatch.show_exceptions is sent in env" do @@ -592,6 +730,44 @@ module ApplicationTests assert_match "We're sorry, but something went wrong", last_response.body end + test "config.action_controller.always_permitted_parameters are: controller, action by default" do + require "#{app_path}/config/environment" + assert_equal %w(controller action), ActionController::Parameters.always_permitted_parameters + end + + test "config.action_controller.always_permitted_parameters = ['controller', 'action', 'format']" do + add_to_config <<-RUBY + config.action_controller.always_permitted_parameters = %w( controller action format ) + RUBY + require "#{app_path}/config/environment" + assert_equal %w( controller action format ), ActionController::Parameters.always_permitted_parameters + end + + test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exeception" do + app_file 'app/controllers/posts_controller.rb', <<-RUBY + class PostsController < ActionController::Base + def create + render text: params.permit(post: [:title]) + end + end + RUBY + + add_to_config <<-RUBY + routes.prepend do + resources :posts + end + config.action_controller.always_permitted_parameters = %w( controller action format ) + config.action_controller.action_on_unpermitted_parameters = :raise + RUBY + + require "#{app_path}/config/environment" + + assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters + + post "/posts", {post: {"title" =>"zomg"}, format: "json"} + assert_equal 200, last_response.status + end + test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do ENV["RAILS_ENV"] = "development" @@ -679,5 +855,246 @@ module ApplicationTests end assert_equal Logger::INFO, Rails.logger.level end + + test "respond_to? accepts include_private" do + make_basic_app + + assert_not Rails.configuration.respond_to?(:method_missing) + assert Rails.configuration.respond_to?(:method_missing, true) + end + + test "config.active_record.dump_schema_after_migration is false on production" do + build_app + ENV["RAILS_ENV"] = "production" + + require "#{app_path}/config/environment" + + assert_not ActiveRecord::Base.dump_schema_after_migration + end + + test "config.active_record.dump_schema_after_migration is true by default on development" do + ENV["RAILS_ENV"] = "development" + + require "#{app_path}/config/environment" + + assert ActiveRecord::Base.dump_schema_after_migration + end + + test "config.annotations wrapping SourceAnnotationExtractor::Annotation class" do + make_basic_app do |app| + app.config.annotations.register_extensions("coffee") do |tag| + /#\s*(#{tag}):?\s*(.*)$/ + end + end + + assert_not_nil SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/] + end + + test "rake_tasks block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + rake_tasks do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + require 'rake' + require 'rake/testtask' + require 'rdoc/task' + + Rails.application.load_tasks + assert Rails.configuration.ran_block + end + + test "generators block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + generators do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_generators + assert Rails.configuration.ran_block + end + + test "console block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + console do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_console + assert Rails.configuration.ran_block + end + + test "runner block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + runner do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_runner + assert Rails.configuration.ran_block + end + + test "loading the first existing database configuration available" do + app_file 'config/environments/development.rb', <<-RUBY + + Rails.application.configure do + config.paths.add 'config/database', with: 'config/nonexistant.yml' + config.paths['config/database'] << 'config/database.yml' + end + RUBY + + require "#{app_path}/config/environment" + + assert_kind_of Hash, Rails.application.config.database_configuration + end + + test 'raises with proper error message if no database configuration found' do + FileUtils.rm("#{app_path}/config/database.yml") + require "#{app_path}/config/environment" + err = assert_raises RuntimeError do + Rails.application.config.database_configuration + end + assert_match 'config/database', err.message + end + + test 'config.action_mailer.show_previews defaults to true in development' do + Rails.env = "development" + require "#{app_path}/config/environment" + + assert Rails.application.config.action_mailer.show_previews + end + + test 'config.action_mailer.show_previews defaults to false in production' do + Rails.env = "production" + require "#{app_path}/config/environment" + + assert_equal false, Rails.application.config.action_mailer.show_previews + end + + test 'config.action_mailer.show_previews can be set in the configuration file' do + Rails.env = "production" + add_to_config <<-RUBY + config.action_mailer.show_previews = true + RUBY + require "#{app_path}/config/environment" + + assert_equal true, Rails.application.config.action_mailer.show_previews + end + + test "config_for loads custom configuration from yaml files" do + app_file 'config/custom.yml', <<-RUBY + development: + key: 'custom key' + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + require "#{app_path}/config/environment" + + assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + end + + test "config_for raises an exception if the file does not exist" do + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + exception = assert_raises(RuntimeError) do + require "#{app_path}/config/environment" + end + + assert_equal "Could not load configuration. No such file - #{app_path}/config/custom.yml", exception.message + end + + test "config_for without the environment configured returns an empty hash" do + app_file 'config/custom.yml', <<-RUBY + test: + key: 'custom key' + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal({}, Rails.application.config.my_custom_config) + end + + test "config_for with empty file returns an empty hash" do + app_file 'config/custom.yml', <<-RUBY + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal({}, Rails.application.config.my_custom_config) + end + + test "config_for containing ERB tags should evaluate" do + app_file 'config/custom.yml', <<-RUBY + development: + key: <%= 'custom key' %> + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + end + + test "config_for with syntax error show a more descritive exception" do + app_file 'config/custom.yml', <<-RUBY + development: + key: foo: + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + exception = assert_raises(RuntimeError) do + require "#{app_path}/config/environment" + end + + assert_match 'YAML syntax error occurred while parsing', exception.message + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 83104acf3c..2d45c9b53f 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -35,8 +35,8 @@ module ApplicationTests require "#{app_path}/config/environment" expanded_path = File.expand_path("app/views", app_path) - assert_equal ActionController::Base.view_paths[0].to_s, expanded_path - assert_equal ActionMailer::Base.view_paths[0].to_s, expanded_path + assert_equal expanded_path, ActionController::Base.view_paths[0].to_s + assert_equal expanded_path, ActionMailer::Base.view_paths[0].to_s end test "allows me to configure default url options for ActionMailer" do @@ -50,7 +50,7 @@ module ApplicationTests assert_equal "test.rails", ActionMailer::Base.default_url_options[:host] end - test "does not include url helpers as action methods" do + test "includes url helpers as action methods" do app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo @@ -66,8 +66,8 @@ module ApplicationTests require "#{app_path}/config/environment" assert Foo.method_defined?(:foo_path) + assert Foo.method_defined?(:foo_url) assert Foo.method_defined?(:main_app) - assert_equal Set.new(["notify"]), Foo.action_methods end test "allows to not load all helpers for controllers" do @@ -217,7 +217,7 @@ module ApplicationTests orig_database_url = ENV.delete("DATABASE_URL") orig_rails_env, Rails.env = Rails.env, 'development' database_url_db_name = "db/database_url_db.sqlite3" - ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 97df073ec7..9ee54796a4 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -183,5 +183,34 @@ en: load_app assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en] end + + test "disable config.i18n.enforce_available_locales" do + add_to_config <<-RUBY + config.i18n.enforce_available_locales = false + config.i18n.default_locale = :fr + RUBY + + load_app + assert_equal false, I18n.enforce_available_locales + + assert_nothing_raised do + I18n.locale = :es + end + end + + test "default config.i18n.enforce_available_locales does not override I18n.enforce_available_locales" do + I18n.enforce_available_locales = false + + add_to_config <<-RUBY + config.i18n.default_locale = :fr + RUBY + + load_app + assert_equal false, I18n.enforce_available_locales + + assert_nothing_raised do + I18n.locale = :es + end + end end end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index b36628ee37..cd05956356 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -71,6 +71,20 @@ module ApplicationTests assert Zoo end + test "eager loading accepts Pathnames" do + app_file "lib/foo.rb", <<-RUBY + module Foo; end + RUBY + + add_to_config <<-RUBY + config.eager_load = true + config.eager_load_paths << Pathname.new("#{app_path}/lib") + RUBY + + require "#{app_path}/config/environment" + assert Foo + end + test "load environment with global" do $initialize_test_set_from_env = nil app_file "config/environments/development.rb", <<-RUBY diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb index baae6fd928..95655b74cf 100644 --- a/railties/test/application/initializers/notifications_test.rb +++ b/railties/test/application/initializers/notifications_test.rb @@ -39,5 +39,18 @@ module ApplicationTests assert_equal 1, logger.logged(:debug).size assert_match(/SHOW tables/, logger.logged(:debug).last) end + + test 'rails load_config_initializer event is instrumented' do + app_file 'config/initializers/foo.rb', '' + + events = [] + callback = ->(*_) { events << _ } + ActiveSupport::Notifications.subscribed(callback, 'load_config_initializer.railties') do + app + end + + assert_equal %w[load_config_initializer.railties], events.map(&:first) + assert_includes events.first.last[:initializer], 'config/initializers/foo.rb' + end end end diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb new file mode 100644 index 0000000000..55e917c3ec --- /dev/null +++ b/railties/test/application/mailer_previews_test.rb @@ -0,0 +1,494 @@ +require 'isolation/abstract_unit' +require 'rack/test' +module ApplicationTests + class MailerPreviewsTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + boot_rails + end + + def teardown + teardown_app + end + + test "/rails/mailers is accessible in development" do + app("development") + get "/rails/mailers" + assert_equal 200, last_response.status + end + + test "/rails/mailers is not accessible in production" do + app("production") + get "/rails/mailers" + assert_equal 404, last_response.status + end + + test "/rails/mailers is accessible with correct configuraiton" do + add_to_config "config.action_mailer.show_previews = true" + app("production") + get "/rails/mailers" + assert_equal 200, last_response.status + end + + test "/rails/mailers is not accessible with show_previews = false" do + add_to_config "config.action_mailer.show_previews = false" + app("development") + get "/rails/mailers" + assert_equal 404, last_response.status + end + + test "mailer previews are loaded from the default preview_path" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + end + + test "mailer previews are loaded from a custom preview_path" do + add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + end + + test "mailer previews are reloaded across requests" do + app('development') + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + remove_file 'test/mailers/previews/notifier_preview.rb' + sleep(1) + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + end + + test "mailer preview actions are added and removed" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + + def bar + mail to: "to@example.net" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + text_template 'notifier/bar', <<-RUBY + Goodbye, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + + def bar + Notifier.bar + end + end + RUBY + + sleep(1) + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + remove_file 'app/views/notifier/bar.text.erb' + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + sleep(1) + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + end + + test "mailer previews are reloaded from a custom preview_path" do + add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" + + app('development') + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + remove_file 'lib/mailer_previews/notifier_preview.rb' + sleep(1) + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + end + + test "mailer preview not found" do + app('development') + get "/rails/mailers/notifier" + assert last_response.not_found? + assert_match "Mailer preview 'notifier' not found", last_response.body + end + + test "mailer preview email not found" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/bar" + assert last_response.not_found? + assert_match "Email 'bar' not found in NotifierPreview", last_response.body + end + + test "mailer preview email part not found" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo?part=text%2Fhtml" + assert last_response.not_found? + assert_match "Email part 'text/html' not found in NotifierPreview#foo", last_response.body + end + + test "message header uses full display names" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "Ruby on Rails <core@rubyonrails.org>" + + def foo + mail to: "Andrew White <andyw@pixeltrix.co.uk>", + cc: "David Heinemeier Hansson <david@heinemeierhansson.com>" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo" + assert_equal 200, last_response.status + assert_match "Ruby on Rails <core@rubyonrails.org>", last_response.body + assert_match "Andrew White <andyw@pixeltrix.co.uk>", last_response.body + assert_match "David Heinemeier Hansson <david@heinemeierhansson.com>", last_response.body + end + + test "part menu selects correct option" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + html_template 'notifier/foo', <<-RUBY + <p>Hello, World!</p> + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo.html" + assert_equal 200, last_response.status + assert_match '<option selected value="?part=text%2Fhtml">View as HTML email</option>', last_response.body + + get "/rails/mailers/notifier/foo.txt" + assert_equal 200, last_response.status + assert_match '<option selected value="?part=text%2Fplain">View as plain-text email</option>', last_response.body + end + + test "*_path helpers emit a deprecation" do + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index' + end + RUBY + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def path_in_view + mail to: "to@example.org" + end + + def path_in_mailer + @url = foo_path + mail to: "to@example.org" + end + end + RUBY + + html_template 'notifier/path_in_view', "<%= link_to 'foo', foo_path %>" + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def path_in_view + Notifier.path_in_view + end + + def path_in_mailer + Notifier.path_in_mailer + end + end + RUBY + + app('development') + + assert_deprecated do + get "/rails/mailers/notifier/path_in_view.html" + assert_equal 200, last_response.status + end + + html_template 'notifier/path_in_mailer', "No ERB in here" + + assert_deprecated do + get "/rails/mailers/notifier/path_in_mailer.html" + assert_equal 200, last_response.status + end + end + + private + def build_app + super + app_file "config/routes.rb", "Rails.application.routes.draw do; end" + end + + def mailer(name, contents) + app_file("app/mailers/#{name}.rb", contents) + end + + def mailer_preview(name, contents) + app_file("test/mailers/previews/#{name}_preview.rb", contents) + end + + def html_template(name, contents) + app_file("app/views/#{name}.html.erb", contents) + end + + def text_template(name, contents) + app_file("app/views/#{name}.text.erb", contents) + end + end +end diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 91c5807379..97d5b5c698 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -1,3 +1,4 @@ +require 'ipaddr' require 'isolation/abstract_unit' require 'active_support/key_generator' @@ -33,6 +34,16 @@ module ApplicationTests end end + test "works with both headers individually" do + make_basic_app + assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_equal "1.1.1.1", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1") + end + assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_equal "1.1.1.2", remote_ip("HTTP_CLIENT_IP" => "1.1.1.2") + end + end + test "can disable IP spoofing check" do make_basic_app do |app| app.config.action_dispatch.ip_spoofing_check = false @@ -43,12 +54,25 @@ module ApplicationTests end end + test "remote_ip works with HTTP_X_FORWARDED_FOR" do + make_basic_app + assert_equal "4.2.42.42", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42") + end + test "the user can set trusted proxies" do make_basic_app do |app| app.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/ end - assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1") + assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42") + end + + test "the user can set trusted proxies with an IPAddr argument" do + make_basic_app do |app| + app.config.action_dispatch.trusted_proxies = IPAddr.new('4.2.42.0/24') + end + + assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "10.0.0.0,4.2.42.42") end end end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 14a56176f5..31a64c2f5a 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -318,7 +318,7 @@ module ApplicationTests add_to_config <<-RUBY config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - config.secret_key_base = nil + secrets.secret_key_base = nil RUBY require "#{app_path}/config/environment" diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 31a35a09bb..a905598d80 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -61,7 +61,7 @@ module ApplicationTests boot! - assert_equal "Rack::Cache", middleware.first + assert middleware.include?("Rack::Cache") end test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do @@ -83,7 +83,7 @@ module ApplicationTests add_to_config "config.ssl_options = { host: 'example.com' }" boot! - assert_equal Rails.application.middleware.first.args, [{host: 'example.com'}] + assert_equal [{host: 'example.com'}], Rails.application.middleware.first.args end test "removing Active Record omits its middleware" do @@ -144,6 +144,12 @@ module ApplicationTests assert_equal "Rack::Config", middleware.second end + test 'unshift middleware' do + add_to_config 'config.middleware.unshift Rack::Config' + boot! + assert_equal 'Rack::Config', middleware.first + end + test "Rails.cache does not respond to middleware" do add_to_config "config.cache_store = :memory_store" boot! @@ -182,7 +188,7 @@ module ApplicationTests end end - etag = "5af83e3196bf99f440f31f2e1a6c9afe".inspect + etag = "W/" + "5af83e3196bf99f440f31f2e1a6c9afe".inspect get "/" assert_equal 200, last_response.status diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index 03c343c475..9ebf163671 100644 --- a/railties/test/application/multiple_applications_test.rb +++ b/railties/test/application/multiple_applications_test.rb @@ -21,6 +21,12 @@ module ApplicationTests assert_equal Rails.application.config.secret_key_base, clone.config.secret_key_base, "The base secret key on the config should be the same" end + def test_inheriting_multiple_times_from_application + new_application_class = Class.new(Rails::Application) + + assert_not_equal Rails.application.object_id, new_application_class.instance.object_id + end + def test_initialization_of_multiple_copies_of_same_application application1 = AppTemplate::Application.new application2 = AppTemplate::Application.new @@ -30,23 +36,23 @@ module ApplicationTests end def test_initialization_of_application_with_previous_config - application1 = AppTemplate::Application.new(config: Rails.application.config) - application2 = AppTemplate::Application.new + application1 = AppTemplate::Application.create(config: Rails.application.config) + application2 = AppTemplate::Application.create assert_equal Rails.application.config, application1.config, "Creating a new application while setting an initial config should result in the same config" assert_not_equal Rails.application.config, application2.config, "New applications without setting an initial config should not have the same config" end def test_initialization_of_application_with_previous_railties - application1 = AppTemplate::Application.new(railties: Rails.application.railties) - application2 = AppTemplate::Application.new + application1 = AppTemplate::Application.create(railties: Rails.application.railties) + application2 = AppTemplate::Application.create assert_equal Rails.application.railties, application1.railties assert_not_equal Rails.application.railties, application2.railties end def test_initialize_new_application_with_all_previous_initialization_variables - application1 = AppTemplate::Application.new( + application1 = AppTemplate::Application.create( config: Rails.application.config, railties: Rails.application.railties, routes_reloader: Rails.application.routes_reloader, @@ -66,26 +72,26 @@ module ApplicationTests end def test_rake_tasks_defined_on_different_applications_go_to_the_same_class - $run_count = 0 + run_count = 0 application1 = AppTemplate::Application.new application1.rake_tasks do - $run_count += 1 + run_count += 1 end application2 = AppTemplate::Application.new application2.rake_tasks do - $run_count += 1 + run_count += 1 end require "#{app_path}/config/environment" - assert_equal 0, $run_count, "The count should stay at zero without any calls to the rake tasks" + assert_equal 0, run_count, "The count should stay at zero without any calls to the rake tasks" require 'rake' require 'rake/testtask' require 'rdoc/task' Rails.application.load_tasks - assert_equal 2, $run_count, "Calling a rake task should result in two increments to the count" + assert_equal 2, run_count, "Calling a rake task should result in two increments to the count" end def test_multiple_applications_can_be_initialized @@ -94,36 +100,56 @@ module ApplicationTests def test_initializers_run_on_different_applications_go_to_the_same_class application1 = AppTemplate::Application.new - $run_count = 0 + run_count = 0 AppTemplate::Application.initializer :init0 do - $run_count += 1 + run_count += 1 end application1.initializer :init1 do - $run_count += 1 + run_count += 1 end AppTemplate::Application.new.initializer :init2 do - $run_count += 1 + run_count += 1 end - assert_equal 0, $run_count, "Without loading the initializers, the count should be 0" + assert_equal 0, run_count, "Without loading the initializers, the count should be 0" - # Set config.eager_load to false so that a eager_load warning doesn't pop up + # Set config.eager_load to false so that an eager_load warning doesn't pop up AppTemplate::Application.new { config.eager_load = false }.initialize! - assert_equal 3, $run_count, "There should have been three initializers that incremented the count" + assert_equal 3, run_count, "There should have been three initializers that incremented the count" + end + + def test_consoles_run_on_different_applications_go_to_the_same_class + run_count = 0 + AppTemplate::Application.console { run_count += 1 } + AppTemplate::Application.new.console { run_count += 1 } + + assert_equal 0, run_count, "Without loading the consoles, the count should be 0" + Rails.application.load_console + assert_equal 2, run_count, "There should have been two consoles that increment the count" + end + + def test_generators_run_on_different_applications_go_to_the_same_class + run_count = 0 + AppTemplate::Application.generators { run_count += 1 } + AppTemplate::Application.new.generators { run_count += 1 } + + assert_equal 0, run_count, "Without loading the generators, the count should be 0" + Rails.application.load_generators + assert_equal 2, run_count, "There should have been two generators that increment the count" end def test_runners_run_on_different_applications_go_to_the_same_class - $run_count = 0 - AppTemplate::Application.runner { $run_count += 1 } - AppTemplate::Application.new.runner { $run_count += 1 } + run_count = 0 + AppTemplate::Application.runner { run_count += 1 } + AppTemplate::Application.new.runner { run_count += 1 } - assert_equal 0, $run_count, "Without loading the runners, the count should be 0" + assert_equal 0, run_count, "Without loading the runners, the count should be 0" Rails.application.load_runner - assert_equal 2, $run_count, "There should have been two runners that increment the count" + assert_equal 2, run_count, "There should have been two runners that increment the count" end def test_isolate_namespace_on_an_application diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb index 701843a6fd..0082ec9cd2 100644 --- a/railties/test/application/rack/logger_test.rb +++ b/railties/test/application/rack/logger_test.rb @@ -11,10 +11,12 @@ module ApplicationTests def setup build_app + add_to_config <<-RUBY + config.logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new + RUBY + require "#{app_path}/config/environment" super - @logger = MockLogger.new - Rails.stubs(:logger).returns(@logger) end def teardown @@ -23,7 +25,7 @@ module ApplicationTests end def logs - @logs ||= @logger.logged(:info).join("\n") + @logs ||= Rails.logger.logged(:info).join("\n") end test "logger logs proper HTTP GET verb and path" do diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 9e711f25bd..267469b6f5 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -1,4 +1,5 @@ require "isolation/abstract_unit" +require "active_support/core_ext/string/strip" module ApplicationTests module RakeTests @@ -20,62 +21,53 @@ module ApplicationTests end def set_database_url - ENV['DATABASE_URL'] = "sqlite3://:@localhost/#{database_url_db_name}" + ENV['DATABASE_URL'] = "sqlite3:#{database_url_db_name}" # ensure it's using the DATABASE_URL FileUtils.rm_rf("#{app_path}/config/database.yml") end - def expected - @expected ||= {} - end - - def db_create_and_drop + def db_create_and_drop(expected_database) Dir.chdir(app_path) do output = `bundle exec rake db:create` - assert_equal output, "" - assert File.exists?(expected[:database]) - assert_equal expected[:database], - ActiveRecord::Base.connection_config[:database] + assert_empty output + assert File.exist?(expected_database) + assert_equal expected_database, ActiveRecord::Base.connection_config[:database] output = `bundle exec rake db:drop` - assert_equal output, "" - assert !File.exists?(expected[:database]) + assert_empty output + assert !File.exist?(expected_database) end end test 'db:create and db:drop without database url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_create_and_drop - end + db_create_and_drop ActiveRecord::Base.configurations[Rails.env]['database'] + end test 'db:create and db:drop with database url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_create_and_drop + db_create_and_drop database_url_db_name end - def db_migrate_and_status + def db_migrate_and_status(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate` output = `bundle exec rake db:migrate:status` - assert_match(/database:\s+\S+#{expected[:database]}/, output) + assert_match(%r{database:\s+\S*#{Regexp.escape(expected_database)}}, output) assert_match(/up\s+\d{14}\s+Create books/, output) end end test 'db:migrate and db:migrate:status without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_migrate_and_status + db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:migrate and db:migrate:status with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_migrate_and_status + db_migrate_and_status database_url_db_name end def db_schema_dump @@ -96,12 +88,11 @@ module ApplicationTests db_schema_dump end - def db_fixtures_load + def db_fixtures_load(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate db:fixtures:load` - assert_match(/#{expected[:database]}/, - ActiveRecord::Base.connection_config[:database]) + assert_match expected_database, ActiveRecord::Base.connection_config[:database] require "#{app_path}/app/models/book" assert_equal 2, Book.count end @@ -109,43 +100,50 @@ module ApplicationTests test 'db:fixtures:load without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_fixtures_load + db_fixtures_load ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:fixtures:load with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_fixtures_load + db_fixtures_load database_url_db_name end - def db_structure_dump_and_load + def db_structure_dump_and_load(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate db:structure:dump` structure_dump = File.read("db/structure.sql") assert_match(/CREATE TABLE \"books\"/, structure_dump) - `bundle exec rake db:drop db:structure:load` - assert_match(/#{expected[:database]}/, - ActiveRecord::Base.connection_config[:database]) + `bundle exec rake environment db:drop db:structure:load` + assert_match expected_database, ActiveRecord::Base.connection_config[:database] require "#{app_path}/app/models/book" #if structure is not loaded correctly, exception would be raised - assert Book.count, 0 + assert_equal 0, Book.count end end test 'db:structure:dump and db:structure:load without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_structure_dump_and_load + db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:structure:dump and db:structure:load with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_structure_dump_and_load + db_structure_dump_and_load database_url_db_name + end + + test 'db:structure:dump does not dump schema information when no migrations are used' do + Dir.chdir(app_path) do + # create table without migrations + `bundle exec rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'` + + stderr_output = capture(:stderr) { `bundle exec rake db:structure:dump` } + assert_empty stderr_output + structure_dump = File.read("db/structure.sql") + assert_match(/CREATE TABLE \"posts\"/, structure_dump) + end end def db_test_load_structure @@ -153,12 +151,12 @@ module ApplicationTests `rails generate model book title:string; bundle exec rake db:migrate db:structure:dump db:test:load_structure` ActiveRecord::Base.configurations = Rails.application.config.database_configuration - ActiveRecord::Base.establish_connection 'test' + ActiveRecord::Base.establish_connection :test require "#{app_path}/app/models/book" #if structure is not loaded correctly, exception would be raised - assert Book.count, 0 - assert_match(/#{ActiveRecord::Base.configurations['test']['database']}/, - ActiveRecord::Base.connection_config[:database]) + assert_equal 0, Book.count + assert_match ActiveRecord::Base.configurations['test']['database'], + ActiveRecord::Base.connection_config[:database] end end @@ -166,6 +164,44 @@ module ApplicationTests require "#{app_path}/config/environment" db_test_load_structure end + + test 'db:test deprecation' do + require "#{app_path}/config/environment" + Dir.chdir(app_path) do + output = `bundle exec rake db:migrate db:test:prepare 2>&1` + assert_equal "WARNING: db:test:prepare is deprecated. The Rails test helper now maintains " \ + "your test schema automatically, see the release notes for details.\n", output + end + end + + test 'db:setup loads schema and seeds database' do + begin + @old_rails_env = ENV["RAILS_ENV"] + @old_rack_env = ENV["RACK_ENV"] + ENV.delete "RAILS_ENV" + ENV.delete "RACK_ENV" + + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: "1") do + create_table :users do |t| + t.string :name + end + end + RUBY + + app_file 'db/seeds.rb', <<-RUBY + puts ActiveRecord::Base.connection_config[:database] + RUBY + + Dir.chdir(app_path) do + database_path = `bundle exec rake db:setup` + assert_equal "development.sqlite3", File.basename(database_path.strip) + end + ensure + ENV["RAILS_ENV"] = @old_rails_env + ENV["RACK_ENV"] = @old_rack_env + end + end end end end diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb index 33c753868c..a3819b93b2 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -58,7 +58,7 @@ module ApplicationTests end test 'migration status when schema migrations table is not present' do - output = Dir.chdir(app_path){ `rake db:migrate:status` } + output = Dir.chdir(app_path){ `rake db:migrate:status 2>&1` } assert_equal "Schema migrations table does not exist yet.\n", output end @@ -153,6 +153,52 @@ module ApplicationTests assert_match(/up\s+\d{3,}\s+Add email to users/, output) end end + + test 'schema generation when dump_schema_after_migration is set' do + add_to_config('config.active_record.dump_schema_after_migration = false') + + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + assert !File.exist?("db/schema.rb") + end + + add_to_config('config.active_record.dump_schema_after_migration = true') + + Dir.chdir(app_path) do + `rails generate model author name:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "authors"/, structure_dump) + end + end + + test 'default schema generation after migration' do + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "books"/, structure_dump) + end + end + + test 'test migration status migrated file is deleted' do + Dir.chdir(app_path) do + `rails generate model user username:string password:string; + rails generate migration add_email_to_users email:string; + rake db:migrate + rm db/migrate/*email*.rb` + + output = `rake db:migrate:status` + File.write('test.txt', output) + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output) + end + end end end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 9a92c5f6ff..95087bf29f 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -1,4 +1,5 @@ require "isolation/abstract_unit" +require 'rails/source_annotation_extractor' module ApplicationTests module RakeTests @@ -18,44 +19,27 @@ module ApplicationTests test 'notes finds notes for certain file_types' do app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>" - app_file "app/views/home/index.html.haml", "-# TODO: note in haml" - app_file "app/views/home/index.html.slim", "/ TODO: note in slim" - app_file "app/assets/javascripts/application.js.coffee", "# TODO: note in coffee" app_file "app/assets/javascripts/application.js", "// TODO: note in js" app_file "app/assets/stylesheets/application.css", "// TODO: note in css" - app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" - app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby" app_file "lib/tasks/task.rake", "# TODO: note in rake" + app_file 'app/views/home/index.html.builder', '# TODO: note in builder' + app_file 'config/locales/en.yml', '# TODO: note in yml' + app_file 'config/locales/en.yaml', '# TODO: note in yaml' + app_file "app/views/home/index.ruby", "# TODO: note in ruby" - boot_rails - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\](\s)/) - + run_rake_notes do |output, lines| assert_match(/note in erb/, output) - assert_match(/note in haml/, output) - assert_match(/note in slim/, output) - assert_match(/note in ruby/, output) - assert_match(/note in coffee/, output) assert_match(/note in js/, output) assert_match(/note in css/, output) - assert_match(/note in scss/, output) - assert_match(/note in sass/, output) assert_match(/note in rake/, output) + assert_match(/note in builder/, output) + assert_match(/note in yml/, output) + assert_match(/note in yaml/, output) + assert_match(/note in ruby/, output) - assert_equal 10, lines.size - - lines.each do |line| - assert_equal 4, line[0].size - assert_equal ' ', line[1] - end + assert_equal 9, lines.size + assert_equal [4], lines.map(&:size).uniq end end @@ -68,18 +52,7 @@ module ApplicationTests app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes do |output, lines| assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) assert_match(/note in db directory/, output) @@ -88,10 +61,7 @@ module ApplicationTests assert_no_match(/note in some_other directory/, output) assert_equal 5, lines.size - - lines.each do |line_number| - assert_equal 4, line_number.size - end + assert_equal [4], lines.map(&:size).uniq end end @@ -104,18 +74,7 @@ module ApplicationTests app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes "SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bundle exec rake notes" do |output, lines| assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) assert_match(/note in db directory/, output) @@ -125,10 +84,7 @@ module ApplicationTests assert_match(/note in some_other directory/, output) assert_equal 6, lines.size - - lines.each do |line_number| - assert_equal 4, line_number.size - end + assert_equal [4], lines.map(&:size).uniq end end @@ -146,32 +102,51 @@ module ApplicationTests end EOS - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes_custom` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes "bundle exec rake notes_custom" do |output, lines| assert_match(/\[FIXME\] note in lib directory/, output) assert_match(/\[TODO\] note in test directory/, output) assert_no_match(/OPTIMIZE/, output) assert_no_match(/note in app directory/, output) assert_equal 2, lines.size + assert_equal [4], lines.map(&:size).uniq + end + end - lines.each do |line_number| - assert_equal 4, line_number.size - end + test 'register a new extension' do + add_to_config %q{ config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } } + app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" + app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" + + run_rake_notes do |output, lines| + assert_match(/note in scss/, output) + assert_match(/note in sass/, output) + assert_equal 2, lines.size end end private + + def run_rake_notes(command = 'bundle exec rake notes') + boot_rails + load_tasks + + Dir.chdir(app_path) do + output = `#{command}` + lines = output.scan(/\[([0-9\s]+)\]\s/).flatten + + yield output, lines + end + end + + def load_tasks + require 'rake' + require 'rdoc/task' + require 'rake/testtask' + + Rails.application.load_tasks + end + def boot_rails super require "#{app_path}/config/environment" diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index c1cb1c1eba..e8c8de9f73 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -111,7 +111,7 @@ module ApplicationTests RUBY output = Dir.chdir(app_path){ `rake routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end def test_rake_routes_with_controller_environment @@ -124,7 +124,7 @@ module ApplicationTests ENV['CONTROLLER'] = 'cart' output = Dir.chdir(app_path){ `rake routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end def test_rake_routes_displays_message_when_no_routes_are_defined @@ -187,7 +187,7 @@ module ApplicationTests def test_scaffold_tests_pass_by_default output = Dir.chdir(app_path) do `rails generate scaffold user username:string password:string; - bundle exec rake db:migrate db:test:clone test` + bundle exec rake db:migrate test` end assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) @@ -197,7 +197,7 @@ module ApplicationTests def test_scaffold_with_references_columns_tests_pass_by_default output = Dir.chdir(app_path) do `rails generate scaffold LineItems product:references cart:belongs_to; - bundle exec rake db:migrate db:test:clone test` + bundle exec rake db:migrate test` end assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) @@ -208,7 +208,8 @@ module ApplicationTests add_to_config "config.active_record.schema_format = :sql" output = Dir.chdir(app_path) do `rails generate scaffold user username:string; - bundle exec rake db:migrate db:test:clone 2>&1 --trace` + bundle exec rake db:migrate; + bundle exec rake db:test:clone 2>&1 --trace` end assert_match(/Execute db:test:clone_structure/, output) end @@ -217,7 +218,8 @@ module ApplicationTests add_to_config "config.active_record.schema_format = :sql" output = Dir.chdir(app_path) do `rails generate scaffold user username:string; - bundle exec rake db:migrate db:test:prepare 2>&1 --trace` + bundle exec rake db:migrate; + bundle exec rake db:test:prepare 2>&1 --trace` end assert_match(/Execute db:test:load_structure/, output) end @@ -227,7 +229,7 @@ module ApplicationTests # ensure we have a schema_migrations table to dump `bundle exec rake db:migrate db:structure:dump DB_STRUCTURE=db/my_structure.sql` end - assert File.exists?(File.join(app_path, 'db', 'my_structure.sql')) + assert File.exist?(File.join(app_path, 'db', 'my_structure.sql')) end def test_rake_dump_structure_should_be_called_twice_when_migrate_redo @@ -248,26 +250,37 @@ module ApplicationTests rails generate model product name:string; bundle exec rake db:migrate db:schema:cache:dump` end - assert File.exists?(File.join(app_path, 'db', 'schema_cache.dump')) + assert File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) end def test_rake_clear_schema_cache Dir.chdir(app_path) do `bundle exec rake db:schema:cache:dump db:schema:cache:clear` end - assert !File.exists?(File.join(app_path, 'db', 'schema_cache.dump')) + assert !File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) end def test_copy_templates Dir.chdir(app_path) do `bundle exec rake rails:templates:copy` %w(controller mailer scaffold).each do |dir| - assert File.exists?(File.join(app_path, 'lib', 'templates', 'erb', dir)) + assert File.exist?(File.join(app_path, 'lib', 'templates', 'erb', dir)) end %w(controller helper scaffold_controller assets).each do |dir| - assert File.exists?(File.join(app_path, 'lib', 'templates', 'rails', dir)) + assert File.exist?(File.join(app_path, 'lib', 'templates', 'rails', dir)) end end end + + def test_template_load_initializers + app_file "config/initializers/dummy.rb", "puts 'Hello, World!'" + app_file "template.rb", "" + + output = Dir.chdir(app_path) do + `bundle exec rake rails:template LOCATION=template.rb` + end + + assert_match(/Hello, World!/, output) + end end end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 118f22995e..032b11a95f 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -109,6 +109,17 @@ module ApplicationTests end end + def test_run_jobs + create_test_file :jobs, 'foo_job' + create_test_file :jobs, 'bar_job' + create_test_file :models, 'foo' + run_test_jobs_command.tap do |output| + assert_match "FooJobTest", output + assert_match "BarJobTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + def test_run_functionals create_test_file :mailers, 'foo_mailer' create_test_file :controllers, 'bar_controller' @@ -132,11 +143,11 @@ module ApplicationTests end def test_run_all_suites - suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] + suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration, :jobs] suites.each { |suite| create_test_file suite, "foo_#{suite}" } run_test_command('') .tap do |output| suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output } - assert_match "7 runs, 7 assertions, 0 failures", output + assert_match "8 runs, 8 assertions, 0 failures", output end end @@ -245,7 +256,7 @@ module ApplicationTests def run_test_command(arguments = 'test/unit/test_test.rb') run_task ['test', arguments] end - %w{ mailers models helpers units controllers functionals integration }.each do |type| + %w{ mailers models helpers units controllers functionals integration jobs }.each do |type| define_method("run_test_#{type}_command") do run_task ["test:#{type}"] end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index c7ad2fba8f..c724c867ec 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -24,7 +24,7 @@ module ApplicationTests end RUBY - run_test_file 'unit/foo_test.rb' + assert_successful_test_run 'unit/foo_test.rb' end test "integration test" do @@ -49,19 +49,182 @@ module ApplicationTests end RUBY - run_test_file 'integration/posts_test.rb' + assert_successful_test_run 'integration/posts_test.rb' + end + + test "enable full backtraces on test failures" do + app_file 'test/unit/failing_test.rb', <<-RUBY + require 'test_helper' + + class FailingTest < ActiveSupport::TestCase + def test_failure + raise "fail" + end + end + RUBY + + output = run_test_file('unit/failing_test.rb', env: { "BACKTRACE" => "1" }) + assert_match %r{/app/test/unit/failing_test\.rb}, output + end + + test "ruby schema migrations" do + output = script('generate model user name:string') + version = output.match(/(\d+)_create_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon" + end + end + RUBY + app_file 'db/schema.rb', '' + + assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" + + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: #{version}) do + create_table :users do |t| + t.string :name + end + end + RUBY + + app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY + Rails.application.config.active_record.maintain_test_schema = false + RUBY + + assert_unsuccessful_run "models/user_test.rb", "Could not find table 'users'" + + File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" + + result = assert_successful_test_run('models/user_test.rb') + assert !result.include?("create_table(:users)") + end + + test "sql structure migrations" do + output = script('generate model user name:string') + version = output.match(/(\d+)_create_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon" + end + end + RUBY + + app_file 'db/structure.sql', '' + app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + Rails.application.config.active_record.schema_format = :sql + RUBY + + assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version}'); + SQL + + app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY + Rails.application.config.active_record.maintain_test_schema = false + RUBY + + assert_unsuccessful_run "models/user_test.rb", "Could not find table 'users'" + + File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" + + assert_successful_test_run('models/user_test.rb') + end + + test "sql structure migrations when adding column to existing table" do + output_1 = script('generate model user name:string') + version_1 = output_1.match(/(\d+)_create_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon" + end + end + RUBY + + app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + Rails.application.config.active_record.schema_format = :sql + RUBY + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version_1}'); + SQL + + assert_successful_test_run('models/user_test.rb') + + output_2 = script('generate migration add_email_to_users') + version_2 = output_2.match(/(\d+)_add_email_to_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon", email: "jon@doe.com" + end + end + RUBY + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version_1}'); + INSERT INTO schema_migrations (version) VALUES ('#{version_2}'); + SQL + + assert_successful_test_run('models/user_test.rb') end private - def run_test_file(name) - result = ruby '-Itest', "#{app_path}/test/#{name}" + def assert_unsuccessful_run(name, message) + result = run_test_file(name) + assert_not_equal 0, $?.to_i + assert result.include?(message) + result + end + + def assert_successful_test_run(name) + result = run_test_file(name) assert_equal 0, $?.to_i, result + result + end + + def run_test_file(name, options = {}) + ruby '-Itest', "#{app_path}/test/#{name}", options end def ruby(*args) + options = args.extract_options! + env = options.fetch(:env, {}) + env["RUBYLIB"] = $:.join(':') + Dir.chdir(app_path) do - `RUBYLIB='#{$:.join(':')}' #{Gem.ruby} #{args.join(' ')}` + `#{env_string(env)} #{Gem.ruby} #{args.join(' ')} 2>&1` end end + + def env_string(variables) + variables.map do |key, value| + "#{key}='#{value}'" + end.join " " + end end end diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 2767779719..efbc853d7b 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -12,6 +12,7 @@ module ApplicationTests boot_rails require "rails" require "action_controller/railtie" + require "action_view/railtie" class MyApp < Rails::Application config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index a34beaedb3..4aea3e980f 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -6,7 +6,13 @@ class Rails::ConsoleTest < ActiveSupport::TestCase include EnvHelpers class FakeConsole - def self.start; end + def self.started? + @started + end + + def self.start + @started = true + end end def test_sandbox_option @@ -19,37 +25,47 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert console.sandbox? end - def test_debugger_option - console = Rails::Console.new(app, parse_arguments(["--debugger"])) - assert console.debugger? - end - def test_no_options console = Rails::Console.new(app, parse_arguments([])) - assert !console.debugger? assert !console.sandbox? end def test_start - FakeConsole.expects(:start) start + + assert app.console.started? assert_match(/Loading \w+ environment \(Rails/, output) end - def test_start_with_debugger - rails_console = Rails::Console.new(app, parse_arguments(["--debugger"])) - rails_console.expects(:require_debugger).returns(nil) + def test_start_with_sandbox + start ["--sandbox"] + - silence_stream(STDOUT) { rails_console.start } + assert app.console.started? + assert app.sandbox + assert_match(/Loading \w+ environment in sandbox \(Rails/, output) end - def test_start_with_sandbox - app.expects(:sandbox=).with(true) - FakeConsole.expects(:start) + if RUBY_VERSION < '2.0.0' + def test_debugger_option + console = Rails::Console.new(app, parse_arguments(["--debugger"])) + assert console.debugger? + end - start ["--sandbox"] + def test_no_options_does_not_set_debugger_flag + console = Rails::Console.new(app, parse_arguments([])) + assert !console.debugger? + end - assert_match(/Loading \w+ environment in sandbox \(Rails/, output) + def test_start_with_debugger + stubbed_console = Class.new(Rails::Console) do + def require_debugger + end + end + + rails_console = stubbed_console.new(app, parse_arguments(["--debugger"])) + silence_stream(STDOUT) { rails_console.start } + end end def test_console_with_environment @@ -58,7 +74,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_defaults_to_IRB - app = build_app(console: nil) + app = build_app(nil) assert_equal IRB, Rails::Console.new(app).console end @@ -109,8 +125,12 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::Console.stubs(:available_environments).returns(['dev']) - options = Rails::Console.parse_arguments(['dev']) + stubbed_console = Class.new(Rails::Console) do + def available_environments + ['dev'] + end + end + options = stubbed_console.parse_arguments(['dev']) assert_match('dev', options[:environment]) end @@ -125,15 +145,29 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def app - @app ||= build_app(console: FakeConsole) + @app ||= build_app(FakeConsole) end - def build_app(config) - config = mock("config", config) - app = mock("app", config: config) - app.stubs(:sandbox=).returns(nil) - app.expects(:load_console) - app + def build_app(console) + mocked_console = Class.new do + attr_reader :sandbox, :console + + def initialize(console) + @console = console + end + + def config + self + end + + def sandbox=(arg) + @sandbox = arg + end + + def load_console + end + end + mocked_console.new(console) end def parse_arguments(args) diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index edb92b3aa2..a3cd1eb0ed 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -1,90 +1,149 @@ require 'abstract_unit' +require 'minitest/mock' require 'rails/commands/dbconsole' class Rails::DBConsoleTest < ActiveSupport::TestCase - def teardown - %w[PGUSER PGHOST PGPORT PGPASSWORD].each{|key| ENV.delete(key)} - end - def test_config - Rails::DBConsole.const_set(:APP_PATH, "erb") - app_config({}) - capture_abort { Rails::DBConsole.new.config } - assert aborted - assert_match(/No database is configured for the environment '\w+'/, output) + def setup + Rails::DBConsole.const_set('APP_PATH', 'rails/all') + end - app_config(test: "with_init") - assert_equal Rails::DBConsole.new.config, "with_init" + def teardown + Rails::DBConsole.send(:remove_const, 'APP_PATH') + %w[PGUSER PGHOST PGPORT PGPASSWORD DATABASE_URL].each{|key| ENV.delete(key)} + end + + def test_config_with_db_config_only + config_sample = { + "test"=> { + "adapter"=> "sqlite3", + "host"=> "localhost", + "port"=> "9000", + "database"=> "foo_test", + "user"=> "foo", + "password"=> "bar", + "pool"=> "5", + "timeout"=> "3000" + } + } + app_db_config(config_sample) do + assert_equal config_sample["test"], Rails::DBConsole.new.config + end + end - app_db_file("test:\n without_init") - assert_equal Rails::DBConsole.new.config, "without_init" + def test_config_with_no_db_config + app_db_config(nil) do + assert_raise(ActiveRecord::AdapterNotSpecified) { + Rails::DBConsole.new.config + } + end + end - app_db_file("test:\n <%= Rails.something_app_specific %>") - assert_equal Rails::DBConsole.new.config, "with_init" + def test_config_with_database_url_only + ENV['DATABASE_URL'] = 'postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000' + expected = { + "adapter" => "postgresql", + "host" => "localhost", + "port" => 9000, + "database" => "foo_test", + "username" => "foo", + "password" => "bar", + "pool" => "5", + "timeout" => "3000" + }.sort + + app_db_config(nil) do + assert_equal expected, Rails::DBConsole.new.config.sort + end + end - app_db_file("test:\n\ninvalid") - assert_equal Rails::DBConsole.new.config, "with_init" + def test_config_choose_database_url_if_exists + host = "database-url-host.com" + ENV['DATABASE_URL'] = "postgresql://foo:bar@#{host}:9000/foo_test?pool=5&timeout=3000" + sample_config = { + "test" => { + "adapter" => "postgresql", + "host" => "not-the-#{host}", + "port" => 9000, + "database" => "foo_test", + "username" => "foo", + "password" => "bar", + "pool" => "5", + "timeout" => "3000" + } + } + app_db_config(sample_config) do + assert_equal host, Rails::DBConsole.new.config["host"] + end end def test_env - assert_equal Rails::DBConsole.new.environment, "test" + assert_equal "test", Rails::DBConsole.new.environment ENV['RAILS_ENV'] = nil ENV['RACK_ENV'] = nil - Rails.stubs(:respond_to?).with(:env).returns(false) - assert_equal Rails::DBConsole.new.environment, "development" + Rails.stub(:respond_to?, false) do + assert_equal "development", Rails::DBConsole.new.environment - ENV['RACK_ENV'] = "rack_env" - assert_equal Rails::DBConsole.new.environment, "rack_env" + ENV['RACK_ENV'] = "rack_env" + assert_equal "rack_env", Rails::DBConsole.new.environment - ENV['RAILS_ENV'] = "rails_env" - assert_equal Rails::DBConsole.new.environment, "rails_env" + ENV['RAILS_ENV'] = "rails_env" + assert_equal "rails_env", Rails::DBConsole.new.environment + end ensure ENV['RAILS_ENV'] = "test" + ENV['RACK_ENV'] = nil end def test_rails_env_is_development_when_argument_is_dev - Rails::DBConsole.stubs(:available_environments).returns(['development', 'test']) - options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) - assert_match('development', options[:environment]) + dbconsole = Rails::DBConsole.new + + dbconsole.stub(:available_environments, ['development', 'test']) do + options = dbconsole.send(:parse_arguments, ['dev']) + assert_match('development', options[:environment]) + end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::DBConsole.stubs(:available_environments).returns(['dev']) - options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) - assert_match('dev', options[:environment]) + dbconsole = Rails::DBConsole.new + + dbconsole.stub(:available_environments, ['dev']) do + options = dbconsole.send(:parse_arguments, ['dev']) + assert_match('dev', options[:environment]) + end end def test_mysql - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], 'db') start(adapter: 'mysql', database: 'db') assert !aborted + assert_equal [%w[mysql mysql5], 'db'], dbconsole.find_cmd_and_exec_args end def test_mysql_full - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], '--host=locahost', '--port=1234', '--socket=socket', '--user=user', '--default-character-set=UTF-8', '-p', 'db') start(adapter: 'mysql', database: 'db', host: 'locahost', port: 1234, socket: 'socket', username: 'user', password: 'qwerty', encoding: 'UTF-8') assert !aborted + assert_equal [%w[mysql mysql5], '--host=locahost', '--port=1234', '--socket=socket', '--user=user', '--default-character-set=UTF-8', '-p', 'db'], dbconsole.find_cmd_and_exec_args end def test_mysql_include_password - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], '--user=user', '--password=qwerty', 'db') start({adapter: 'mysql', database: 'db', username: 'user', password: 'qwerty'}, ['-p']) assert !aborted + assert_equal [%w[mysql mysql5], '--user=user', '--password=qwerty', 'db'], dbconsole.find_cmd_and_exec_args end def test_postgresql - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start(adapter: 'postgresql', database: 'db') assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args end def test_postgresql_full - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start(adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3', host: 'host', port: 5432) assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args assert_equal 'user', ENV['PGUSER'] assert_equal 'host', ENV['PGHOST'] assert_equal '5432', ENV['PGPORT'] @@ -92,60 +151,60 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_postgresql_include_password - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start({adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3'}, ['-p']) assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args assert_equal 'user', ENV['PGUSER'] assert_equal 'q1w2e3', ENV['PGPASSWORD'] end def test_sqlite - dbconsole.expects(:find_cmd_and_exec).with('sqlite', 'db') start(adapter: 'sqlite', database: 'db') assert !aborted + assert_equal ['sqlite', 'db'], dbconsole.find_cmd_and_exec_args end def test_sqlite3 - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('db.sqlite3').to_s) start(adapter: 'sqlite3', database: 'db.sqlite3') assert !aborted + assert_equal ['sqlite3', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_mode - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-html', Rails.root.join('db.sqlite3').to_s) start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--mode', 'html']) assert !aborted + assert_equal ['sqlite3', '-html', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_header - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-header', Rails.root.join('db.sqlite3').to_s) start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--header']) + assert_equal ['sqlite3', '-header', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_absolute_path - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '/tmp/db.sqlite3') start(adapter: 'sqlite3', database: '/tmp/db.sqlite3') assert !aborted + assert_equal ['sqlite3', '/tmp/db.sqlite3'], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_without_defined_rails_root - Rails.stubs(:respond_to?) - Rails.expects(:respond_to?).with(:root).once.returns(false) - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('../config/db.sqlite3').to_s) - start(adapter: 'sqlite3', database: 'config/db.sqlite3') - assert !aborted + Rails.stub(:respond_to?, false) do + start(adapter: 'sqlite3', database: 'config/db.sqlite3') + assert !aborted + assert_equal ['sqlite3', Rails.root.join('../config/db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + end end def test_oracle - dbconsole.expects(:find_cmd_and_exec).with('sqlplus', 'user@db') start(adapter: 'oracle', database: 'db', username: 'user', password: 'secret') assert !aborted + assert_equal ['sqlplus', 'user@db'], dbconsole.find_cmd_and_exec_args end def test_oracle_include_password - dbconsole.expects(:find_cmd_and_exec).with('sqlplus', 'user/secret@db') start({adapter: 'oracle', database: 'db', username: 'user', password: 'secret'}, ['-p']) assert !aborted + assert_equal ['sqlplus', 'user/secret@db'], dbconsole.find_cmd_and_exec_args end def test_unknown_command_line_client @@ -177,13 +236,28 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private + def app_db_config(results) + Rails.application.config.stub(:database_configuration, results || {}) do + yield + end + end + def dbconsole - @dbconsole ||= Rails::DBConsole.new(nil) + @dbconsole ||= Class.new(Rails::DBConsole) do + attr_reader :find_cmd_and_exec_args + + def find_cmd_and_exec(*args) + @find_cmd_and_exec_args = args + end + end.new(nil) end def start(config = {}, argv = []) - dbconsole.stubs(config: config.stringify_keys, arguments: argv) - capture_abort { dbconsole.start } + dbconsole.stub(:config, config.stringify_keys) do + dbconsole.stub(:arguments, argv) do + capture_abort { dbconsole.start } + end + end end def capture_abort @@ -197,11 +271,4 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end end - def app_db_file(result) - IO.stubs(:read).with("config/database.yml").returns(result) - end - - def app_config(result) - Rails.application.config.stubs(:database_configuration).returns(result.stringify_keys) - end end diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index cb57b3c0cd..ba688f1e9e 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -27,16 +27,62 @@ class Rails::ServerTest < ActiveSupport::TestCase end def test_environment_with_rails_env - with_rails_env 'production' do - server = Rails::Server.new - assert_equal 'production', server.options[:environment] + with_rack_env nil do + with_rails_env 'production' do + server = Rails::Server.new + assert_equal 'production', server.options[:environment] + end end end def test_environment_with_rack_env - with_rack_env 'production' do - server = Rails::Server.new - assert_equal 'production', server.options[:environment] + with_rails_env nil do + with_rack_env 'production' do + server = Rails::Server.new + assert_equal 'production', server.options[:environment] + end + end + end + + def test_log_stdout + with_rack_env nil do + with_rails_env nil do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + + args = ["-e", "development"] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + + args = ["-e", "production"] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + + with_rack_env 'development' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + end + + with_rack_env 'production' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + end + + with_rails_env 'development' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + end + + with_rails_env 'production' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + end + end end end end diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index 2442cb995d..d5072614cf 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -1,3 +1,4 @@ +require 'active_support' require 'active_support/testing/autorun' require 'rails/configuration' require 'active_support/test_case' @@ -39,7 +40,7 @@ module Rails @stack.swap :foo @stack.delete :foo - mock = MiniTest::Mock.new + mock = Minitest::Mock.new mock.expect :send, nil, [:swap, :foo] mock.expect :send, nil, [:delete, :foo] @@ -50,7 +51,7 @@ module Rails private def assert_playback(msg_name, args) - mock = MiniTest::Mock.new + mock = Minitest::Mock.new mock.expect :send, nil, [msg_name, args] @stack.merge_into(mock) mock.verify diff --git a/railties/test/engine_test.rb b/railties/test/engine_test.rb index 7970913d21..f46fb748f5 100644 --- a/railties/test/engine_test.rb +++ b/railties/test/engine_test.rb @@ -11,4 +11,15 @@ class EngineTest < ActiveSupport::TestCase assert !engine.routes? end + + def test_application_can_be_subclassed + klass = Class.new(Rails::Application) do + attr_reader :hello + def initialize + @hello = "world" + super + end + end + assert_equal "world", klass.instance.hello + end end diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb index 6223c85bbf..330fe150ca 100644 --- a/railties/test/env_helpers.rb +++ b/railties/test/env_helpers.rb @@ -1,7 +1,10 @@ +require 'rails' + module EnvHelpers private def with_rails_env(env) + Rails.instance_variable_set :@_env, nil switch_env 'RAILS_ENV', env do switch_env 'RACK_ENV', nil do yield @@ -10,6 +13,7 @@ module EnvHelpers end def with_rack_env(env) + Rails.instance_variable_set :@_env, nil switch_env 'RACK_ENV', env do switch_env 'RAILS_ENV', nil do yield diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 0db40c1d32..2206e389b5 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' require 'env_helpers' +require 'mocha/setup' # FIXME: stop using mocha class ActionsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -41,13 +42,13 @@ class ActionsTest < Rails::Generators::TestCase def test_add_source_adds_source_to_gemfile run_generator action :add_source, 'http://gems.github.com' - assert_file 'Gemfile', /source "http:\/\/gems\.github\.com"/ + assert_file 'Gemfile', /source 'http:\/\/gems\.github\.com'/ end def test_gem_should_put_gem_dependency_in_gemfile run_generator action :gem, 'will-paginate' - assert_file 'Gemfile', /gem "will\-paginate"/ + assert_file 'Gemfile', /gem 'will\-paginate'/ end def test_gem_with_version_should_include_version_in_gemfile @@ -55,7 +56,7 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec', '>=2.0.0.a5' - assert_file 'Gemfile', /gem "rspec", ">=2.0.0.a5"/ + assert_file 'Gemfile', /gem 'rspec', '>=2.0.0.a5'/ end def test_gem_should_insert_on_separate_lines @@ -66,8 +67,8 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec' action :gem, 'rspec-rails' - assert_file 'Gemfile', /^gem "rspec"$/ - assert_file 'Gemfile', /^gem "rspec-rails"$/ + assert_file 'Gemfile', /^gem 'rspec'$/ + assert_file 'Gemfile', /^gem 'rspec-rails'$/ end def test_gem_should_include_options @@ -75,7 +76,25 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec', github: 'dchelimsky/rspec', tag: '1.2.9.rc1' - assert_file 'Gemfile', /gem "rspec", github: "dchelimsky\/rspec", tag: "1\.2\.9\.rc1"/ + assert_file 'Gemfile', /gem 'rspec', github: 'dchelimsky\/rspec', tag: '1\.2\.9\.rc1'/ + end + + def test_gem_with_non_string_options + run_generator + + action :gem, 'rspec', require: false + action :gem, 'rspec-rails', group: [:development, :test] + + assert_file 'Gemfile', /^gem 'rspec', require: false$/ + assert_file 'Gemfile', /^gem 'rspec-rails', group: \[:development, :test\]$/ + end + + def test_gem_falls_back_to_inspect_if_string_contains_single_quote + run_generator + + action :gem, 'rspec', ">=2.0'0" + + assert_file 'Gemfile', /^gem 'rspec', ">=2\.0'0"$/ end def test_gem_group_should_wrap_gems_in_a_group @@ -89,7 +108,7 @@ class ActionsTest < Rails::Generators::TestCase gem 'fakeweb' end - assert_file 'Gemfile', /\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend/ + assert_file 'Gemfile', /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ end def test_environment_should_include_data_in_environment_initializer_block @@ -234,7 +253,7 @@ class ActionsTest < Rails::Generators::TestCase protected def action(*args, &block) - silence(:stdout){ generator.send(*args, &block) } + capture(:stdout){ generator.send(*args, &block) } end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 42b6275932..d687a8f506 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -1,9 +1,11 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' require 'generators/shared_generator_tests' +require 'mocha/setup' # FIXME: stop using mocha DEFAULT_APP_FILES = %w( .gitignore + README.rdoc Gemfile Rakefile config.ru @@ -20,6 +22,7 @@ DEFAULT_APP_FILES = %w( bin/bundle bin/rails bin/rake + bin/setup config/environments config/initializers config/locales @@ -28,6 +31,7 @@ DEFAULT_APP_FILES = %w( lib/tasks lib/assets log + test/test_helper.rb test/fixtures test/controllers test/models @@ -36,6 +40,8 @@ DEFAULT_APP_FILES = %w( test/integration vendor vendor/assets + vendor/assets/stylesheets + vendor/assets/javascripts tmp/cache tmp/cache/assets ) @@ -54,9 +60,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application", media: "all", "data-turbolinks-track" => true/) - assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+"application", "data-turbolinks-track" => true/) + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => true/) + assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => true/) assert_file("app/assets/stylesheets/application.css") + assert_file("app/assets/javascripts/application.js") end def test_invalid_application_name_raises_an_error @@ -108,10 +115,13 @@ class AppGeneratorTest < Rails::Generators::TestCase FileUtils.mv(app_root, app_moved_root) + # make sure we are in correct dir + FileUtils.cd(app_moved_root) + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_moved_root, shell: @shell generator.send(:app_const) - quietly { generator.send(:create_config_files) } + quietly { generator.send(:update_config_files) } assert_file "myapp_moved/config/environment.rb", /Rails\.application\.initialize!/ assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/ end @@ -126,10 +136,46 @@ class AppGeneratorTest < Rails::Generators::TestCase generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell generator.send(:app_const) - quietly { generator.send(:create_config_files) } + quietly { generator.send(:update_config_files) } assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/ end + def test_new_application_use_json_serialzier + run_generator + + assert_file("config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/) + end + + def test_rails_update_keep_the_cookie_serializer_if_it_is_already_configured + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + Rails.application.config.root = app_root + Rails.application.class.stubs(:name).returns("Myapp") + Rails.application.stubs(:is_a?).returns(Rails::Application) + + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/) + end + + def test_rails_update_set_the_cookie_serializer_to_marchal_if_it_is_not_already_configured + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + FileUtils.rm("#{app_root}/config/initializers/cookies_serializer.rb") + + Rails.application.config.root = app_root + Rails.application.class.stubs(:name).returns("Myapp") + Rails.application.stubs(:is_a?).returns(Rails::Application) + + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :marshal/) + end + def test_application_names_are_not_singularized run_generator [File.join(destination_root, "hats")] assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/ @@ -148,20 +194,20 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_config_database_is_added_by_default run_generator assert_file "config/database.yml", /sqlite3/ - unless defined?(JRUBY_VERSION) - assert_gem "sqlite3" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcsqlite3-adapter" + else + assert_gem "sqlite3" end end def test_config_another_database run_generator([destination_root, "-d", "mysql"]) assert_file "config/database.yml", /mysql/ - unless defined?(JRUBY_VERSION) - assert_gem "mysql2" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcmysql-adapter" + else + assert_gem "mysql2" end end @@ -173,10 +219,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_config_postgresql_database run_generator([destination_root, "-d", "postgresql"]) assert_file "config/database.yml", /postgresql/ - unless defined?(JRUBY_VERSION) - assert_gem "pg" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcpostgresql-adapter" + else + assert_gem "pg" end end @@ -205,9 +251,9 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_gem "activerecord-jdbc-adapter" end - def test_config_jdbc_database_when_no_option_given - if defined?(JRUBY_VERSION) - run_generator([destination_root]) + if defined?(JRUBY_VERSION) + def test_config_jdbc_database_when_no_option_given + run_generator assert_file "config/database.yml", /sqlite3/ assert_gem "activerecord-jdbcsqlite3-adapter" end @@ -222,11 +268,16 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generator_if_skip_action_view_is_given + run_generator [destination_root, "--skip-action-view"] + assert_file "config/application.rb", /#\s+require\s+["']action_view\/railtie["']/ + end + def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] + assert_no_file "config/initializers/assets.rb" assert_file "config/application.rb" do |content| assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) - assert_match(/config\.assets\.enabled = false/, content) end assert_file "Gemfile" do |content| assert_no_match(/sass-rails/, content) @@ -240,46 +291,25 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/config\.assets\.digest = true/, content) assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) assert_no_match(/config\.assets\.css_compressor = :sass/, content) - assert_no_match(/config\.assets\.version = '1\.0'/, content) end end def test_inclusion_of_javascript_runtime - run_generator([destination_root]) + run_generator if defined?(JRUBY_VERSION) assert_gem "therubyrhino" else - assert_file "Gemfile", /# gem\s+["']therubyracer["']+, platforms: :ruby$/ + assert_file "Gemfile", /# gem 'therubyracer', platforms: :ruby/ end end - def test_creation_of_a_test_directory - run_generator - assert_file 'test' - end - - def test_creation_of_app_assets_images_directory - run_generator - assert_file "app/assets/images" - end - - def test_creation_of_vendor_assets_javascripts_directory - run_generator - assert_file "vendor/assets/javascripts" - end - - def test_creation_of_vendor_assets_stylesheets_directory - run_generator - assert_file "vendor/assets/stylesheets" - end - def test_jquery_is_the_default_javascript_library run_generator assert_file "app/assets/javascripts/application.js" do |contents| assert_match %r{^//= require jquery}, contents assert_match %r{^//= require jquery_ujs}, contents end - assert_file "Gemfile", /^gem 'jquery-rails'/ + assert_gem "jquery-rails" end def test_other_javascript_libraries @@ -293,26 +323,43 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_javascript_is_skipped_if_required run_generator [destination_root, "--skip-javascript"] - assert_file "app/assets/javascripts/application.js" do |contents| - assert_no_match %r{^//=\s+require\s}, contents - end + + assert_no_file "app/assets/javascripts" + assert_no_file "vendor/assets/javascripts" + assert_file "app/views/layouts/application.html.erb" do |contents| - assert_match(/stylesheet_link_tag\s+"application", media: "all" %>/, contents) - assert_match(/javascript_include_tag\s+"application" \%>/, contents) + assert_match(/stylesheet_link_tag\s+'application', media: 'all' %>/, contents) + assert_no_match(/javascript_include_tag\s+'application' \%>/, contents) end + assert_file "Gemfile" do |content| - assert_match(/coffee-rails/, content) + assert_no_match(/coffee-rails/, content) + assert_no_match(/jquery-rails/, content) end end - def test_inclusion_of_debugger + def test_inclusion_of_jbuilder run_generator - assert_file "Gemfile", /# gem 'debugger'/ + assert_gem 'jbuilder' end - def test_inclusion_of_lazy_loaded_sdoc + def test_inclusion_of_a_debugger run_generator - assert_file 'Gemfile', /gem 'sdoc', require: false/ + if defined?(JRUBY_VERSION) + assert_file "Gemfile" do |content| + assert_no_match(/byebug/, content) + assert_no_match(/debugger/, content) + end + elsif RUBY_VERSION < '2.0.0' + assert_gem 'debugger' + else + assert_gem 'byebug' + end + end + + def test_inclusion_of_doc + run_generator + assert_file 'Gemfile', /gem 'sdoc',\s+'~> 0.4.0',\s+group: :doc/ end def test_template_from_dir_pwd @@ -348,10 +395,11 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-test-unit", "--skip-active-record"] assert_file "config/application.rb", /#\s+require\s+["']rails\/test_unit\/railtie["']/ assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ + assert_file "config/application.rb", /\s+require\s+["']active_job\/railtie["']/ end def test_new_hash_style - run_generator [destination_root] + run_generator assert_file "config/initializers/session_store.rb" do |file| assert_match(/config.session_store :cookie_store, key: '_.+_session'/, file) end @@ -362,13 +410,125 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/run bundle install/, output) end -protected + def test_application_name_with_spaces + path = File.join(destination_root, "foo bar".shellescape) + + # This also applies to MySQL apps but not with SQLite + run_generator [path, "-d", 'postgresql'] + + assert_file "foo bar/config/database.yml", /database: foo_bar_development/ + assert_file "foo bar/config/initializers/session_store.rb", /key: '_foo_bar/ + end + + def test_web_console + run_generator + assert_gem 'web-console' + end + + def test_spring + run_generator + assert_gem 'spring' + end + + def test_spring_binstubs + jruby_skip "spring doesn't run on JRuby" + generator.stubs(:bundle_command).with('install') + generator.expects(:bundle_command).with('exec spring binstub --all').once + quietly { generator.invoke_all } + end + + def test_spring_no_fork + jruby_skip "spring doesn't run on JRuby" + Process.stubs(:respond_to?).with(:fork).returns(false) + run_generator + + assert_file "Gemfile" do |content| + assert_no_match(/spring/, content) + end + end + + def test_skip_spring + run_generator [destination_root, "--skip-spring"] + + assert_file "Gemfile" do |content| + assert_no_match(/spring/, content) + end + end + + def test_generator_if_skip_gems_is_given + run_generator [destination_root, "--skip-gems", "turbolinks", "coffee-rails"] + + assert_file "Gemfile" do |content| + assert_no_match(/turbolinks/, content) + assert_no_match(/coffee-rails/, content) + end + assert_file "app/views/layouts/application.html.erb" do |content| + assert_no_match(/data-turbolinks-track/, content) + end + assert_file "app/assets/javascripts/application.js" do |content| + assert_no_match(/turbolinks/, content) + end + end + + def test_gitignore_when_sqlite3 + run_generator + + assert_file '.gitignore' do |content| + assert_match(/sqlite3/, content) + end + end + + def test_gitignore_when_no_active_record + run_generator [destination_root, '--skip-active-record'] + + assert_file '.gitignore' do |content| + assert_no_match(/sqlite/i, content) + end + end + + def test_gitignore_when_non_sqlite3_db + run_generator([destination_root, "-d", "mysql"]) + + assert_file '.gitignore' do |content| + assert_no_match(/sqlite/i, content) + end + end + + def test_psych_gem + run_generator + gem_regex = /gem 'psych',\s+'~> 2.0', \s+platforms: :rbx/ + + assert_file "Gemfile" do |content| + if defined?(Rubinius) + assert_match(gem_regex, content) + else + assert_no_match(gem_regex, content) + end + end + end + + def test_after_bundle_callback + path = 'http://example.org/rails_template' + template = %{ after_bundle { run 'echo ran after_bundle' } } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + + bundler_first = sequence('bundle, binstubs, after_bundle') + generator.expects(:bundle_command).with('install').once.in_sequence(bundler_first) + generator.expects(:bundle_command).with('exec spring binstub --all').in_sequence(bundler_first) + generator.expects(:run).with('echo ran after_bundle').in_sequence(bundler_first) + + quietly { generator.invoke_all } + end + + protected def action(*args, &block) - silence(:stdout) { generator.send(*args, &block) } + capture(:stdout) { generator.send(*args, &block) } end def assert_gem(gem) - assert_file "Gemfile", /^gem\s+["']#{gem}["']$/ + assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/ end end diff --git a/railties/test/generators/argv_scrubber_test.rb b/railties/test/generators/argv_scrubber_test.rb new file mode 100644 index 0000000000..31e07bc8da --- /dev/null +++ b/railties/test/generators/argv_scrubber_test.rb @@ -0,0 +1,136 @@ +require 'active_support/test_case' +require 'active_support/testing/autorun' +require 'rails/generators/rails/app/app_generator' +require 'tempfile' + +module Rails + module Generators + class ARGVScrubberTest < ActiveSupport::TestCase # :nodoc: + # Future people who read this... These tests are just to surround the + # current behavior of the ARGVScrubber, they do not mean that the class + # *must* act this way, I just want to prevent regressions. + + def test_version + ['-v', '--version'].each do |str| + scrubber = ARGVScrubber.new [str] + output = nil + exit_code = nil + scrubber.extend(Module.new { + define_method(:puts) { |string| output = string } + define_method(:exit) { |code| exit_code = code } + }) + scrubber.prepare! + assert_equal "Rails #{Rails::VERSION::STRING}", output + assert_equal 0, exit_code + end + end + + def test_default_help + argv = ['zomg', 'how', 'are', 'you'] + scrubber = ARGVScrubber.new argv + args = scrubber.prepare! + assert_equal ['--help'] + argv.drop(1), args + end + + def test_prepare_returns_args + scrubber = ARGVScrubber.new ['hi mom'] + args = scrubber.prepare! + assert_equal '--help', args.first + end + + def test_no_mutations + scrubber = ARGVScrubber.new ['hi mom'].freeze + args = scrubber.prepare! + assert_equal '--help', args.first + end + + def test_new_command_no_rc + scrubber = Class.new(ARGVScrubber) { + def self.default_rc_file + File.join(Dir.tmpdir, 'whatever') + end + }.new ['new'] + args = scrubber.prepare! + assert_equal [], args + end + + def test_new_homedir_rc + file = Tempfile.new 'myrcfile' + file.puts '--hello-world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_singleton_method(:default_rc_file) do + file.path + end + define_method(:puts) { |msg| message = msg } + }.new ['new'] + args = scrubber.prepare! + assert_equal ['--hello-world'], args + assert_match 'hello-world', message + assert_match file.path, message + ensure + file.close + file.unlink + end + + def test_rc_whitespace_separated + file = Tempfile.new 'myrcfile' + file.puts '--hello --world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| message = msg } + }.new ['new', "--rc=#{file.path}"] + args = scrubber.prepare! + assert_equal ['--hello', '--world'], args + ensure + file.close + file.unlink + end + + def test_new_rc_option + file = Tempfile.new 'myrcfile' + file.puts '--hello-world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| message = msg } + }.new ['new', "--rc=#{file.path}"] + args = scrubber.prepare! + assert_equal ['--hello-world'], args + assert_match 'hello-world', message + assert_match file.path, message + ensure + file.close + file.unlink + end + + def test_new_rc_option_and_custom_options + file = Tempfile.new 'myrcfile' + file.puts '--hello' + file.puts '--world' + file.flush + + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| } + }.new ['new', 'tenderapp', '--love', "--rc=#{file.path}"] + + args = scrubber.prepare! + assert_equal ["tenderapp", "--hello", "--world", "--love"], args + ensure + file.close + file.unlink + end + + def test_no_rc + scrubber = ARGVScrubber.new ['new', '--no-rc'] + args = scrubber.prepare! + assert_equal [], args + end + end + end +end diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 5205deafd9..a7d56dd352 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -28,13 +28,11 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_invokes_helper run_generator assert_file "app/helpers/account_helper.rb" - assert_file "test/helpers/account_helper_test.rb" end def test_does_not_invoke_helper_if_required run_generator ["account", "--skip-helper"] assert_no_file "app/helpers/account_helper.rb" - assert_no_file "test/helpers/account_helper_test.rb" end def test_invokes_assets @@ -43,6 +41,12 @@ class ControllerGeneratorTest < Rails::Generators::TestCase assert_file "app/assets/stylesheets/account.css" end + def test_does_not_invoke_assets_if_required + run_generator ["account", "--skip-assets"] + assert_no_file "app/assets/javascripts/account.js" + assert_no_file "app/assets/stylesheets/account.css" + end + def test_invokes_default_test_framework run_generator assert_file "test/controllers/account_controller_test.rb" @@ -61,7 +65,14 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_add_routes run_generator - assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/ + assert_file "config/routes.rb", /get 'account\/foo'/, /get 'account\/bar'/ + end + + def test_skip_routes + run_generator ["account", "foo", "--skip-routes"] + assert_file "config/routes.rb" do |routes| + assert_no_match(/get 'account\/foo'/, routes) + end end def test_invokes_default_template_engine_even_with_no_action @@ -82,4 +93,9 @@ class ControllerGeneratorTest < Rails::Generators::TestCase assert_instance_method :bar, controller end end + + def test_namespaced_routes_are_created_in_routes + run_generator ["admin/dashboard", "index"] + assert_file "config/routes.rb", /namespace :admin do\n\s+get 'dashboard\/index'\n/ + end end diff --git a/railties/test/generators/create_migration_test.rb b/railties/test/generators/create_migration_test.rb new file mode 100644 index 0000000000..e16a77479a --- /dev/null +++ b/railties/test/generators/create_migration_test.rb @@ -0,0 +1,134 @@ +require 'generators/generators_test_helper' +require 'rails/generators/rails/migration/migration_generator' + +class CreateMigrationTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + class Migrator < Rails::Generators::MigrationGenerator + include Rails::Generators::Migration + + def self.next_migration_number(dirname) + current_migration_number(dirname) + 1 + end + end + + tests Migrator + + def default_destination_path + "db/migrate/create_articles.rb" + end + + def create_migration(destination_path = default_destination_path, config = {}, generator_options = {}, &block) + migration_name = File.basename(destination_path, '.rb') + generator([migration_name], generator_options) + generator.set_migration_assigns!(destination_path) + + dir, base = File.split(destination_path) + timestamped_destination_path = File.join(dir, ["%migration_number%", base].join('_')) + + @migration = Rails::Generators::Actions::CreateMigration.new(generator, timestamped_destination_path, block || "contents", config) + end + + def migration_exists!(*args) + @existing_migration = create_migration(*args) + invoke! + @generator = nil + end + + def invoke! + capture(:stdout) { @migration.invoke! } + end + + def revoke! + capture(:stdout) { @migration.revoke! } + end + + def test_invoke + create_migration + + assert_match(/create db\/migrate\/1_create_articles.rb\n/, invoke!) + assert_file @migration.destination + end + + def test_invoke_pretended + create_migration(default_destination_path, {}, { pretend: true }) + + assert_no_file @migration.destination + end + + def test_invoke_when_exists + migration_exists! + create_migration + + assert_equal @existing_migration.destination, @migration.existing_migration + end + + def test_invoke_when_exists_identical + migration_exists! + create_migration + + assert_match(/identical db\/migrate\/1_create_articles.rb\n/, invoke!) + assert @migration.identical? + end + + def test_invoke_when_exists_not_identical + migration_exists! + create_migration { "different content" } + + assert_raise(Rails::Generators::Error) { invoke! } + end + + def test_invoke_forced_when_exists_not_identical + dest = "db/migrate/migration.rb" + migration_exists!(dest) + create_migration(dest, force: true) { "different content" } + + stdout = invoke! + assert_match(/remove db\/migrate\/1_migration.rb\n/, stdout) + assert_match(/create db\/migrate\/2_migration.rb\n/, stdout) + assert_file @migration.destination + assert_no_file @existing_migration.destination + end + + def test_invoke_forced_pretended_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, { force: true }, { pretend: true }) do + "different content" + end + + stdout = invoke! + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, stdout) + assert_match(/create db\/migrate\/2_create_articles.rb\n/, stdout) + assert_no_file @migration.destination + end + + def test_invoke_skipped_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, {}, { skip: true }) { "different content" } + + assert_match(/skip db\/migrate\/2_create_articles.rb\n/, invoke!) + assert_no_file @migration.destination + end + + def test_revoke + migration_exists! + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_no_file @existing_migration.destination + end + + def test_revoke_pretended + migration_exists! + create_migration(default_destination_path, {}, { pretend: true }) + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_file @existing_migration.destination + end + + def test_revoke_when_no_exists + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + end +end diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb new file mode 100644 index 0000000000..7871399dd7 --- /dev/null +++ b/railties/test/generators/generator_test.rb @@ -0,0 +1,85 @@ +require 'active_support/test_case' +require 'active_support/testing/autorun' +require 'rails/generators/app_base' + +module Rails + module Generators + class GeneratorTest < ActiveSupport::TestCase + def make_builder_class + Class.new(AppBase) do + add_shared_options_for "application" + + # include a module to get around thor's method_added hook + include(Module.new { + def gemfile_entries; super; end + def invoke_all; super; self; end + def add_gem_entry_filter; super; end + def gemfile_entry(*args); super; end + }) + end + end + + def test_construction + klass = make_builder_class + assert klass.start(['new', 'blah']) + end + + def test_add_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove' + assert_includes generator.gemfile_entries.map(&:name), 'tenderlove' + end + + def test_add_gem_with_version + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', '2.0.0' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.version == '2.0.0' + } + end + + def test_add_github_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', github: 'hello world' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.options[:github] == 'hello world' + } + end + + def test_add_path_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', path: 'hello world' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.options[:path] == 'hello world' + } + end + + def test_filter + klass = make_builder_class + generator = klass.start(['new', 'blah']) + gems = generator.gemfile_entries + generator.add_gem_entry_filter { |gem| + gem.name != gems.first.name + } + assert_equal gems.drop(1), generator.gemfile_entries + end + + def test_two_filters + klass = make_builder_class + generator = klass.start(['new', 'blah']) + gems = generator.gemfile_entries + generator.add_gem_entry_filter { |gem| + gem.name != gems.first.name + } + generator.add_gem_entry_filter { |gem| + gem.name != gems[1].name + } + assert_equal gems.drop(2), generator.gemfile_entries + end + end + end +end diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 7fdd54fc30..6cc91f166b 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -1,10 +1,14 @@ require 'abstract_unit' +require 'active_support/core_ext/module/remove_method' require 'rails/generators' require 'rails/generators/test_case' module Rails - def self.root - @root ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures')) + class << self + remove_possible_method :root + def root + @root ||= Pathname.new(File.expand_path('../../fixtures', __FILE__)) + end end end Rails.application.config.root = Rails.root @@ -16,6 +20,7 @@ Rails.application.load_generators require 'active_record' require 'action_dispatch' +require 'action_view' module GeneratorsTestHelper def self.included(base) @@ -36,4 +41,12 @@ module GeneratorsTestHelper FileUtils.mkdir_p(destination) FileUtils.cp routes, destination end + + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end + end + end end diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb index 81d4fcb129..add04f21a4 100644 --- a/railties/test/generators/helper_generator_test.rb +++ b/railties/test/generators/helper_generator_test.rb @@ -13,26 +13,11 @@ class HelperGeneratorTest < Rails::Generators::TestCase assert_file "app/helpers/admin_helper.rb", /module AdminHelper/ end - def test_invokes_default_test_framework - run_generator - assert_file "test/helpers/admin_helper_test.rb", /class AdminHelperTest < ActionView::TestCase/ - end - - def test_logs_if_the_test_framework_cannot_be_found - content = run_generator ["admin", "--test-framework=rspec"] - assert_match(/rspec \[not found\]/, content) - end - def test_check_class_collision content = capture(:stderr){ run_generator ["object"] } assert_match(/The name 'ObjectHelper' is either already used in your application or reserved/, content) end - def test_check_class_collision_on_tests - content = capture(:stderr){ run_generator ["another_object"] } - assert_match(/The name 'AnotherObjectHelperTest' is either already used in your application or reserved/, content) - end - def test_namespaced_and_not_namespaced_helpers run_generator ["products"] diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index 6b2351fc1a..25649881eb 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -1,7 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/mailer/mailer_generator' - class MailerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(notifier foo bar) @@ -23,8 +22,11 @@ class MailerGeneratorTest < Rails::Generators::TestCase end def test_check_class_collision - content = capture(:stderr){ run_generator ["object"] } - assert_match(/The name 'Object' is either already used in your application or reserved/, content) + Object.send :const_set, :Notifier, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'Notifier' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :Notifier end def test_invokes_default_test_framework @@ -34,17 +36,58 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_match(/test "foo"/, test) assert_match(/test "bar"/, test) end + assert_file "test/mailers/previews/notifier_preview.rb" do |preview| + assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/notifier/, preview) + assert_match(/class NotifierPreview < ActionMailer::Preview/, preview) + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/foo/, preview) + assert_instance_method :foo, preview do |foo| + assert_match(/Notifier.foo/, foo) + end + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/bar/, preview) + assert_instance_method :bar, preview do |bar| + assert_match(/Notifier.bar/, bar) + end + end end - def test_invokes_default_template_engine + def test_check_test_class_collision + Object.send :const_set, :NotifierTest, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'NotifierTest' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :NotifierTest + end + + def test_check_preview_class_collision + Object.send :const_set, :NotifierPreview, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'NotifierPreview' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :NotifierPreview + end + + def test_invokes_default_text_template_engine run_generator assert_file "app/views/notifier/foo.text.erb" do |view| - assert_match(%r(app/views/notifier/foo\.text\.erb), view) + assert_match(%r(\sapp/views/notifier/foo\.text\.erb), view) assert_match(/<%= @greeting %>/, view) end assert_file "app/views/notifier/bar.text.erb" do |view| - assert_match(%r(app/views/notifier/bar\.text\.erb), view) + assert_match(%r(\sapp/views/notifier/bar\.text\.erb), view) + assert_match(/<%= @greeting %>/, view) + end + end + + def test_invokes_default_html_template_engine + run_generator + assert_file "app/views/notifier/foo.html.erb" do |view| + assert_match(%r(\sapp/views/notifier/foo\.html\.erb), view) + assert_match(/<%= @greeting %>/, view) + end + + assert_file "app/views/notifier/bar.html.erb" do |view| + assert_match(%r(\sapp/views/notifier/bar\.html\.erb), view) assert_match(/<%= @greeting %>/, view) end end @@ -65,7 +108,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_match(/class Farm::Animal < ActionMailer::Base/, mailer) assert_match(/en\.farm\.animal\.moos\.subject/, mailer) end + assert_file "test/mailers/previews/farm/animal_preview.rb" do |preview| + assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal/, preview) + assert_match(/class Farm::AnimalPreview < ActionMailer::Preview/, preview) + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal\/moos/, preview) + end assert_file "app/views/farm/animal/moos.text.erb" + assert_file "app/views/farm/animal/moos.html.erb" end def test_actions_are_turned_into_methods diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index d876597944..72f5fe29ca 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -159,6 +159,18 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_add_migration_with_required_references + migration = "add_references_to_books" + run_generator [migration, "author:belongs_to{required}", "distributor:references{polymorphic,required}"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_reference :books, :author, index: true, null: false/, change) + assert_match(/add_reference :books, :distributor, polymorphic: true, index: true, null: false/, change) + end + end + end + def test_create_join_table_migration migration = "add_media_join_table" run_generator [migration, "artist_id", "musics:uniq"] @@ -197,4 +209,54 @@ class MigrationGeneratorTest < Rails::Generators::TestCase def test_properly_identifies_usage_file assert generator_class.send(:usage_path) end + + def test_migration_with_singular_table_name + with_singular_table_name do + migration = "add_title_body_to_post" + run_generator [migration, 'title:string'] + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_column :post, :title, :string/, change) + end + end + end + end + + def test_create_join_table_migration_with_singular_table_name + with_singular_table_name do + migration = "add_media_join_table" + run_generator [migration, "artist_id", "music:uniq"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/create_join_table :artist, :music/, change) + assert_match(/# t.index \[:artist_id, :music_id\]/, change) + assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, change) + end + end + end + end + + def test_create_table_migration_with_singular_table_name + with_singular_table_name do + run_generator ["create_book", "title:string", "content:text"] + assert_migration "db/migrate/create_book.rb" do |content| + assert_method :change, content do |change| + assert_match(/create_table :book/, change) + assert_match(/ t\.string :title/, change) + assert_match(/ t\.text :content/, change) + end + end + end + end + + private + + def with_singular_table_name + old_state = ActiveRecord::Base.pluralize_table_names + ActiveRecord::Base.pluralize_table_names = false + yield + ensure + ActiveRecord::Base.pluralize_table_names = old_state + end end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 01ab77ee20..c78597c81b 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -1,5 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/model/model_generator' +require 'active_support/core_ext/string/strip' class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -34,6 +35,13 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_no_migration "db/migrate/create_accounts.rb" end + def test_plural_names_are_singularized + content = run_generator ["accounts".freeze] + assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ + assert_file "test/models/account_test.rb", /class AccountTest/ + assert_match(/\[WARNING\] The model name 'accounts' was recognized as a plural, using the singular 'account' instead\. Override with --force-plural or setup custom inflection rules for this noun before running the generator\./, content) + end + def test_model_with_underscored_parent_option run_generator ["account", "--parent", "admin/account"] assert_file "app/models/account.rb", /class Account < Admin::Account/ @@ -215,7 +223,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_migration_with_timestamps run_generator - assert_migration "db/migrate/create_accounts.rb", /t.timestamps/ + assert_migration "db/migrate/create_accounts.rb", /t.timestamps null: false/ end def test_migration_timestamps_are_skipped @@ -356,6 +364,49 @@ class ModelGeneratorTest < Rails::Generators::TestCase end end + def test_required_belongs_to_adds_required_association + run_generator ["account", "supplier:references{required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_polymorphic_belongs_to_generages_correct_model + run_generator ["account", "supplier:references{required,polymorphic}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_and_polymorphic_are_order_independent + run_generator ["account", "supplier:references{polymorphic.required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_adds_null_false_to_column + run_generator ["account", "supplier:references{required}"] + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.references :supplier,.*\snull: false/, up) + end + end + end + private def assert_generated_fixture(path, parsed_contents) fixture_file = File.new File.expand_path(path, destination_root) diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 2bc2c33a72..4199e00b0d 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -1,5 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' +require 'mocha/setup' # FIXME: stop using mocha # Mock out what we need from AR::Base. module ActiveRecord @@ -117,6 +118,25 @@ class NamedBaseTest < Rails::Generators::TestCase assert Rails::Generators.hidden_namespaces.include?('hidden') end + def test_scaffold_plural_names_with_model_name_option + g = generator ['Admin::Foo'], model_name: 'User' + assert_name g, 'user', :singular_name + assert_name g, 'User', :name + assert_name g, 'user', :file_path + assert_name g, 'User', :class_name + assert_name g, 'user', :file_name + assert_name g, 'User', :human_name + assert_name g, 'users', :plural_name + assert_name g, 'user', :i18n_scope + assert_name g, 'users', :table_name + assert_name g, 'Admin::Foos', :controller_name + assert_name g, %w(admin), :controller_class_path + assert_name g, 'Admin::Foos', :controller_class_name + assert_name g, 'admin/foos', :controller_file_path + assert_name g, 'foos', :controller_file_name + assert_name g, 'admin.foos', :controller_i18n_scope + end + protected def assert_name(generator, value, method) diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index a4d8b3d1b0..7eeb084eab 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -44,10 +44,9 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase end end - def test_helpr_is_also_namespaced + def test_helper_is_also_namespaced run_generator assert_file "app/helpers/test_app/account_helper.rb", /module TestApp/, / module AccountHelper/ - assert_file "test/helpers/test_app/account_helper_test.rb", /module TestApp/, / class AccountHelperTest/ end def test_invokes_default_test_framework @@ -63,7 +62,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase def test_routes_should_not_be_namespaced run_generator - assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/ + assert_file "config/routes.rb", /get 'account\/foo'/, /get 'account\/bar'/ end def test_invokes_default_template_engine_even_with_no_action @@ -229,7 +228,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/product_lines_helper.rb" - assert_file "test/helpers/test_app/product_lines_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -260,7 +258,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/product_lines_helper.rb" - assert_no_file "test/helpers/test_app/product_lines_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" @@ -297,7 +294,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/admin/roles_helper.rb" - assert_file "test/helpers/test_app/admin/roles_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -329,7 +325,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/admin/roles_helper.rb" - assert_no_file "test/helpers/test_app/admin/roles_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" @@ -366,7 +361,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/admin/user/special/roles_helper.rb" - assert_file "test/helpers/test_app/admin/user/special/roles_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -397,7 +391,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/admin/user/special/roles_helper.rb" - assert_no_file "test/helpers/test_app/admin/user/special/roles_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 068eb66bc6..645efa5daf 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/plugin/plugin_generator' require 'generators/shared_generator_tests' +require 'mocha/setup' # FIXME: stop using mocha DEFAULT_PLUGIN_FILES = %w( .gitignore @@ -35,6 +36,12 @@ class PluginGeneratorTest < Rails::Generators::TestCase content = capture(:stderr){ run_generator [File.join(destination_root, "43things")] } assert_equal "Invalid plugin name 43things. Please give a name which does not start with numbers.\n", content + + content = capture(:stderr){ run_generator [File.join(destination_root, "plugin")] } + assert_equal "Invalid plugin name plugin. Please give a name which does not match one of the reserved rails words.\n", content + + content = capture(:stderr){ run_generator [File.join(destination_root, "Digest")] } + assert_equal "Invalid plugin name Digest, constant Digest is already in use. Please choose another plugin name.\n", content end def test_camelcase_plugin_name_underscores_filenames @@ -47,7 +54,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator assert_file "README.rdoc", /Bukkits/ assert_no_file "config/routes.rb" - assert_file "test/test_helper.rb" + assert_file "test/test_helper.rb", /require.+test\/dummy\/config\/environment/ assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ end @@ -58,6 +65,20 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "test/integration/navigation_test.rb", /ActionDispatch::IntegrationTest/ end + def test_inclusion_of_a_debugger + run_generator [destination_root, '--full'] + if defined?(JRUBY_VERSION) + assert_file "Gemfile" do |content| + assert_no_match(/byebug/, content) + assert_no_match(/debugger/, content) + end + elsif RUBY_VERSION < '2.0.0' + assert_file "Gemfile", /# gem 'debugger'/ + else + assert_file "Gemfile", /# gem 'byebug'/ + end + end + def test_generating_test_files_in_full_mode_without_unit_test_files run_generator [destination_root, "-T", "--full"] @@ -74,7 +95,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generating_adds_dummy_app_without_javascript_and_assets_deps - run_generator [destination_root] + run_generator assert_file "test/dummy/app/assets/stylesheets/application.css" @@ -139,7 +160,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/bukkits/, contents) end assert_match(/run bundle install/, result) - assert_match(/Using bukkits \(0\.0\.1\)/, result) + assert_match(/Using bukkits \(?0\.0\.1\)?/, result) assert_match(/Your bundle is complete/, result) assert_equal 1, result.scan("Your bundle is complete").size end @@ -168,22 +189,22 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_tests_works_in_full_mode run_generator [destination_root, "--full", "--skip_active_record"] FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_migration_tasks_work_with_mountable_option run_generator [destination_root, "--mountable"] FileUtils.cd destination_root quietly { system 'bundle install' } - `bundle exec rake db:migrate` - assert_equal 0, $?.exitstatus + output = `bundle exec rake db:migrate 2>&1` + assert $?.success?, "Command failed: #{output}" end def test_creating_engine_in_full_mode @@ -249,6 +270,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb", /require.+spec\/dummy\/config\/environment/ end def test_creating_dummy_application_with_different_name @@ -256,6 +278,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/fake" assert_file "spec/fake/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb", /require.+spec\/fake\/config\/environment/ end def test_creating_dummy_without_tests_but_with_dummy_path @@ -263,6 +286,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test" + assert_no_file "test/test_helper.rb" assert_file '.gitignore' do |contents| assert_match(/spec\/dummy/, contents) end @@ -292,8 +316,8 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails.version}"/, contents) - assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + assert_match(/gem 'rails', '~> #{Rails.version}'/, contents) + assert_match_sqlite3(contents) assert_no_match(/# gem "jquery-rails"/, contents) end end @@ -303,18 +327,18 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails.version}"/, contents) - assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + assert_match(/gem 'rails', '~> #{Rails.version}'/, contents) + assert_match_sqlite3(contents) end end def test_creating_plugin_in_app_directory_adds_gemfile_entry - # simulate application existance + # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" Object.const_set('APP_PATH', Rails.root) FileUtils.touch gemfile_path - run_generator [destination_root] + run_generator assert_file gemfile_path, /gem 'bukkits', path: 'tmp\/bukkits'/ ensure @@ -323,7 +347,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_skipping_gemfile_entry - # simulate application existance + # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" Object.const_set('APP_PATH', Rails.root) FileUtils.touch gemfile_path @@ -338,6 +362,52 @@ class PluginGeneratorTest < Rails::Generators::TestCase FileUtils.rm gemfile_path end + def test_generating_controller_inside_mountable_engine + run_generator [destination_root, "--mountable"] + + capture(:stdout) do + `#{destination_root}/bin/rails g controller admin/dashboard foo` + end + + assert_file "config/routes.rb" do |contents| + assert_match(/namespace :admin/, contents) + assert_no_match(/namespace :bukkit/, contents) + end + end + + def test_git_name_and_email_in_gemspec_file + name = `git config user.name`.chomp rescue "TODO: Write your name" + email = `git config user.email`.chomp rescue "TODO: Write your email address" + + run_generator + assert_file "bukkits.gemspec" do |contents| + assert_match name, contents + assert_match email, contents + end + end + + def test_git_name_in_license_file + name = `git config user.name`.chomp rescue "TODO: Write your name" + + run_generator + assert_file "MIT-LICENSE" do |contents| + assert_match name, contents + end + end + + def test_no_details_from_git_when_skip_git + name = "TODO: Write your name" + email = "TODO: Write your email address" + + run_generator [destination_root, '--skip-git'] + assert_file "MIT-LICENSE" do |contents| + assert_match name, contents + end + assert_file "bukkits.gemspec" do |contents| + assert_match name, contents + assert_match email, contents + end + end protected def action(*args, &block) @@ -347,4 +417,12 @@ protected def default_files ::DEFAULT_PLUGIN_FILES end + + def assert_match_sqlite3(contents) + if defined?(JRUBY_VERSION) + assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents) + else + assert_match(/group :development do\n gem 'sqlite3'\nend/, contents) + end + end end diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 3d4e694361..581d80d60e 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -36,7 +36,6 @@ class ResourceGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/accounts_controller_test.rb", /class AccountsControllerTest < ActionController::TestCase/ assert_file "app/helpers/accounts_helper.rb", /module AccountsHelper/ - assert_file "test/helpers/accounts_helper_test.rb", /class AccountsHelperTest < ActionView::TestCase/ end def test_resource_controller_with_actions @@ -63,19 +62,19 @@ class ResourceGeneratorTest < Rails::Generators::TestCase content = run_generator ["accounts".freeze] assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ assert_file "test/models/account_test.rb", /class AccountTest/ - assert_match(/Plural version of the model detected, using singularized version. Override with --force-plural./, content) + assert_match(/\[WARNING\] The model name 'accounts' was recognized as a plural, using the singular 'account' instead\. Override with --force-plural or setup custom inflection rules for this noun before running the generator\./, content) end def test_plural_names_can_be_forced content = run_generator ["accounts", "--force-plural"] assert_file "app/models/accounts.rb", /class Accounts < ActiveRecord::Base/ assert_file "test/models/accounts_test.rb", /class AccountsTest/ - assert_no_match(/Plural version of the model detected/, content) + assert_no_match(/\[WARNING\]/, content) end def test_mass_nouns_do_not_throw_warnings content = run_generator ["sheep".freeze] - assert_no_match(/Plural version of the model detected/, content) + assert_no_match(/\[WARNING\]/, content) end def test_route_is_removed_on_revoke diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index 013cb78252..ca972a3bdd 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -81,7 +81,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_helper_are_invoked_with_a_pluralized_name run_generator assert_file "app/helpers/users_helper.rb", /module UsersHelper/ - assert_file "test/helpers/users_helper_test.rb", /class UsersHelperTest < ActionView::TestCase/ end def test_views_are_generated @@ -93,6 +92,14 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_no_file "app/views/layouts/users.html.erb" end + def test_index_page_have_notice + run_generator + + %w(index show).each do |view| + assert_file "app/views/users/#{view}.html.erb", /notice/ + end + end + def test_functional_tests run_generator ["User", "name:string", "age:integer", "organization:references{polymorphic}"] @@ -118,7 +125,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_skip_helper_if_required run_generator ["User", "name:string", "age:integer", "--no-helper"] assert_no_file "app/helpers/users_helper.rb" - assert_no_file "test/helpers/users_helper_test.rb" end def test_skip_layout_if_required @@ -160,10 +166,12 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase Unknown::Generators.send :remove_const, :ActiveModel end - def test_new_hash_style - run_generator - assert_file "app/controllers/users_controller.rb" do |content| - assert_match(/render action: 'new'/, content) + def test_model_name_option + run_generator ["Admin::User", "--model-name=User"] + assert_file "app/controllers/admin/users_controller.rb" do |content| + assert_instance_method :index, content do |m| + assert_match("@users = User.all", m) + end end end end diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 4b837da483..637bde2a44 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -70,7 +70,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_file "app/helpers/product_lines_helper.rb" - assert_file "test/helpers/product_lines_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css" @@ -114,7 +113,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_no_file "app/helpers/product_lines_helper.rb" - assert_no_file "test/helpers/product_lines_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css", /:visited/ @@ -182,7 +180,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_file "app/helpers/admin/roles_helper.rb" - assert_file "test/helpers/admin/roles_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css", /:visited/ @@ -216,7 +213,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_no_file "app/helpers/admin/roles_helper.rb" - assert_no_file "test/helpers/admin/roles_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css" @@ -305,8 +301,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end assert_file "app/views/accounts/_form.html.erb" do |content| - assert_match(/<%= f\.text_field :name %>/, content) - assert_match(/<%= f\.text_field :currency_id %>/, content) + assert_match(/^\W{4}<%= f\.text_field :name %>/, content) + assert_match(/^\W{4}<%= f\.text_field :currency_id %>/, content) end end diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 369a0ee46c..b998fef42e 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -26,11 +26,17 @@ module SharedGeneratorTests default_files.each { |path| assert_file path } end - def test_generation_runs_bundle_install - generator([destination_root]).expects(:bundle_command).with('install').once + def assert_generates_with_bundler(options = {}) + generator([destination_root], options) + generator.expects(:bundle_command).with('install').once + generator.stubs(:bundle_command).with('exec spring binstub --all') quietly { generator.invoke_all } end + def test_generation_runs_bundle_install + assert_generates_with_bundler + end + def test_plugin_new_generate_pretend run_generator ["testapp", "--pretend"] default_files.each{ |path| assert_no_file File.join("testapp",path) } @@ -46,11 +52,6 @@ module SharedGeneratorTests assert_no_file "test" end - def test_options_before_application_name_raises_an_error - content = capture(:stderr){ run_generator(["--pretend", destination_root]) } - assert_match(/Options should be given after the \w+ name. For details run: rails( plugin new)? --help\n/, content) - end - def test_name_collision_raises_an_error reserved_words = %w[application destroy plugin runner test] reserved_words.each do |reserved| @@ -77,9 +78,12 @@ module SharedGeneratorTests end def test_template_raises_an_error_with_invalid_path - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } - assert_match(/The template \[.*\] could not be loaded/, content) - assert_match(/non\/existent\/path/, content) + quietly do + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } + + assert_match(/The template \[.*\] could not be loaded/, content) + assert_match(/non\/existent\/path/, content) + end end def test_template_is_executed_when_supplied @@ -88,7 +92,7 @@ module SharedGeneratorTests template.instance_eval "def read; self; end" # Make the string respond to read generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) + quietly { assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) } end def test_template_is_executed_when_supplied_an_https_path @@ -97,19 +101,17 @@ module SharedGeneratorTests template.instance_eval "def read; self; end" # Make the string respond to read generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) + quietly { assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) } end def test_dev_option - generator([destination_root], dev: true).expects(:bundle_command).with('install').once - quietly { generator.invoke_all } + assert_generates_with_bundler dev: true rails_path = File.expand_path('../../..', Rails.root) assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ end def test_edge_option - generator([destination_root], edge: true).expects(:bundle_command).with('install').once - quietly { generator.invoke_all } + assert_generates_with_bundler edge: true assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} end diff --git a/railties/test/generators/task_generator_test.rb b/railties/test/generators/task_generator_test.rb index 9399be9510..d5bd44b9db 100644 --- a/railties/test/generators/task_generator_test.rb +++ b/railties/test/generators/task_generator_test.rb @@ -7,6 +7,18 @@ class TaskGeneratorTest < Rails::Generators::TestCase def test_task_is_created run_generator - assert_file "lib/tasks/feeds.rake", /namespace :feeds/ + assert_file "lib/tasks/feeds.rake" do |content| + assert_match(/namespace :feeds/, content) + assert_match(/task foo:/, content) + assert_match(/task bar:/, content) + end + end + + def test_task_on_revoke + task_path = 'lib/tasks/feeds.rake' + run_generator + assert_file task_path + run_generator ['feeds'], behavior: :revoke + assert_no_file task_path end end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 5130b285a9..127e059bf1 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/model/model_generator' require 'rails/generators/test_unit/model/model_generator' +require 'mocha/setup' # FIXME: stop using mocha class GeneratorsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -15,14 +16,22 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_simple_invoke - assert File.exists?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke("test_unit:model", ["Account"]) end def test_invoke_when_generator_is_not_found - output = capture(:stdout){ Rails::Generators.invoke :unknown } - assert_equal "Could not find generator unknown.\n", output + name = :unknown + output = capture(:stdout){ Rails::Generators.invoke name } + assert_match "Could not find generator '#{name}'", output + assert_match "`rails generate --help`", output + end + + def test_generator_suggestions + name = :migrationz + output = capture(:stdout){ Rails::Generators.invoke name } + assert_match "Maybe you meant 'migration'", output end def test_help_when_a_generator_with_required_arguments_is_invoked_without_arguments @@ -31,7 +40,7 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_should_give_higher_preference_to_rails_generators - assert File.exists?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) Rails::Generators::ModelGenerator.expects(:start).with(["Account"], {}) warnings = capture(:stderr){ Rails::Generators.invoke :model, ["Account"] } assert warnings.empty? @@ -143,6 +152,8 @@ class GeneratorsTest < Rails::Generators::TestCase klass = Rails::Generators.find_by_namespace(:plugin, :remarkable) assert klass assert_equal "test_unit:plugin", klass.namespace + ensure + Rails::Generators.fallbacks.delete(:remarkable) end def test_fallbacks_for_generators_on_find_by_namespace_with_context @@ -150,18 +161,26 @@ class GeneratorsTest < Rails::Generators::TestCase klass = Rails::Generators.find_by_namespace(:remarkable, :rails, :plugin) assert klass assert_equal "test_unit:plugin", klass.namespace + ensure + Rails::Generators.fallbacks.delete(:remarkable) end def test_fallbacks_for_generators_on_invoke Rails::Generators.fallbacks[:shoulda] = :test_unit TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke "shoulda:model", ["Account"] + ensure + Rails::Generators.fallbacks.delete(:shoulda) end def test_nested_fallbacks_for_generators + Rails::Generators.fallbacks[:shoulda] = :test_unit Rails::Generators.fallbacks[:super_shoulda] = :shoulda TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke "super_shoulda:model", ["Account"] + ensure + Rails::Generators.fallbacks.delete(:shoulda) + Rails::Generators.fallbacks.delete(:super_shoulda) end def test_developer_options_are_overwritten_by_user_options diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index a3295a6e69..40469e31d7 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -9,6 +9,7 @@ require 'fileutils' require 'bundler/setup' unless defined?(Bundler) +require 'active_support' require 'active_support/testing/autorun' require 'active_support/test_case' @@ -93,7 +94,8 @@ module TestHelpers # Build an application by invoking the generator and going through the whole stack. def build_app(options = {}) @prev_rails_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = 'development' + ENV['RAILS_ENV'] = "development" + ENV['SECRET_KEY_BASE'] ||= SecureRandom.hex(16) FileUtils.rm_rf(app_path) FileUtils.cp_r(app_template_path, app_path) @@ -117,11 +119,29 @@ module TestHelpers end end + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: sqlite3 + pool: 5 + timeout: 5000 + development: + <<: *default + database: db/development.sqlite3 + test: + <<: *default + database: db/test.sqlite3 + production: + <<: *default + database: db/production.sqlite3 + YAML + end + add_to_config <<-RUBY config.eager_load = false - config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log + config.active_support.test_order = :random config.action_controller.allow_forgery_protection = false RUBY end @@ -135,10 +155,11 @@ module TestHelpers def make_basic_app require "rails" require "action_controller/railtie" + require "action_view/railtie" app = Class.new(Rails::Application) app.config.eager_load = false - app.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" + app.secrets.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" app.config.session_store :cookie_store, key: "_myapp_session" app.config.active_support.deprecation = :log @@ -242,6 +263,12 @@ module TestHelpers end end + def gsub_app_file(path, regexp, *args, &block) + path = "#{app_path}/#{path}" + content = File.read(path).gsub(regexp, *args, &block) + File.open(path, 'wb') { |f| f.write(content) } + end + def remove_file(path) FileUtils.rm_rf "#{app_path}/#{path}" end @@ -251,8 +278,12 @@ module TestHelpers end def use_frameworks(arr) - to_remove = [:actionmailer, - :activerecord] - arr + to_remove = [:actionmailer, :activerecord] - arr + + if to_remove.include?(:activerecord) + remove_from_config 'config.active_record.*' + end + $:.reject! {|path| path =~ %r'/(#{to_remove.join('|')})/' } end @@ -266,6 +297,35 @@ class ActiveSupport::TestCase include TestHelpers::Paths include TestHelpers::Rack include TestHelpers::Generation + + self.test_order = :sorted + + private + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end + + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end + end + end end # Create a scope and build a fixture rails app diff --git a/railties/test/path_generation_test.rb b/railties/test/path_generation_test.rb new file mode 100644 index 0000000000..13bf29d3c3 --- /dev/null +++ b/railties/test/path_generation_test.rb @@ -0,0 +1,88 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'active_support/core_ext/object/with_options' +require 'active_support/core_ext/object/json' +require 'rails' +require 'rails/application' + +ROUTING = ActionDispatch::Routing + +class PathGenerationTest < ActiveSupport::TestCase + attr_reader :app + + class TestSet < ROUTING::RouteSet + def initialize(block) + @block = block + super() + end + + class Dispatcher < ROUTING::RouteSet::Dispatcher + def initialize(defaults, set, block) + super(defaults) + @block = block + @set = set + end + + def controller_reference(controller_param) + block = @block + set = @set + Class.new(ActionController::Base) { + include set.url_helpers + define_method(:process) { |name| block.call(self) } + def to_a; [200, {}, []]; end + } + end + end + + def dispatcher defaults + TestSet::Dispatcher.new defaults, self, @block + end + end + + def send_request(uri_or_host, method, path, script_name = nil) + host = uri_or_host.host unless path + path ||= uri_or_host.path + + params = {'PATH_INFO' => path, + 'REQUEST_METHOD' => method, + 'HTTP_HOST' => host } + + params['SCRIPT_NAME'] = script_name if script_name + + status, headers, body = app.call(params) + new_body = [] + body.each { |part| new_body << part } + body.close if body.respond_to? :close + [status, headers, new_body] + end + + def test_original_script_name + original_logger = Rails.logger + Rails.logger = Logger.new nil + + app = Class.new(Rails::Application) { + attr_accessor :controller + def initialize + super + app = self + @routes = TestSet.new ->(c) { app.controller = c } + secrets.secret_key_base = "foo" + secrets.secret_token = "foo" + end + def app; routes; end + } + + @app = app + app.routes.draw { resource :blogs } + + url = URI("http://example.org/blogs") + + send_request(url, 'GET', nil, '/FOO') + assert_equal '/FOO/blogs', app.instance.controller.blogs_path + + send_request(url, 'GET', nil) + assert_equal '/blogs', app.instance.controller.blogs_path + ensure + Rails.logger = original_logger + end +end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 12f18b9dbf..1aeb9ec339 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -1,9 +1,10 @@ require 'abstract_unit' require 'rails/paths' +require 'mocha/setup' # FIXME: stop using mocha class PathsTest < ActiveSupport::TestCase def setup - File.stubs(:exists?).returns(true) + File.stubs(:exist?).returns(true) @root = Rails::Paths::Root.new("/foo/bar") end @@ -180,7 +181,7 @@ class PathsTest < ActiveSupport::TestCase assert_equal 1, @root.eager_load.select {|p| p == @root["app"].expanded.first }.size end - test "paths added to a eager_load path should be added to the eager_load collection" do + test "paths added to an eager_load path should be added to the eager_load collection" do @root["app"] = "/app" @root["app"].eager_load! @root["app"] << "/app2" diff --git a/railties/test/rack_logger_test.rb b/railties/test/rack_logger_test.rb index 6ebd47fff9..fcc79b57fb 100644 --- a/railties/test/rack_logger_test.rb +++ b/railties/test/rack_logger_test.rb @@ -39,11 +39,11 @@ module Rails def setup @subscriber = Subscriber.new @notifier = ActiveSupport::Notifications.notifier - notifier.subscribe 'request.action_dispatch', subscriber + @subscription = notifier.subscribe 'request.action_dispatch', subscriber end def teardown - notifier.unsubscribe subscriber + notifier.unsubscribe @subscription end def test_notification diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index a9b237d0a5..8d61af4972 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'mocha/setup' # FIXME: stop using mocha module ActionController class Base diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index 44a5fd1904..4bec302ff8 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -66,16 +66,6 @@ class InfoTest < ActiveSupport::TestCase end protected - def svn_info=(info) - Rails::Info.module_eval do - class << self - def svn_info - info - end - end - end - end - def properties Rails::Info.properties end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index d095535abd..1976466229 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -34,6 +34,7 @@ module RailtiesTest test "serving sprocket's assets" do @plugin.write "app/assets/javascripts/engine.js.erb", "<%= :alert %>();" + add_to_env_config "development", "config.assets.digest = false" boot_rails require 'rack/test' @@ -90,8 +91,8 @@ module RailtiesTest Dir.chdir(app_path) do output = `bundle exec rake bukkits:install:migrations` - assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb") - assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/2_create_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb") assert_match(/Copied migration 2_create_users.bukkits.rb from bukkits/, output) assert_match(/Copied migration 3_add_last_name_to_users.bukkits.rb from bukkits/, output) assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output) @@ -111,6 +112,74 @@ module RailtiesTest end end + test 'respects the order of railties when installing migrations' do + @blog = engine "blog" do |plugin| + plugin.write "lib/blog.rb", <<-RUBY + module Blog + class Engine < ::Rails::Engine + end + end + RUBY + end + + @plugin.write "db/migrate/1_create_users.rb", <<-RUBY + class CreateUsers < ActiveRecord::Migration + end + RUBY + + @blog.write "db/migrate/2_create_blogs.rb", <<-RUBY + class CreateBlogs < ActiveRecord::Migration + end + RUBY + + add_to_config("config.railties_order = [Bukkits::Engine, Blog::Engine, :all, :main_app]") + + boot_rails + + Dir.chdir(app_path) do + output = `bundle exec rake railties:install:migrations`.split("\n") + + assert_match(/Copied migration \d+_create_users.bukkits.rb from bukkits/, output.first) + assert_match(/Copied migration \d+_create_blogs.blog_engine.rb from blog_engine/, output.last) + end + end + + test "dont reverse default railties order" do + @api = engine "api" do |plugin| + plugin.write "lib/api.rb", <<-RUBY + module Api + class Engine < ::Rails::Engine; end + end + RUBY + end + + # added last but here is loaded before api engine + @core = engine "core" do |plugin| + plugin.write "lib/core.rb", <<-RUBY + module Core + class Engine < ::Rails::Engine; end + end + RUBY + end + + @core.write "db/migrate/1_create_users.rb", <<-RUBY + class CreateUsers < ActiveRecord::Migration; end + RUBY + + @api.write "db/migrate/2_create_keys.rb", <<-RUBY + class CreateKeys < ActiveRecord::Migration; end + RUBY + + boot_rails + + Dir.chdir(app_path) do + output = `bundle exec rake railties:install:migrations`.split("\n") + + assert_match(/Copied migration \d+_create_users.core_engine.rb from core_engine/, output.first) + assert_match(/Copied migration \d+_create_keys.api_engine.rb from api_engine/, output.last) + end + end + test "mountable engine should copy migrations within engine_path" do @plugin.write "lib/bukkits.rb", <<-RUBY module Bukkits @@ -136,7 +205,7 @@ module RailtiesTest Dir.chdir(@plugin.path) do output = `bundle exec rake app:bukkits:install:migrations` - assert File.exists?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb") assert_match(/Copied migration 0_add_first_name_to_users.bukkits.rb from bukkits/, output) assert_equal 1, Dir["#{app_path}/db/migrate/*.rb"].length end @@ -399,7 +468,7 @@ YAML assert $plugin_initializer end - test "midleware referenced in configuration" do + test "middleware referenced in configuration" do @plugin.write "lib/bukkits.rb", <<-RUBY class Bukkits def initialize(app) @@ -592,11 +661,15 @@ YAML @plugin.write "app/models/bukkits/post.rb", <<-RUBY module Bukkits class Post - extend ActiveModel::Naming + include ActiveModel::Model def to_param "1" end + + def persisted? + true + end end end RUBY @@ -704,8 +777,7 @@ YAML @plugin.write "app/models/bukkits/post.rb", <<-RUBY module Bukkits class Post - extend ActiveModel::Naming - include ActiveModel::Conversion + include ActiveModel::Model attr_accessor :title def to_param @@ -1077,6 +1149,7 @@ YAML RUBY add_to_config("config.railties_order = [:all, :main_app, Blog::Engine]") + add_to_env_config "development", "config.assets.digest = false" boot_rails diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 0ef2ff2e2e..fb2071c7c3 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -88,18 +88,14 @@ module ApplicationTests @plugin.write "app/models/blog/post.rb", <<-RUBY module Blog class Post - extend ActiveModel::Naming + include ActiveModel::Model def id 44 end - def to_param - id.to_s - end - - def new_record? - false + def persisted? + true end end end diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 4cbd4822be..5042d628cf 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -72,6 +72,14 @@ module RailtiesTest assert $to_prepare end + test "railtie have access to application in before_configuration callbacks" do + $before_configuration = false + class Foo < Rails::Railtie ; config.before_configuration { $before_configuration = Rails.root.to_path } ; end + assert_not $before_configuration + require "#{app_path}/config/environment" + assert_equal app_path, $before_configuration + end + test "railtie can add after_initialize callbacks" do $after_initialize = false class Foo < Rails::Railtie ; config.after_initialize { $after_initialize = true } ; end diff --git a/railties/test/version_test.rb b/railties/test/version_test.rb new file mode 100644 index 0000000000..f270d8f0c9 --- /dev/null +++ b/railties/test/version_test.rb @@ -0,0 +1,12 @@ +require 'abstract_unit' + +class VersionTest < ActiveSupport::TestCase + def test_rails_version_returns_a_string + assert Rails.version.is_a? String + end + + def test_rails_gem_version_returns_a_correct_gem_version_object + assert Rails.gem_version.is_a? Gem::Version + assert_equal Rails.version, Rails.gem_version.to_s + end +end |