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 as the root element." - # The +resource+ parameter passed into the block is a ResourceOptions object, and - # is used to configure the tests for the details of your resources. - # - def should_be_restful(&blk) # :yields: resource - resource = ResourceOptions.new - blk.call(resource) - resource.normalize!(self) - - resource.formats.each do |format| - resource.actions.each do |action| - if self.respond_to? :"make_#{action}_#{format}_tests" - self.send(:"make_#{action}_#{format}_tests", resource) - else - should "test #{action} #{format}" do - flunk "Test for #{action} as #{format} not implemented" - end - end - end - end - end - - # :section: Test macros - - # Macro that creates a test asserting that the flash contains the given value. - # val can be a String, a Regex, or nil (indicating that the flash should not be set) - # - # Example: - # - # should_set_the_flash_to "Thank you for placing this order." - # should_set_the_flash_to /created/i - # should_set_the_flash_to nil - def should_set_the_flash_to(val) - if val - should "have #{val.inspect} in the flash" do - assert_contains flash.values, val, ", Flash: #{flash.inspect}" - end - else - should "not set the flash" do - assert_equal({}, flash, "Flash was set to:\n#{flash.inspect}") - end - end - end - - # Macro that creates a test asserting that the flash is empty. Same as - # @should_set_the_flash_to nil@ - def should_not_set_the_flash - should_set_the_flash_to nil - end - - # Macro that creates a test asserting that the controller assigned to @name - # - # Example: - # - # should_assign_to :user - def should_assign_to(name) - should "assign @#{name}" do - assert assigns(name.to_sym), "The action isn't assigning to @#{name}" - end - end - - # Macro that creates a test asserting that the controller did not assign to @name - # - # Example: - # - # should_not_assign_to :user - def should_not_assign_to(name) - should "not assign to @#{name}" do - assert !assigns(name.to_sym), "@#{name} was visible" - end - end - - # Macro that creates a test asserting that the controller responded with a 'response' status code. - # Example: - # - # should_respond_with :success - def should_respond_with(response) - should "respond with #{response}" do - assert_response response - end - end - - # Macro that creates a test asserting that the controller rendered the given template. - # Example: - # - # should_render_template :new - def should_render_template(template) - should "render template #{template.inspect}" do - assert_template template.to_s - end - end - - # Macro that creates a test asserting that the controller returned a redirect to the given path. - # The given string is evaled to produce the resulting redirect path. All of the instance variables - # set by the controller are available to the evaled string. - # Example: - # - # should_redirect_to '"/"' - # should_redirect_to "users_url(@user)" - def should_redirect_to(url) - should "redirect to #{url.inspect}" do - instantiate_variables_from_assigns do - assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__) - end - end - end - - # Macro that creates a test asserting that the rendered view contains a
element. - def should_render_a_form - should "display a form" do - assert_select "form", true, "The template doesn't contain a element" - end - end - end - - module InstanceMethods # :nodoc: - - private # :enddoc: - - SPECIAL_INSTANCE_VARIABLES = %w{ - _cookies - _flash - _headers - _params - _request - _response - _session - action_name - before_filter_chain_aborted - cookies - flash - headers - ignore_missing_templates - logger - params - request - request_origin - response - session - template - template_class - template_root - url - variables_added - }.map(&:to_s) - - def instantiate_variables_from_assigns(*names, &blk) - old = {} - names = (@response.template.assigns.keys - SPECIAL_INSTANCE_VARIABLES) if names.empty? - names.each do |name| - old[name] = instance_variable_get("@#{name}") - instance_variable_set("@#{name}", assigns(name.to_sym)) - end - blk.call - names.each do |name| - instance_variable_set("@#{name}", old[name]) - end - end - - def get_existing_record(res) # :nodoc: - returning(instance_variable_get("@#{res.object}")) do |record| - assert(record, "This test requires you to set @#{res.object} in your setup block") - end - end - - def make_parent_params(resource, record = nil, parent_names = nil) # :nodoc: - parent_names ||= resource.parents.reverse - return {} if parent_names == [] # Base case - parent_name = parent_names.shift - parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first) - - { :"#{parent_name}_id" => parent.to_param }.merge(make_parent_params(resource, parent, parent_names)) - end - - end - end - end -end - diff --git a/test/lib/shoulda/controller_tests/formats/html.rb b/test/lib/shoulda/controller_tests/formats/html.rb deleted file mode 100755 index ba92bba..0000000 --- a/test/lib/shoulda/controller_tests/formats/html.rb +++ /dev/null @@ -1,201 +0,0 @@ -module ThoughtBot # :nodoc: - module Shoulda # :nodoc: - module Controller # :nodoc: - module HTML # :nodoc: all - def self.included(other) - other.class_eval do - extend ThoughtBot::Shoulda::Controller::HTML::ClassMethods - end - end - - module ClassMethods - def controller_name_from_class - self.name.gsub(/Test/, '') - end - - def make_show_html_tests(res) - context "on GET to #{controller_name_from_class}#show" do - setup do - record = get_existing_record(res) - parent_params = make_parent_params(res, record) - get :show, parent_params.merge({ res.identifier => record.to_param }) - end - - if res.denied.actions.include?(:show) - should_not_assign_to res.object - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - else - should_assign_to res.object - should_respond_with :success - should_render_template :show - should_not_set_the_flash - end - end - end - - def make_edit_html_tests(res) - context "on GET to #{controller_name_from_class}#edit" do - setup do - @record = get_existing_record(res) - parent_params = make_parent_params(res, @record) - get :edit, parent_params.merge({ res.identifier => @record.to_param }) - end - - if res.denied.actions.include?(:edit) - should_not_assign_to res.object - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - else - should_assign_to res.object - should_respond_with :success - should_render_template :edit - should_not_set_the_flash - should_render_a_form - should "set @#{res.object} to requested instance" do - assert_equal @record, assigns(res.object) - end - end - end - end - - def make_index_html_tests(res) - context "on GET to #{controller_name_from_class}#index" do - setup do - record = get_existing_record(res) rescue nil - parent_params = make_parent_params(res, record) - get(:index, parent_params) - end - - if res.denied.actions.include?(:index) - should_not_assign_to res.object.to_s.pluralize - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - else - should_respond_with :success - should_assign_to res.object.to_s.pluralize - should_render_template :index - should_not_set_the_flash - end - end - end - - def make_new_html_tests(res) - context "on GET to #{controller_name_from_class}#new" do - setup do - record = get_existing_record(res) rescue nil - parent_params = make_parent_params(res, record) - get(:new, parent_params) - end - - if res.denied.actions.include?(:new) - should_not_assign_to res.object - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - else - should_respond_with :success - should_assign_to res.object - should_not_set_the_flash - should_render_template :new - should_render_a_form - end - end - end - - def make_destroy_html_tests(res) - context "on DELETE to #{controller_name_from_class}#destroy" do - setup do - @record = get_existing_record(res) - parent_params = make_parent_params(res, @record) - delete :destroy, parent_params.merge({ res.identifier => @record.to_param }) - end - - if res.denied.actions.include?(:destroy) - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - - should "not destroy record" do - assert_nothing_raised { assert @record.reload } - end - else - should_set_the_flash_to res.destroy.flash - if res.destroy.redirect.is_a? Symbol - should_respond_with res.destroy.redirect - else - should_redirect_to res.destroy.redirect - end - - should "destroy record" do - assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do - @record.reload - end - end - end - end - end - - def make_create_html_tests(res) - context "on POST to #{controller_name_from_class}#create with #{res.create.params.inspect}" do - setup do - record = get_existing_record(res) rescue nil - parent_params = make_parent_params(res, record) - @count = res.klass.count - post :create, parent_params.merge(res.object => res.create.params) - end - - if res.denied.actions.include?(:create) - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - should_not_assign_to res.object - - should "not create new record" do - assert_equal @count, res.klass.count - end - else - should_assign_to res.object - should_set_the_flash_to res.create.flash - if res.create.redirect.is_a? Symbol - should_respond_with res.create.redirect - else - should_redirect_to res.create.redirect - end - - should "not have errors on @#{res.object}" do - assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:" - end - end - end - end - - def make_update_html_tests(res) - context "on PUT to #{controller_name_from_class}#update with #{res.create.params.inspect}" do - setup do - @record = get_existing_record(res) - parent_params = make_parent_params(res, @record) - put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params) - end - - if res.denied.actions.include?(:update) - should_not_assign_to res.object - should_redirect_to res.denied.redirect - should_set_the_flash_to res.denied.flash - else - should_assign_to res.object - should_set_the_flash_to(res.update.flash) - if res.update.redirect.is_a? Symbol - should_respond_with res.update.redirect - else - should_redirect_to res.update.redirect - end - - should "not have errors on @#{res.object}" do - assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:" - end - end - end - end - end - end - end - end -end diff --git a/test/lib/shoulda/controller_tests/formats/xml.rb b/test/lib/shoulda/controller_tests/formats/xml.rb deleted file mode 100755 index f3c16f1..0000000 --- a/test/lib/shoulda/controller_tests/formats/xml.rb +++ /dev/null @@ -1,170 +0,0 @@ -module ThoughtBot # :nodoc: - module Shoulda # :nodoc: - module Controller # :nodoc: - module XML - def self.included(other) #:nodoc: - other.class_eval do - extend ThoughtBot::Shoulda::Controller::XML::ClassMethods - end - end - - module ClassMethods - # Macro that creates a test asserting that the controller responded with an XML content-type - # and that the XML contains ++ as the root element. - def should_respond_with_xml_for(name = nil) - should "have ContentType set to 'application/xml'" do - assert_xml_response - end - - if name - should "return <#{name}/> as the root element" do - body = @response.body.first(100).map {|l| " #{l}"} - assert_select name.to_s.dasherize, 1, "Body:\n#{body}...\nDoes not have <#{name}/> as the root element." - end - end - end - alias should_respond_with_xml should_respond_with_xml_for - - protected - - def make_show_xml_tests(res) # :nodoc: - context "on GET to #{controller_name_from_class}#show as xml" do - setup do - request_xml - record = get_existing_record(res) - parent_params = make_parent_params(res, record) - get :show, parent_params.merge({ res.identifier => record.to_param }) - end - - if res.denied.actions.include?(:show) - should_not_assign_to res.object - should_respond_with 401 - else - should_assign_to res.object - should_respond_with :success - should_respond_with_xml_for res.object - end - end - end - - def make_edit_xml_tests(res) # :nodoc: - # XML doesn't need an :edit action - end - - def make_new_xml_tests(res) # :nodoc: - # XML doesn't need a :new action - end - - def make_index_xml_tests(res) # :nodoc: - context "on GET to #{controller_name_from_class}#index as xml" do - setup do - request_xml - parent_params = make_parent_params(res) - get(:index, parent_params) - end - - if res.denied.actions.include?(:index) - should_not_assign_to res.object.to_s.pluralize - should_respond_with 401 - else - should_respond_with :success - should_respond_with_xml_for res.object.to_s.pluralize - should_assign_to res.object.to_s.pluralize - end - end - end - - def make_destroy_xml_tests(res) # :nodoc: - context "on DELETE to #{controller_name_from_class}#destroy as xml" do - setup do - request_xml - @record = get_existing_record(res) - parent_params = make_parent_params(res, @record) - delete :destroy, parent_params.merge({ res.identifier => @record.to_param }) - end - - if res.denied.actions.include?(:destroy) - should_respond_with 401 - - should "not destroy record" do - assert @record.reload - end - else - should "destroy record" do - assert_raises(::ActiveRecord::RecordNotFound, "@#{res.object} was not destroyed.") do - @record.reload - end - end - end - end - end - - def make_create_xml_tests(res) # :nodoc: - context "on POST to #{controller_name_from_class}#create as xml" do - setup do - request_xml - parent_params = make_parent_params(res) - @count = res.klass.count - post :create, parent_params.merge(res.object => res.create.params) - end - - if res.denied.actions.include?(:create) - should_respond_with 401 - should_not_assign_to res.object - - should "not create new record" do - assert_equal @count, res.klass.count - end - else - should_assign_to res.object - - should "not have errors on @#{res.object}" do - assert_equal [], pretty_error_messages(assigns(res.object)), "@#{res.object} has errors:" - end - end - end - end - - def make_update_xml_tests(res) # :nodoc: - context "on PUT to #{controller_name_from_class}#update as xml" do - setup do - request_xml - @record = get_existing_record(res) - parent_params = make_parent_params(res, @record) - put :update, parent_params.merge(res.identifier => @record.to_param, res.object => res.update.params) - end - - if res.denied.actions.include?(:update) - should_not_assign_to res.object - should_respond_with 401 - else - should_assign_to res.object - - should "not have errors on @#{res.object}" do - assert_equal [], assigns(res.object).errors.full_messages, "@#{res.object} has errors:" - end - end - end - end - end - - # Sets the next request's format to 'application/xml' - def request_xml - @request.accept = "application/xml" - end - - # Asserts that the controller's response was 'application/xml' - def assert_xml_response - content_type = (@response.headers["Content-Type"] || @response.headers["type"]).to_s - regex = %r{\bapplication/xml\b} - - msg = "Content Type '#{content_type.inspect}' doesn't match '#{regex.inspect}'\n" - msg += "Body: #{@response.body.first(100).chomp} ..." - - assert_match regex, content_type, msg - end - - end - end - end -end diff --git a/test/lib/shoulda/gem/proc_extensions.rb b/test/lib/shoulda/gem/proc_extensions.rb deleted file mode 100755 index 0d577df..0000000 --- a/test/lib/shoulda/gem/proc_extensions.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Stolen straight from ActiveSupport - -class Proc #:nodoc: - def bind(object) - block, time = self, Time.now - (class << object; self end).class_eval do - method_name = "__bind_#{time.to_i}_#{time.usec}" - define_method(method_name, &block) - method = instance_method(method_name) - remove_method(method_name) - method - end.bind(object) - end -end diff --git a/test/lib/shoulda/gem/shoulda.rb b/test/lib/shoulda/gem/shoulda.rb deleted file mode 100755 index d1fab1d..0000000 --- a/test/lib/shoulda/gem/shoulda.rb +++ /dev/null @@ -1,239 +0,0 @@ -require File.join(File.dirname(__FILE__), 'proc_extensions') - -module Thoughtbot - module Shoulda - class << self - attr_accessor :current_context - end - - VERSION = '1.1.1' - - # = Should statements - # - # Should statements are just syntactic sugar over normal Test::Unit test methods. A should block - # contains all the normal code and assertions you're used to seeing, with the added benefit that - # they can be wrapped inside context blocks (see below). - # - # == Example: - # - # class UserTest << Test::Unit::TestCase - # - # def setup - # @user = User.new("John", "Doe") - # end - # - # should "return its full name" - # assert_equal 'John Doe', @user.full_name - # end - # - # end - # - # ...will produce the following test: - # * "test: User should return its full name. " - # - # Note: The part before should in the test name is gleamed from the name of the Test::Unit class. - - def should(name, &blk) - if Shoulda.current_context - Shoulda.current_context.should(name, &blk) - else - context_name = self.name.gsub(/Test/, "") - context = Thoughtbot::Shoulda::Context.new(context_name, self) do - should(name, &blk) - end - context.build - end - end - - # Just like should, but never runs, and instead prints an 'X' in the Test::Unit output. - def should_eventually(name, &blk) - context_name = self.name.gsub(/Test/, "") - context = Thoughtbot::Shoulda::Context.new(context_name, self) do - should_eventually(name, &blk) - end - context.build - end - - # = Contexts - # - # A context block groups should statements under a common set of setup/teardown methods. - # Context blocks can be arbitrarily nested, and can do wonders for improving the maintainability - # and readability of your test code. - # - # A context block can contain setup, should, should_eventually, and teardown blocks. - # - # class UserTest << Test::Unit::TestCase - # context "A User instance" do - # setup do - # @user = User.find(:first) - # end - # - # should "return its full name" - # assert_equal 'John Doe', @user.full_name - # end - # end - # end - # - # This code will produce the method "test: A User instance should return its full name. ". - # - # Contexts may be nested. Nested contexts run their setup blocks from out to in before each - # should statement. They then run their teardown blocks from in to out after each should statement. - # - # class UserTest << Test::Unit::TestCase - # context "A User instance" do - # setup do - # @user = User.find(:first) - # end - # - # should "return its full name" - # assert_equal 'John Doe', @user.full_name - # end - # - # context "with a profile" do - # setup do - # @user.profile = Profile.find(:first) - # end - # - # should "return true when sent :has_profile?" - # assert @user.has_profile? - # end - # end - # end - # end - # - # This code will produce the following methods - # * "test: A User instance should return its full name. " - # * "test: A User instance with a profile should return true when sent :has_profile?. " - # - # Just like should statements, a context block can exist next to normal def test_the_old_way; end - # tests. This means you do not have to fully commit to the context/should syntax in a test file. - - def context(name, &blk) - if Shoulda.current_context - Shoulda.current_context.context(name, &blk) - else - context = Thoughtbot::Shoulda::Context.new(name, self, &blk) - context.build - end - end - - class Context # :nodoc: - - attr_accessor :name # my name - attr_accessor :parent # may be another context, or the original test::unit class. - attr_accessor :subcontexts # array of contexts nested under myself - attr_accessor :setup_block # block given via a setup method - attr_accessor :teardown_block # block given via a teardown method - attr_accessor :shoulds # array of hashes representing the should statements - attr_accessor :should_eventuallys # array of hashes representing the should eventually statements - - def initialize(name, parent, &blk) - Shoulda.current_context = self - self.name = name - self.parent = parent - self.setup_block = nil - self.teardown_block = nil - self.shoulds = [] - self.should_eventuallys = [] - self.subcontexts = [] - - blk.bind(self).call - Shoulda.current_context = nil - end - - def context(name, &blk) - subcontexts << Context.new(name, self, &blk) - Shoulda.current_context = self - end - - def setup(&blk) - self.setup_block = blk - end - - def teardown(&blk) - self.teardown_block = blk - end - - def should(name, &blk) - self.shoulds << { :name => name, :block => blk } - end - - def should_eventually(name, &blk) - self.should_eventuallys << { :name => name, :block => blk } - end - - def full_name - parent_name = parent.full_name if am_subcontext? - return [parent_name, name].join(" ").strip - end - - def am_subcontext? - parent.is_a?(self.class) # my parent is the same class as myself. - end - - def test_unit_class - am_subcontext? ? parent.test_unit_class : parent - end - - def create_test_from_should_hash(should) - test_name = ["test:", full_name, "should", "#{should[:name]}. "].flatten.join(' ').to_sym - - if test_unit_class.instance_methods.include?(test_name.to_s) - warn " * WARNING: '#{test_name}' is already defined" - end - - context = self - test_unit_class.send(:define_method, test_name) do |*args| - begin - context.run_all_setup_blocks(self) - should[:block].bind(self).call - ensure - context.run_all_teardown_blocks(self) - end - end - end - - def run_all_setup_blocks(binding) - self.parent.run_all_setup_blocks(binding) if am_subcontext? - setup_block.bind(binding).call if setup_block - end - - def run_all_teardown_blocks(binding) - teardown_block.bind(binding).call if teardown_block - self.parent.run_all_teardown_blocks(binding) if am_subcontext? - end - - def print_should_eventuallys - should_eventuallys.each do |should| - test_name = [full_name, "should", "#{should[:name]}. "].flatten.join(' ') - puts " * DEFERRED: " + test_name - end - subcontexts.each { |context| context.print_should_eventuallys } - end - - def build - shoulds.each do |should| - create_test_from_should_hash(should) - end - - subcontexts.each { |context| context.build } - - print_should_eventuallys - end - - def method_missing(method, *args, &blk) - test_unit_class.send(method, *args, &blk) - end - - end - end -end - -module Test # :nodoc: all - module Unit - class TestCase - extend Thoughtbot::Shoulda - end - end -end - diff --git a/test/lib/shoulda/general.rb b/test/lib/shoulda/general.rb deleted file mode 100755 index e9c57d2..0000000 --- a/test/lib/shoulda/general.rb +++ /dev/null @@ -1,129 +0,0 @@ -module ThoughtBot # :nodoc: - module Shoulda # :nodoc: - module General - def self.included(other) # :nodoc: - other.class_eval do - extend ThoughtBot::Shoulda::General::ClassMethods - end - end - - module ClassMethods - # Loads all fixture files (test/fixtures/*.yml) - def load_all_fixtures - all_fixtures = Dir.glob(File.join(Test::Unit::TestCase.fixture_path, "*.yml")).collect do |f| - File.basename(f, '.yml').to_sym - end - fixtures *all_fixtures - end - end - - # Prints a message to stdout, tagged with the name of the calling method. - def report!(msg = "") - puts("#{caller.first}: #{msg}") - end - - # Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered. - # - # assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes - def assert_same_elements(a1, a2, msg = nil) - [:select, :inject, :size].each do |m| - [a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") } - end - - assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h } - assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } - - assert_equal(a1h, a2h, msg) - end - - # Asserts that the given collection contains item x. If x is a regular expression, ensure that - # at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails. - # - # assert_contains(['a', '1'], /\d/) => passes - # assert_contains(['a', '1'], 'a') => passes - # assert_contains(['a', '1'], /not there/) => fails - def assert_contains(collection, x, extra_msg = "") - collection = [collection] unless collection.is_a?(Array) - msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}" - case x - when Regexp: assert(collection.detect { |e| e =~ x }, msg) - else assert(collection.include?(x), msg) - end - end - - # Asserts that the given collection does not contain item x. If x is a regular expression, ensure that - # none of the elements from the collection match x. - def assert_does_not_contain(collection, x, extra_msg = "") - collection = [collection] unless collection.is_a?(Array) - msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg - case x - when Regexp: assert(!collection.detect { |e| e =~ x }, msg) - else assert(!collection.include?(x), msg) - end - end - - # Asserts that the given object can be saved - # - # assert_save User.new(params) - def assert_save(obj) - assert obj.save, "Errors: #{pretty_error_messages obj}" - obj.reload - end - - # Asserts that the given object is valid - # - # assert_valid User.new(params) - def assert_valid(obj) - assert obj.valid?, "Errors: #{pretty_error_messages obj}" - end - - # Asserts that the block uses ActionMailer to send emails - # - # assert_sends_email(2) { Mailer.deliver_messages } - def assert_sends_email(num = 1, &blk) - ActionMailer::Base.deliveries.clear - blk.call - msg = "Sent #{ActionMailer::Base.deliveries.size} emails, when #{num} expected:\n" - ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" } - assert(num == ActionMailer::Base.deliveries.size, msg) - end - - # Asserts that an email was delivered. Can take a blog that can further - # narrow down the types of emails you're expecting. - # - # assert_sent_email - # - # passes if ActionMailer::Base.deliveries has an email - # - # assert_sent_email do |email| - # email.subject =~ /hi there/ && email.to == 'none@none.com' - # end - # - # passes if there is an email with subject containing 'hi there' and - # recipient equal to 'none@none.com' - # - def assert_sent_email - emails = ActionMailer::Base.deliveries - assert !emails.empty?, "No emails were sent" - if block_given? - matching_emails = emails.select {|e| yield e } - assert !matching_emails.empty?, "None of the emails matched." - end - end - - # Asserts that no ActionMailer mails were delivered - # - # assert_did_not_send_email - def assert_did_not_send_email - msg = "Sent #{ActionMailer::Base.deliveries.size} emails.\n" - ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" } - assert ActionMailer::Base.deliveries.empty?, msg - end - - def pretty_error_messages(obj) - obj.errors.map { |a, m| "#{a} #{m} (#{obj.send(a).inspect})" } - end - - end - end -end diff --git a/test/lib/shoulda/private_helpers.rb b/test/lib/shoulda/private_helpers.rb deleted file mode 100755 index 036dce4..0000000 --- a/test/lib/shoulda/private_helpers.rb +++ /dev/null @@ -1,22 +0,0 @@ -module ThoughtBot # :nodoc: - module Shoulda # :nodoc: - module Private # :nodoc: - # Returns the values for the entries in the args hash who's keys are listed in the wanted array. - # Will raise if there are keys in the args hash that aren't listed. - def get_options!(args, *wanted) - ret = [] - opts = (args.last.is_a?(Hash) ? args.pop : {}) - wanted.each {|w| ret << opts.delete(w)} - raise ArgumentError, "Unsuported options given: #{opts.keys.join(', ')}" unless opts.keys.empty? - return *ret - end - - # Returns the model class constant, as determined by the test class name. - # - # class TestUser; model_class; end => User - def model_class - self.name.gsub(/Test$/, '').constantize - end - end - end -end