Create Rails::Generators::TestCase.

This commit is contained in:
José Valim 2010-01-03 15:13:54 +01:00
parent e88ea3255f
commit 441227a10f
9 changed files with 260 additions and 112 deletions

View File

@ -272,7 +272,7 @@ module Rails
# parameters.
#
def invoked?(args)
args.last.is_a?(Hash) && args.last.key?(:invocations)
args.last.is_a?(Hash) && (args.last.key?(:invocations) || args.last.key?(:destination_root))
end
# Use Rails default banner.

View File

@ -0,0 +1,224 @@
require 'active_support/test_case'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/hash/reverse_merge'
require 'rails/generators'
require 'fileutils'
module Rails
module Generators
# Disable color in output. Easier to debug.
no_color!
# This class provides a TestCase for testing generators. To setup, you need
# just to configure the destination and set which generator is being tested:
#
# class AppGeneratorTest < Rails::Generators::TestCase
# tests AppGenerator
# destination File.expand_path("../tmp", File.dirname(__FILE__))
# end
#
# If you want to ensure your destination root is clean before running each test,
# you can set a setup callback:
#
# class AppGeneratorTest < Rails::Generators::TestCase
# tests AppGenerator
# destination File.expand_path("../tmp", File.dirname(__FILE__))
# setup :prepare_destination
# end
#
class TestCase < ActiveSupport::TestCase
include FileUtils
extlib_inheritable_accessor :destination_root, :current_path, :instance_writer => false
extlib_inheritable_accessor :generator_class
# Generators frequently change the current path using +FileUtils.cd+.
# So we need to store the path at file load and revert back to it after each test.
self.current_path = File.expand_path(Dir.pwd)
setup :destination_root_is_set?, :ensure_current_path
teardown :ensure_current_path
# Sets which generator should be tested:
#
# tests AppGenerator
#
def self.tests(klass)
self.generator_class = klass
end
# Sets the destination of generator files:
#
# destination File.expand_path("../tmp", File.dirname(__FILE__))
#
def self.destination(path)
self.destination_root = path
end
# Captures the given stream and returns it:
#
# stream = capture(:stdout){ puts "Cool" }
# stream #=> "Cool\n"
#
def capture(stream)
begin
stream = stream.to_s
eval "$#{stream} = StringIO.new"
yield
result = eval("$#{stream}").string
ensure
eval("$#{stream} = #{stream.upcase}")
end
result
end
alias :silence :capture
# Asserts a given file exists. You need to supply an absolute path or a path relative
# to the configured destination:
#
# assert_file "config/environment.rb"
#
# You can also give extra arguments. If the argument is a regexp, it will check if the
# regular expression matches the given file content. If it's a string, it compares the
# file with the given string:
#
# assert_file "config/environment.rb", /initialize/
#
# Finally, when a block is given, it yields the file content:
#
# assert_file "app/controller/products_controller.rb" do |controller|
# assert_instance_method :index, content do |index|
# assert_match /Product\.all/, index
# end
# end
#
def assert_file(relative, *contents)
absolute = File.expand_path(relative, destination_root)
assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not"
read = File.read(absolute) if block_given? || !contents.empty?
yield read if block_given?
contents.each do |content|
case content
when String
assert_equal content, read
when Regexp
assert_match content, read
end
end
end
alias :assert_directory :assert_file
# Asserts a given file does not exist. You need to supply an absolute path or a
# path relative to the configured destination:
#
# assert_no_file "config/random.rb"
#
def assert_no_file(relative)
absolute = File.expand_path(relative, destination_root)
assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does"
end
alias :assert_no_directory :assert_no_file
# Asserts a given file does not exist. You need to supply an absolute path or a
# path relative to the configured destination:
#
# assert_migration "db/migrate/create_products.rb"
#
# This method manipulates the given path and tries to find any migration which
# matches the migration name. For example, the call above is converted to:
#
# assert_file "db/migrate/003_create_products.rb"
#
# Consequently, assert_migration accepts the same arguments has assert_file.
#
def assert_migration(relative, *contents, &block)
file_name = migration_file_name(relative)
assert file_name, "Expected migration #{relative} to exist, but was not found"
assert_file file_name, *contents, &block
end
# Asserts a given migration does not exist. You need to supply an absolute path or a
# path relative to the configured destination:
#
# assert_no_file "config/random.rb"
#
def assert_no_migration(relative)
file_name = migration_file_name(relative)
assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
end
# Asserts the given class method exists in the given content. This method does not detect
# class methods inside (class << self), only class methods which starts with "self.".
# When a block is given, it yields the content of the method.
#
# assert_migration "db/migrate/create_products.rb" do |migration|
# assert_class_method :up, migration do |up|
# assert_match /create_table/, up
# end
# end
#
def assert_class_method(method, content, &block)
assert_instance_method "self.#{method}", content, &block
end
# Asserts the given method exists in the given content. When a block is given,
# it yields the content of the method.
#
# assert_file "app/controller/products_controller.rb" do |controller|
# assert_instance_method :index, content do |index|
# assert_match /Product\.all/, index
# end
# end
#
def assert_instance_method(method, content)
assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}"
yield $2.strip if block_given?
end
alias :assert_method :assert_instance_method
# Runs the generator configured for this class. The first argument is an array like
# command line arguments:
#
# class AppGeneratorTest < Rails::Generators::TestCase
# tests AppGenerator
# destination File.expand_path("../tmp", File.dirname(__FILE__))
# teardown :cleanup_destination_root
#
# test "database.yml is not created when skipping activerecord" do
# run_generator %w(myapp --skip-activerecord)
# assert_no_file "config/database.yml"
# end
# end
#
# You can provide a configuration hash as second argument. This method returns the output
# printed by the generator.
def run_generator(args=[], config={})
capture(:stdout) { self.generator_class.start args, config.reverse_merge(:destination_root => destination_root) }
end
protected
def destination_root_is_set? #:nodoc:
raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root
end
def ensure_current_path #:nodoc:
cd current_path
end
def prepare_destination
rm_rf(destination_root)
mkdir_p(destination_root)
end
def migration_file_name(relative) #:nodoc:
absolute = File.expand_path(relative, destination_root)
dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '')
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
end
end
end
end

View File

@ -6,7 +6,7 @@ class ControllerGeneratorTest < GeneratorsTestCase
def test_help_does_not_show_invoked_generators_options_if_they_already_exist
content = run_generator ["--help"]
assert_no_match /Helper options:/, content
assert_no_match /Helper options\:/, content
end
def test_controller_skeleton_is_created
@ -66,8 +66,8 @@ class ControllerGeneratorTest < GeneratorsTestCase
run_generator
assert_file "app/controllers/account_controller.rb" do |controller|
assert_instance_method controller, :foo
assert_instance_method controller, :bar
assert_instance_method :foo, controller
assert_instance_method :bar, controller
end
end

View File

@ -10,93 +10,17 @@ end
Rails.application.config.root = Rails.root
require 'rails/generators'
require 'rails/generators/test_case'
require 'rubygems'
require 'active_record'
require 'action_dispatch'
CURRENT_PATH = File.expand_path(Dir.pwd)
Rails::Generators.no_color!
class GeneratorsTestCase < ActiveSupport::TestCase
include FileUtils
def destination_root
File.join(Rails.root, "tmp")
end
def setup
cd CURRENT_PATH
rm_rf(destination_root)
mkdir_p(destination_root)
end
class GeneratorsTestCase < Rails::Generators::TestCase
destination File.join(Rails.root, "tmp")
setup :prepare_destination
def test_truth
# don't complain, test/unit
# Don't cry test unit
end
def capture(stream)
begin
stream = stream.to_s
eval "$#{stream} = StringIO.new"
yield
result = eval("$#{stream}").string
ensure
eval("$#{stream} = #{stream.upcase}")
end
result
end
alias :silence :capture
def assert_file(relative, *contents)
absolute = File.join(destination_root, relative)
assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not"
read = File.read(absolute) if block_given? || !contents.empty?
yield read if block_given?
contents.each do |content|
case content
when String
assert_equal content, read
when Regexp
assert_match content, read
end
end
end
def assert_no_file(relative)
absolute = File.join(destination_root, relative)
assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does"
end
def assert_migration(relative, *contents, &block)
file_name = migration_file_name(relative)
assert file_name, "Expected migration #{relative} to exist, but was not found"
assert_file File.join(File.dirname(relative), file_name), *contents, &block
end
def assert_no_migration(relative)
file_name = migration_file_name(relative)
assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
end
def assert_class_method(content, method, &block)
assert_instance_method content, "self.#{method}", &block
end
def assert_instance_method(content, method)
assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}"
yield $2.strip if block_given?
end
protected
def migration_file_name(relative)
absolute = File.join(destination_root, relative)
dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '')
migration = Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
File.basename(migration) if migration
end
end
end

View File

@ -21,12 +21,12 @@ class MigrationGeneratorTest < GeneratorsTestCase
run_generator [@migration, "title:string", "body:text"]
assert_migration "db/migrate/#{@migration}.rb" do |content|
assert_class_method content, :up do |up|
assert_class_method :up, content do |up|
assert_match /add_column :posts, :title, :string/, up
assert_match /add_column :posts, :body, :text/, up
end
assert_class_method content, :down do |down|
assert_class_method :down, content do |down|
assert_match /remove_column :posts, :title/, down
assert_match /remove_column :posts, :body/, down
end
@ -38,12 +38,12 @@ class MigrationGeneratorTest < GeneratorsTestCase
run_generator [@migration, "title:string", "body:text"]
assert_migration "db/migrate/#{@migration}.rb" do |content|
assert_class_method content, :up do |up|
assert_class_method :up, content do |up|
assert_match /remove_column :posts, :title/, up
assert_match /remove_column :posts, :body/, up
end
assert_class_method content, :down do |down|
assert_class_method :down, content do |down|
assert_match /add_column :posts, :title, :string/, down
assert_match /add_column :posts, :body, :text/, down
end

View File

@ -84,13 +84,13 @@ class ModelGeneratorTest < GeneratorsTestCase
run_generator ["product", "name:string", "supplier_id:integer"]
assert_migration "db/migrate/create_products.rb" do |m|
assert_class_method m, :up do |up|
assert_class_method :up, m do |up|
assert_match /create_table :products/, up
assert_match /t\.string :name/, up
assert_match /t\.integer :supplier_id/, up
end
assert_class_method m, :down do |down|
assert_class_method :down, m do |down|
assert_match /drop_table :products/, down
end
end
@ -126,7 +126,7 @@ class ModelGeneratorTest < GeneratorsTestCase
run_generator ["account", "--no-timestamps"]
assert_migration "db/migrate/create_accounts.rb" do |m|
assert_class_method m, :up do |up|
assert_class_method :up, m do |up|
assert_no_match /t.timestamps/, up
end
end

View File

@ -50,8 +50,8 @@ class ResourceGeneratorTest < GeneratorsTestCase
run_generator ["account", "--actions", "index", "new"]
assert_file "app/controllers/accounts_controller.rb" do |controller|
assert_instance_method controller, :index
assert_instance_method controller, :new
assert_instance_method :index, controller
assert_instance_method :new, controller
end
assert_file "app/views/accounts/index.html.erb"

View File

@ -15,35 +15,35 @@ class ScaffoldControllerGeneratorTest < GeneratorsTestCase
assert_file "app/controllers/users_controller.rb" do |content|
assert_match /class UsersController < ApplicationController/, content
assert_instance_method content, :index do |m|
assert_instance_method :index, content do |m|
assert_match /@users = User\.all/, m
end
assert_instance_method content, :show do |m|
assert_instance_method :show, content do |m|
assert_match /@user = User\.find\(params\[:id\]\)/, m
end
assert_instance_method content, :new do |m|
assert_instance_method :new, content do |m|
assert_match /@user = User\.new/, m
end
assert_instance_method content, :edit do |m|
assert_instance_method :edit, content do |m|
assert_match /@user = User\.find\(params\[:id\]\)/, m
end
assert_instance_method content, :create do |m|
assert_instance_method :create, content do |m|
assert_match /@user = User\.new\(params\[:user\]\)/, m
assert_match /@user\.save/, m
assert_match /@user\.errors/, m
end
assert_instance_method content, :update do |m|
assert_instance_method :update, content do |m|
assert_match /@user = User\.find\(params\[:id\]\)/, m
assert_match /@user\.update_attributes\(params\[:user\]\)/, m
assert_match /@user\.errors/, m
end
assert_instance_method content, :destroy do |m|
assert_instance_method :destroy, content do |m|
assert_match /@user = User\.find\(params\[:id\]\)/, m
assert_match /@user\.destroy/, m
end
@ -108,7 +108,7 @@ class ScaffoldControllerGeneratorTest < GeneratorsTestCase
assert_file "app/controllers/users_controller.rb" do |content|
assert_match /class UsersController < ApplicationController/, content
assert_instance_method content, :index do |m|
assert_instance_method :index, content do |m|
assert_match /@users = User\.all/, m
end
end
@ -127,7 +127,7 @@ class ScaffoldControllerGeneratorTest < GeneratorsTestCase
assert_file "app/controllers/users_controller.rb" do |content|
assert_match /class UsersController < ApplicationController/, content
assert_instance_method content, :index do |m|
assert_instance_method :index, content do |m|
assert_match /@users = User\.find\(:all\)/, m
assert_no_match /@users = User\.all/, m
end

View File

@ -32,35 +32,35 @@ class ScaffoldGeneratorTest < GeneratorsTestCase
assert_file "app/controllers/product_lines_controller.rb" do |content|
assert_match /class ProductLinesController < ApplicationController/, content
assert_instance_method content, :index do |m|
assert_instance_method :index, content do |m|
assert_match /@product_lines = ProductLine\.all/, m
end
assert_instance_method content, :show do |m|
assert_instance_method :show, content do |m|
assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
end
assert_instance_method content, :new do |m|
assert_instance_method :new, content do |m|
assert_match /@product_line = ProductLine\.new/, m
end
assert_instance_method content, :edit do |m|
assert_instance_method :edit, content do |m|
assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
end
assert_instance_method content, :create do |m|
assert_instance_method :create, content do |m|
assert_match /@product_line = ProductLine\.new\(params\[:product_line\]\)/, m
assert_match /@product_line\.save/, m
assert_match /@product_line\.errors/, m
end
assert_instance_method content, :update do |m|
assert_instance_method :update, content do |m|
assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
assert_match /@product_line\.update_attributes\(params\[:product_line\]\)/, m
assert_match /@product_line\.errors/, m
end
assert_instance_method content, :destroy do |m|
assert_instance_method :destroy, content do |m|
assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
assert_match /@product_line\.destroy/, m
end