diff --git a/test/lib/shoulda.rb b/test/lib/shoulda.rb
deleted file mode 100755
index a90ff18..0000000
--- a/test/lib/shoulda.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'shoulda/gem/shoulda'
-require 'shoulda/private_helpers'
-require 'shoulda/general'
-require 'shoulda/active_record_helpers'
-require 'shoulda/controller_tests/controller_tests.rb'
-require 'yaml'
-
-shoulda_options = {}
-
-possible_config_paths = []
-possible_config_paths << File.join(ENV["HOME"], ".shoulda.conf") if ENV["HOME"]
-possible_config_paths << "shoulda.conf"
-possible_config_paths << File.join("test", "shoulda.conf")
-possible_config_paths << File.join(RAILS_ROOT, "test", "shoulda.conf") if defined?(RAILS_ROOT)
-
-possible_config_paths.each do |config_file|
- if File.exists? config_file
- shoulda_options = YAML.load_file(config_file).symbolize_keys
- break
- end
-end
-
-require 'shoulda/color' if shoulda_options[:color]
-
-module Test # :nodoc: all
- module Unit
- class TestCase
-
- include ThoughtBot::Shoulda::General
- include ThoughtBot::Shoulda::Controller
-
- extend ThoughtBot::Shoulda::ActiveRecord
- end
- end
-end
-
-module ActionController #:nodoc: all
- module Integration
- class Session
- include ThoughtBot::Shoulda::General
- end
- end
-end
diff --git a/test/lib/shoulda/active_record_helpers.rb b/test/lib/shoulda/active_record_helpers.rb
deleted file mode 100755
index 8133755..0000000
--- a/test/lib/shoulda/active_record_helpers.rb
+++ /dev/null
@@ -1,576 +0,0 @@
-module ThoughtBot # :nodoc:
- module Shoulda # :nodoc:
- # = Macro test helpers for your active record models
- #
- # These helpers will test most of the validations and associations for your ActiveRecord models.
- #
- # class UserTest < Test::Unit::TestCase
- # should_require_attributes :name, :phone_number
- # should_not_allow_values_for :phone_number, "abcd", "1234"
- # should_allow_values_for :phone_number, "(123) 456-7890"
- #
- # should_protect_attributes :password
- #
- # should_have_one :profile
- # should_have_many :dogs
- # should_have_many :messes, :through => :dogs
- # should_belong_to :lover
- # end
- #
- # For all of these helpers, the last parameter may be a hash of options.
- #
- module ActiveRecord
- # Ensures that the model cannot be saved if one of the attributes listed is not present.
- #
- # Options:
- # * :message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /blank/
- #
- # Example:
- # should_require_attributes :name, :phone_number
- #
- def should_require_attributes(*attributes)
- message = get_options!(attributes, :message)
- message ||= /blank/
- klass = model_class
-
- attributes.each do |attribute|
- should "require #{attribute} to be set" do
- object = klass.new
- object.send("#{attribute}=", nil)
- assert !object.valid?, "#{klass.name} does not require #{attribute}."
- assert object.errors.on(attribute), "#{klass.name} does not require #{attribute}."
- assert_contains(object.errors.on(attribute), message)
- end
- end
- end
-
- # Ensures that the model cannot be saved if one of the attributes listed is not unique.
- # Requires an existing record
- #
- # Options:
- # * :message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /taken/
- #
- # Example:
- # should_require_unique_attributes :keyword, :username
- #
- def should_require_unique_attributes(*attributes)
- message, scope = get_options!(attributes, :message, :scoped_to)
- message ||= /taken/
-
- klass = model_class
- attributes.each do |attribute|
- attribute = attribute.to_sym
- should "require unique value for #{attribute}#{" scoped to #{scope}" if scope}" do
- assert existing = klass.find(:first), "Can't find first #{klass}"
- object = klass.new
-
- object.send(:"#{attribute}=", existing.send(attribute))
- if scope
- assert_respond_to object, :"#{scope}=", "#{klass.name} doesn't seem to have a #{scope} attribute."
- object.send(:"#{scope}=", existing.send(scope))
- end
-
- assert !object.valid?, "#{klass.name} does not require a unique value for #{attribute}."
- assert object.errors.on(attribute), "#{klass.name} does not require a unique value for #{attribute}."
-
- assert_contains(object.errors.on(attribute), message)
-
- # Now test that the object is valid when changing the scoped attribute
- # TODO: There is a chance that we could change the scoped field
- # to a value that's already taken. An alternative implementation
- # could actually find all values for scope and create a unique
- # one.
- if scope
- # Assume the scope is a foreign key if the field is nil
- object.send(:"#{scope}=", existing.send(scope).nil? ? 1 : existing.send(scope).next)
- object.errors.clear
- object.valid?
- assert_does_not_contain(object.errors.on(attribute), message,
- "after :#{scope} set to #{object.send(scope.to_sym)}")
- end
- end
- end
- end
-
- # Ensures that the attribute cannot be set on mass update.
- # Requires an existing record.
- #
- # should_protect_attributes :password, :admin_flag
- #
- def should_protect_attributes(*attributes)
- get_options!(attributes)
- klass = model_class
-
- attributes.each do |attribute|
- attribute = attribute.to_sym
- should "protect #{attribute} from mass updates" do
- protected_attributes = klass.protected_attributes || []
- assert protected_attributes.include?(attribute.to_s),
- "#{klass} is protecting #{protected_attributes.to_a.to_sentence}, but not #{attribute}."
- end
- end
- end
-
- # Ensures that the attribute cannot be set to the given values
- # Requires an existing record
- #
- # Options:
- # * :message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /invalid/
- #
- # Example:
- # should_not_allow_values_for :isbn, "bad 1", "bad 2"
- #
- def should_not_allow_values_for(attribute, *bad_values)
- message = get_options!(bad_values, :message)
- message ||= /invalid/
- klass = model_class
- bad_values.each do |v|
- should "not allow #{attribute} to be set to #{v.inspect}" do
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
- assert_contains(object.errors.on(attribute), message, "when set to \"#{v}\"")
- end
- end
- end
-
- # Ensures that the attribute can be set to the given values.
- # Requires an existing record
- #
- # Example:
- # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
- #
- def should_allow_values_for(attribute, *good_values)
- get_options!(good_values)
- klass = model_class
- good_values.each do |v|
- should "allow #{attribute} to be set to #{v.inspect}" do
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- object.save
- assert_nil object.errors.on(attribute)
- end
- end
- end
-
- # Ensures that the length of the attribute is in the given range
- # Requires an existing record
- #
- # Options:
- # * :short_message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /short/
- # * :long_message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /long/
- #
- # Example:
- # should_ensure_length_in_range :password, (6..20)
- #
- def should_ensure_length_in_range(attribute, range, opts = {})
- short_message, long_message = get_options!([opts], :short_message, :long_message)
- short_message ||= /short/
- long_message ||= /long/
-
- klass = model_class
- min_length = range.first
- max_length = range.last
- same_length = (min_length == max_length)
-
- if min_length > 0
- should "not allow #{attribute} to be less than #{min_length} chars long" do
- min_value = "x" * (min_length - 1)
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", min_value)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{min_value}\""
- assert object.errors.on(attribute),
- "There are no errors set on #{attribute} after being set to \"#{min_value}\""
- assert_contains(object.errors.on(attribute), short_message, "when set to \"#{min_value}\"")
- end
- end
-
- if min_length > 0
- should "allow #{attribute} to be exactly #{min_length} chars long" do
- min_value = "x" * min_length
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", min_value)
- object.save
- assert_does_not_contain(object.errors.on(attribute), short_message, "when set to \"#{min_value}\"")
- end
- end
-
- should "not allow #{attribute} to be more than #{max_length} chars long" do
- max_value = "x" * (max_length + 1)
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", max_value)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{max_value}\""
- assert object.errors.on(attribute),
- "There are no errors set on #{attribute} after being set to \"#{max_value}\""
- assert_contains(object.errors.on(attribute), long_message, "when set to \"#{max_value}\"")
- end
-
- unless same_length
- should "allow #{attribute} to be exactly #{max_length} chars long" do
- max_value = "x" * max_length
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", max_value)
- object.save
- assert_does_not_contain(object.errors.on(attribute), long_message, "when set to \"#{max_value}\"")
- end
- end
- end
-
- # Ensures that the length of the attribute is at least a certain length
- # Requires an existing record
- #
- # Options:
- # * :short_message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /short/
- #
- # Example:
- # should_ensure_length_at_least :name, 3
- #
- def should_ensure_length_at_least(attribute, min_length, opts = {})
- short_message = get_options!([opts], :short_message)
- short_message ||= /short/
-
- klass = model_class
-
- if min_length > 0
- min_value = "x" * (min_length - 1)
- should "not allow #{attribute} to be less than #{min_length} chars long" do
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", min_value)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{min_value}\""
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{min_value}\""
- assert_contains(object.errors.on(attribute), short_message, "when set to \"#{min_value}\"")
- end
- end
- should "allow #{attribute} to be at least #{min_length} chars long" do
- valid_value = "x" * (min_length)
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", valid_value)
- assert object.save, "Could not save #{klass} with #{attribute} set to \"#{valid_value}\""
- end
- end
-
- # Ensure that the attribute is in the range specified
- # Requires an existing record
- #
- # Options:
- # * :low_message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /included/
- # * :high_message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /included/
- #
- # Example:
- # should_ensure_value_in_range :age, (0..100)
- #
- def should_ensure_value_in_range(attribute, range, opts = {})
- low_message, high_message = get_options!([opts], :low_message, :high_message)
- low_message ||= /included/
- high_message ||= /included/
-
- klass = model_class
- min = range.first
- max = range.last
-
- should "not allow #{attribute} to be less than #{min}" do
- v = min - 1
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
- assert_contains(object.errors.on(attribute), low_message, "when set to \"#{v}\"")
- end
-
- should "allow #{attribute} to be #{min}" do
- v = min
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- object.save
- assert_does_not_contain(object.errors.on(attribute), low_message, "when set to \"#{v}\"")
- end
-
- should "not allow #{attribute} to be more than #{max}" do
- v = max + 1
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
- assert_contains(object.errors.on(attribute), high_message, "when set to \"#{v}\"")
- end
-
- should "allow #{attribute} to be #{max}" do
- v = max
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send("#{attribute}=", v)
- object.save
- assert_does_not_contain(object.errors.on(attribute), high_message, "when set to \"#{v}\"")
- end
- end
-
- # Ensure that the attribute is numeric
- # Requires an existing record
- #
- # Options:
- # * :message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /number/
- #
- # Example:
- # should_only_allow_numeric_values_for :age
- #
- def should_only_allow_numeric_values_for(*attributes)
- message = get_options!(attributes, :message)
- message ||= /number/
- klass = model_class
- attributes.each do |attribute|
- attribute = attribute.to_sym
- should "only allow numeric values for #{attribute}" do
- assert object = klass.find(:first), "Can't find first #{klass}"
- object.send(:"#{attribute}=", "abcd")
- assert !object.valid?, "Instance is still valid"
- assert_contains(object.errors.on(attribute), message)
- end
- end
- end
-
- # Ensures that the has_many relationship exists. Will also test that the
- # associated table has the required columns. Works with polymorphic
- # associations.
- #
- # Options:
- # * :through - association name for has_many :through
- #
- # Example:
- # should_have_many :friends
- # should_have_many :enemies, :through => :friends
- #
- def should_have_many(*associations)
- through = get_options!(associations, :through)
- klass = model_class
- associations.each do |association|
- name = "have many #{association}"
- name += " through #{through}" if through
- should name do
- reflection = klass.reflect_on_association(association)
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
- assert_equal :has_many, reflection.macro
-
- if through
- through_reflection = klass.reflect_on_association(through)
- assert through_reflection, "#{klass.name} does not have any relationship to #{through}"
- assert_equal(through, reflection.options[:through])
- end
-
- unless reflection.options[:through]
- # This is not a through association, so check for the existence of the foreign key on the other table
- if reflection.options[:foreign_key]
- fk = reflection.options[:foreign_key]
- elsif reflection.options[:as]
- fk = reflection.options[:as].to_s.foreign_key
- else
- fk = reflection.primary_key_name
- end
- associated_klass = (reflection.options[:class_name] || association.to_s.classify).constantize
- assert associated_klass.column_names.include?(fk.to_s), "#{associated_klass.name} does not have a #{fk} foreign key."
- end
- end
- end
- end
-
- # Ensure that the has_one relationship exists. Will also test that the
- # associated table has the required columns. Works with polymorphic
- # associations.
- #
- # Example:
- # should_have_one :god # unless hindu
- #
- def should_have_one(*associations)
- get_options!(associations)
- klass = model_class
- associations.each do |association|
- should "have one #{association}" do
- reflection = klass.reflect_on_association(association)
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
- assert_equal :has_one, reflection.macro
-
- associated_klass = (reflection.options[:class_name] || association.to_s.camelize).constantize
-
- if reflection.options[:foreign_key]
- fk = reflection.options[:foreign_key]
- elsif reflection.options[:as]
- fk = reflection.options[:as].to_s.foreign_key
- fk_type = fk.gsub(/_id$/, '_type')
- assert associated_klass.column_names.include?(fk_type),
- "#{associated_klass.name} does not have a #{fk_type} column."
- else
- fk = klass.name.foreign_key
- end
- assert associated_klass.column_names.include?(fk.to_s),
- "#{associated_klass.name} does not have a #{fk} foreign key."
- end
- end
- end
-
- # Ensures that the has_and_belongs_to_many relationship exists, and that the join
- # table is in place.
- #
- # should_have_and_belong_to_many :posts, :cars
- #
- def should_have_and_belong_to_many(*associations)
- get_options!(associations)
- klass = model_class
-
- associations.each do |association|
- should "should have and belong to many #{association}" do
- reflection = klass.reflect_on_association(association)
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
- assert_equal :has_and_belongs_to_many, reflection.macro
- table = reflection.options[:join_table]
- assert ::ActiveRecord::Base.connection.tables.include?(table), "table #{table} doesn't exist"
- end
- end
- end
-
- # Ensure that the belongs_to relationship exists.
- #
- # should_belong_to :parent
- #
- def should_belong_to(*associations)
- get_options!(associations)
- klass = model_class
- associations.each do |association|
- should "belong_to #{association}" do
- reflection = klass.reflect_on_association(association)
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
- assert_equal :belongs_to, reflection.macro
-
- unless reflection.options[:polymorphic]
- associated_klass = (reflection.options[:class_name] || association.to_s.classify).constantize
- fk = reflection.options[:foreign_key] || reflection.primary_key_name
- assert klass.column_names.include?(fk.to_s), "#{klass.name} does not have a #{fk} foreign key."
- end
- end
- end
- end
-
- # Ensure that the given class methods are defined on the model.
- #
- # should_have_class_methods :find, :destroy
- #
- def should_have_class_methods(*methods)
- get_options!(methods)
- klass = model_class
- methods.each do |method|
- should "respond to class method ##{method}" do
- assert_respond_to klass, method, "#{klass.name} does not have class method #{method}"
- end
- end
- end
-
- # Ensure that the given instance methods are defined on the model.
- #
- # should_have_instance_methods :email, :name, :name=
- #
- def should_have_instance_methods(*methods)
- get_options!(methods)
- klass = model_class
- methods.each do |method|
- should "respond to instance method ##{method}" do
- assert_respond_to klass.new, method, "#{klass.name} does not have instance method #{method}"
- end
- end
- end
-
- # Ensure that the given columns are defined on the models backing SQL table.
- #
- # should_have_db_columns :id, :email, :name, :created_at
- #
- def should_have_db_columns(*columns)
- column_type = get_options!(columns, :type)
- klass = model_class
- columns.each do |name|
- test_name = "have column #{name}"
- test_name += " of type #{column_type}" if column_type
- should test_name do
- column = klass.columns.detect {|c| c.name == name.to_s }
- assert column, "#{klass.name} does not have column #{name}"
- end
- end
- end
-
- # Ensure that the given column is defined on the models backing SQL table. The options are the same as
- # the instance variables defined on the column definition: :precision, :limit, :default, :null,
- # :primary, :type, :scale, and :sql_type.
- #
- # should_have_db_column :email, :type => "string", :default => nil, :precision => nil, :limit => 255,
- # :null => true, :primary => false, :scale => nil, :sql_type => 'varchar(255)'
- #
- def should_have_db_column(name, opts = {})
- klass = model_class
- test_name = "have column named :#{name}"
- test_name += " with options " + opts.inspect unless opts.empty?
- should test_name do
- column = klass.columns.detect {|c| c.name == name.to_s }
- assert column, "#{klass.name} does not have column #{name}"
- opts.each do |k, v|
- assert_equal column.instance_variable_get("@#{k}").to_s, v.to_s, ":#{name} column on table for #{klass} does not match option :#{k}"
- end
- end
- end
-
- # Ensures that there are DB indices on the given columns or tuples of columns.
- # Also aliased to should_have_index for readability
- #
- # should_have_indices :email, :name, [:commentable_type, :commentable_id]
- # should_have_index :age
- #
- def should_have_indices(*columns)
- table = model_class.name.tableize
- indices = ::ActiveRecord::Base.connection.indexes(table).map(&:columns)
-
- columns.each do |column|
- should "have index on #{table} for #{column.inspect}" do
- columns = [column].flatten.map(&:to_s)
- assert_contains(indices, columns)
- end
- end
- end
-
- alias_method :should_have_index, :should_have_indices
-
- # Ensures that the model cannot be saved if one of the attributes listed is not accepted.
- #
- # Options:
- # * :message - value the test expects to find in errors.on(:attribute).
- # Regexp or string. Default = /must be accepted/
- #
- # Example:
- # should_require_acceptance_of :eula
- #
- def should_require_acceptance_of(*attributes)
- message = get_options!(attributes, :message)
- message ||= /must be accepted/
- klass = model_class
-
- attributes.each do |attribute|
- should "require #{attribute} to be accepted" do
- object = klass.new
- object.send("#{attribute}=", false)
-
- assert !object.valid?, "#{klass.name} does not require acceptance of #{attribute}."
- assert object.errors.on(attribute), "#{klass.name} does not require acceptance of #{attribute}."
- assert_contains(object.errors.on(attribute), message)
- end
- end
- end
-
- private
-
- include ThoughtBot::Shoulda::Private
- end
- end
-end
diff --git a/test/lib/shoulda/color.rb b/test/lib/shoulda/color.rb
deleted file mode 100755
index 1ccfad2..0000000
--- a/test/lib/shoulda/color.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require 'test/unit/ui/console/testrunner'
-
-# Completely stolen from redgreen gem
-#
-# Adds colored output to your tests. Specify color: true in
-# your ~/.shoulda.conf file to enable.
-#
-# *Bug*: for some reason, this adds another line of output to the end of
-# every rake task, as though there was another (empty) set of tests.
-# A fix would be most welcome.
-#
-module ThoughtBot::Shoulda::Color
- COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33 } # :nodoc:
- def self.method_missing(color_name, *args) # :nodoc:
- color(color_name) + args.first + color(:clear)
- end
- def self.color(color) # :nodoc:
- "\e[#{COLORS[color.to_sym]}m"
- end
-end
-
-module Test # :nodoc:
- module Unit # :nodoc:
- class TestResult # :nodoc:
- alias :old_to_s :to_s
- def to_s
- if old_to_s =~ /\d+ tests, \d+ assertions, (\d+) failures, (\d+) errors/
- ThoughtBot::Shoulda::Color.send($1.to_i != 0 || $2.to_i != 0 ? :red : :green, $&)
- end
- end
- end
-
- class AutoRunner # :nodoc:
- alias :old_initialize :initialize
- def initialize(standalone)
- old_initialize(standalone)
- @runner = proc do |r|
- Test::Unit::UI::Console::RedGreenTestRunner
- end
- end
- end
-
- class Failure # :nodoc:
- alias :old_long_display :long_display
- def long_display
- # old_long_display.sub('Failure', ThoughtBot::Shoulda::Color.red('Failure'))
- ThoughtBot::Shoulda::Color.red(old_long_display)
- end
- end
-
- class Error # :nodoc:
- alias :old_long_display :long_display
- def long_display
- # old_long_display.sub('Error', ThoughtBot::Shoulda::Color.yellow('Error'))
- ThoughtBot::Shoulda::Color.yellow(old_long_display)
- end
- end
-
- module UI # :nodoc:
- module Console # :nodoc:
- class RedGreenTestRunner < Test::Unit::UI::Console::TestRunner # :nodoc:
- def output_single(something, level=NORMAL)
- return unless (output?(level))
- something = case something
- when '.' then ThoughtBot::Shoulda::Color.green('.')
- when 'F' then ThoughtBot::Shoulda::Color.red("F")
- when 'E' then ThoughtBot::Shoulda::Color.yellow("E")
- else something
- end
- @io.write(something)
- @io.flush
- end
- end
- end
- end
- end
-end
diff --git a/test/lib/shoulda/controller_tests/controller_tests.rb b/test/lib/shoulda/controller_tests/controller_tests.rb
deleted file mode 100755
index f0059c0..0000000
--- a/test/lib/shoulda/controller_tests/controller_tests.rb
+++ /dev/null
@@ -1,467 +0,0 @@
-module ThoughtBot # :nodoc:
- module Shoulda # :nodoc:
- module Controller
- def self.included(other) # :nodoc:
- other.class_eval do
- extend ThoughtBot::Shoulda::Controller::ClassMethods
- include ThoughtBot::Shoulda::Controller::InstanceMethods
- ThoughtBot::Shoulda::Controller::ClassMethods::VALID_FORMATS.each do |format|
- include "ThoughtBot::Shoulda::Controller::#{format.to_s.upcase}".constantize
- end
- end
- end
-
- # = Macro test helpers for your controllers
- #
- # By using the macro helpers you can quickly and easily create concise and easy to read test suites.
- #
- # This code segment:
- # context "on GET to :show for first record" do
- # setup do
- # get :show, :id => 1
- # end
- #
- # should_assign_to :user
- # should_respond_with :success
- # should_render_template :show
- # should_not_set_the_flash
- #
- # should "do something else really cool" do
- # assert_equal 1, assigns(:user).id
- # end
- # end
- #
- # Would produce 5 tests for the +show+ action
- #
- # Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your
- # controller responds restfully to a variety of requested formats.
- module ClassMethods
- # Formats tested by #should_be_restful. Defaults to [:html, :xml]
- VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*.rb')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
- VALID_FORMATS.each {|f| require "shoulda/controller_tests/formats/#{f}.rb"}
-
- # Actions tested by #should_be_restful
- VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc:
-
- # A ResourceOptions object is passed into should_be_restful in order to configure the tests for your controller.
- #
- # Example:
- # class UsersControllerTest < Test::Unit::TestCase
- # load_all_fixtures
- #
- # def setup
- # ...normal setup code...
- # @user = User.find(:first)
- # end
- #
- # should_be_restful do |resource|
- # resource.identifier = :id
- # resource.klass = User
- # resource.object = :user
- # resource.parent = []
- # resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy]
- # resource.formats = [:html, :xml]
- #
- # resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13}
- # resource.update.params = { :name => "sue" }
- #
- # resource.create.redirect = "user_url(@user)"
- # resource.update.redirect = "user_url(@user)"
- # resource.destroy.redirect = "users_url"
- #
- # resource.create.flash = /created/i
- # resource.update.flash = /updated/i
- # resource.destroy.flash = /removed/i
- # end
- # end
- #
- # Whenever possible, the resource attributes will be set to sensible defaults.
- #
- class ResourceOptions
- # Configuration options for the create, update, destroy actions under should_be_restful
- class ActionOptions
- # String evaled to get the target of the redirection.
- # All of the instance variables set by the controller will be available to the
- # evaled code.
- #
- # Example:
- # resource.create.redirect = "user_url(@user.company, @user)"
- #
- # Defaults to a generated url based on the name of the controller, the action, and the resource.parents list.
- attr_accessor :redirect
-
- # String or Regexp describing a value expected in the flash. Will match against any flash key.
- #
- # Defaults:
- # destroy:: /removed/
- # create:: /created/
- # update:: /updated/
- attr_accessor :flash
-
- # Hash describing the params that should be sent in with this action.
- attr_accessor :params
- end
-
- # Configuration options for the denied actions under should_be_restful
- #
- # Example:
- # context "The public" do
- # setup do
- # @request.session[:logged_in] = false
- # end
- #
- # should_be_restful do |resource|
- # resource.parent = :user
- #
- # resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy]
- # resource.denied.flash = /get outta here/i
- # resource.denied.redirect = 'new_session_url'
- # end
- # end
- #
- class DeniedOptions
- # String evaled to get the target of the redirection.
- # All of the instance variables set by the controller will be available to the
- # evaled code.
- #
- # Example:
- # resource.create.redirect = "user_url(@user.company, @user)"
- attr_accessor :redirect
-
- # String or Regexp describing a value expected in the flash. Will match against any flash key.
- #
- # Example:
- # resource.create.flash = /created/
- attr_accessor :flash
-
- # Actions that should be denied (only used by resource.denied). Note that these actions will
- # only be tested if they are also listed in +resource.actions+
- # The special value of :all will deny all of the REST actions.
- attr_accessor :actions
- end
-
- # Name of key in params that references the primary key.
- # Will almost always be :id (default), unless you are using a plugin or have patched rails.
- attr_accessor :identifier
-
- # Name of the ActiveRecord class this resource is responsible for. Automatically determined from
- # test class if not explicitly set. UserTest => "User"
- attr_accessor :klass
-
- # Name of the instantiated ActiveRecord object that should be used by some of the tests.
- # Defaults to the underscored name of the AR class. CompanyManager => :company_manager
- attr_accessor :object
-
- # Name of the parent AR objects. Can be set as parent= or parents=, and can take either
- # the name of the parent resource (if there's only one), or an array of names (if there's
- # more than one).
- #
- # Example:
- # # in the routes...
- # map.resources :companies do
- # map.resources :people do
- # map.resources :limbs
- # end
- # end
- #
- # # in the tests...
- # class PeopleControllerTest < Test::Unit::TestCase
- # should_be_restful do |resource|
- # resource.parent = :companies
- # end
- # end
- #
- # class LimbsControllerTest < Test::Unit::TestCase
- # should_be_restful do |resource|
- # resource.parents = [:companies, :people]
- # end
- # end
- attr_accessor :parent
- alias parents parent
- alias parents= parent=
-
- # Actions that should be tested. Must be a subset of VALID_ACTIONS (default).
- # Tests for each actionw will only be generated if the action is listed here.
- # The special value of :all will test all of the REST actions.
- #
- # Example (for a read-only controller):
- # resource.actions = [:show, :index]
- attr_accessor :actions
-
- # Formats that should be tested. Must be a subset of VALID_FORMATS (default).
- # Each action will be tested against the formats listed here. The special value
- # of :all will test all of the supported formats.
- #
- # Example:
- # resource.actions = [:html, :xml]
- attr_accessor :formats
-
- # ActionOptions object specifying options for the create action.
- attr_accessor :create
-
- # ActionOptions object specifying options for the update action.
- attr_accessor :update
-
- # ActionOptions object specifying options for the desrtoy action.
- attr_accessor :destroy
-
- # DeniedOptions object specifying which actions should return deny a request, and what should happen in that case.
- attr_accessor :denied
-
- def initialize # :nodoc:
- @create = ActionOptions.new
- @update = ActionOptions.new
- @destroy = ActionOptions.new
- @denied = DeniedOptions.new
-
- @create.flash ||= /created/i
- @update.flash ||= /updated/i
- @destroy.flash ||= /removed/i
- @denied.flash ||= /denied/i
-
- @create.params ||= {}
- @update.params ||= {}
-
- @actions = VALID_ACTIONS
- @formats = VALID_FORMATS
- @denied.actions = []
- end
-
- def normalize!(target) # :nodoc:
- @denied.actions = VALID_ACTIONS if @denied.actions == :all
- @actions = VALID_ACTIONS if @actions == :all
- @formats = VALID_FORMATS if @formats == :all
-
- @denied.actions = @denied.actions.map(&:to_sym)
- @actions = @actions.map(&:to_sym)
- @formats = @formats.map(&:to_sym)
-
- ensure_valid_members(@actions, VALID_ACTIONS, 'actions')
- ensure_valid_members(@denied.actions, VALID_ACTIONS, 'denied.actions')
- ensure_valid_members(@formats, VALID_FORMATS, 'formats')
-
- @identifier ||= :id
- @klass ||= target.name.gsub(/ControllerTest$/, '').singularize.constantize
- @object ||= @klass.name.tableize.singularize
- @parent ||= []
- @parent = [@parent] unless @parent.is_a? Array
-
- collection_helper = [@parent, @object.to_s.pluralize, 'url'].flatten.join('_')
- collection_args = @parent.map {|n| "@#{object}.#{n}"}.join(', ')
- @destroy.redirect ||= "#{collection_helper}(#{collection_args})"
-
- member_helper = [@parent, @object, 'url'].flatten.join('_')
- member_args = [@parent.map {|n| "@#{object}.#{n}"}, "@#{object}"].flatten.join(', ')
- @create.redirect ||= "#{member_helper}(#{member_args})"
- @update.redirect ||= "#{member_helper}(#{member_args})"
- @denied.redirect ||= "new_session_url"
- end
-
- private
-
- def ensure_valid_members(ary, valid_members, name) # :nodoc:
- invalid = ary - valid_members
- raise ArgumentError, "Unsupported #{name}: #{invalid.inspect}" unless invalid.empty?
- end
- end
-
- # :section: should_be_restful
- # Generates a full suite of tests for a restful controller.
- #
- # The following definition will generate tests for the +index+, +show+, +new+,
- # +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats:
- #
- # should_be_restful do |resource|
- # resource.parent = :user
- #
- # resource.create.params = { :title => "first post", :body => 'blah blah blah'}
- # resource.update.params = { :title => "changed" }
- # end
- #
- # This generates about 40 tests, all of the format:
- # "on GET to :show should assign @user."
- # "on GET to :show should not set the flash."
- # "on GET to :show should render 'show' template."
- # "on GET to :show should respond with success."
- # "on GET to :show as xml should assign @user."
- # "on GET to :show as xml should have ContentType set to 'application/xml'."
- # "on GET to :show as xml should respond with success."
- # "on GET to :show as xml should return