1
0
Fork 0
mirror of https://github.com/thoughtbot/shoulda-matchers.git synced 2022-11-09 12:01:38 -05:00

Moved everthing to trunk

git-svn-id: https://svn.thoughtbot.com/plugins/tb_test_helpers/trunk@38 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
This commit is contained in:
tsaleh 2007-03-14 18:12:55 +00:00
parent 37686ae0da
commit 7a4202f9b8
8 changed files with 416 additions and 0 deletions

0
README Normal file
View file

40
bin/convert_to_should_syntax Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env ruby
require 'fileutils'
def usage(msg = nil)
puts "Error: #{msg}" if msg
puts if msg
puts "Usage: #{File.basename(__FILE__)} normal_test_file.rb"
puts
puts "Will convert an existing test file with names like "
puts
puts " def test_should_do_stuff"
puts " ..."
puts " end"
puts
puts "to one using the new syntax: "
puts
puts " should \"be super cool\" do"
puts " ..."
puts " end"
puts
puts "A copy of the old file will be left under /tmp/ in case this script just seriously screws up"
puts
exit (msg ? 2 : 0)
end
usage("Wrong number of arguments.") unless ARGV.size == 1
usage("This system doesn't have a /tmp directory. wtf?") unless File.directory?('/tmp')
file = ARGV.shift
tmpfile = "/tmp/#{File.basename(file)}"
usage("File '#{file}' doesn't exist") unless File.exists?(file)
FileUtils.cp(file, tmpfile)
contents = File.read(tmpfile)
contents.gsub!(/def test_should_(.*)\s*$/, 'should "\1" do')
contents.gsub!(/def test_(.*)\s*$/, 'should "RENAME ME: test \1" do')
contents.gsub!(/should ".*" do$/) {|line| line.tr!('_', ' ')}
File.open(file, 'w') { |f| f.write(contents) }
puts "File '#{file}' has been converted to 'should' syntax. Old version has been stored in '#{tmpfile}'"

1
init.rb Normal file
View file

@ -0,0 +1 @@
require 'tb_test_helpers'

View file

@ -0,0 +1,198 @@
class Test::Unit::TestCase
class << self
# Ensures that the model cannot be saved if one of the attributes listed is not present.
# Requires an existing record
def should_require_attributes(*attributes)
klass = self.name.gsub(/Test$/, '').constantize
attributes.each do |attribute|
should "require #{attribute} to be set" do
object = klass.new
assert !object.valid?, "Instance is still valid"
assert object.errors.on(attribute), "No errors found"
assert object.errors.on(attribute).to_a.include?("can't be blank"), "Error message doesn't match"
end
end
end
# Ensures that the model cannot be saved if one of the attributes listed is not unique.
# Requires an existing record
def should_require_unique_attributes(*attributes)
klass = self.name.gsub(/Test$/, '').constantize
attributes.each do |attribute|
attribute = attribute.to_sym
should "require unique value for #{attribute}" do
assert existing = klass.find(:first), "Can't find first #{klass}"
object = klass.new
object.send(:"#{attribute}=", existing.send(attribute))
assert !object.valid?, "Instance is still valid"
assert object.errors.on(attribute), "No errors found"
assert object.errors.on(attribute).to_a.include?('has already been taken'), "Error message doesn't match"
end
end
end
# Ensures that the attribute cannot be set on update
# Requires an existing record
def should_protect_attributes(*attributes)
klass = self.name.gsub(/Test$/, '').constantize
attributes.each do |attribute|
attribute = attribute.to_sym
should "not allow #{attribute} to be changed by update" do
assert object = klass.find(:first), "Can't find first #{klass}"
value = object[attribute]
assert object.update_attributes({ attribute => 1 }),
"Cannot update #{klass} with { :#{attribute} => 1 }, #{object.errors.full_messages.to_sentence}"
assert object.valid?, "#{klass} isn't valid after changing #{attribute}"
assert_equal value, object[attribute], "Was able to change #{klass}##{attribute}"
end
end
end
# Ensures that the attribute cannot be set to the given values
# Requires an existing record
def should_not_allow_values_for(attribute, *bad_values)
klass = self.name.gsub(/Test$/, '').constantize
bad_values.each do |v|
should "not allow #{attribute} to be set to \"#{v}\"" 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_match(/invalid/, object.errors.on(attribute), "Error set on #{attribute} doesn't include \"invalid\" when set to \"#{v}\"")
end
end
end
# Ensures that the attribute can be set to the given values.
# Requires an existing record
def should_allow_values_for(attribute, *good_values)
klass = self.name.gsub(/Test$/, '').constantize
good_values.each do |v|
should "allow #{attribute} to be set to \"#{v}\"" do
assert object = klass.find(:first), "Can't find first #{klass}"
object.send("#{attribute}=", v)
object.save
# assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
assert_no_match(/invalid/, object.errors.on(attribute), "Error set on #{attribute} includes \"invalid\" when set to \"#{v}\"")
end
end
end
# Ensures that the length of the attribute is in the given range
# Requires an existing record
def should_ensure_length_in_range(attribute, range)
klass = self.name.gsub(/Test$/, '').constantize
min_length = range.first
max_length = range.last
min_value = "x" * (min_length - 1)
max_value = "x" * (max_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_match(/short/, object.errors.on(attribute), "Error set on #{attribute} doesn't include \"short\" when set to \"#{min_value}\"")
end
should "not allow #{attribute} to be more than #{max_length} chars long" do
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_match(/long/, object.errors.on(attribute), "Error set on #{attribute} doesn't include \"long\" when set to \"#{max_value}\"")
end
end
# Ensure that the attribute is in the range specified
# Requires an existing record
def should_ensure_value_in_range(attribute, range)
klass = self.name.gsub(/Test$/, '').constantize
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}\""
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}\""
end
end
# Ensure that the attribute is numeric
# Requires an existing record
def should_only_allow_numeric_values_for(*attributes)
klass = self.name.gsub(/Test$/, '').constantize
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 object.errors.on(attribute), "No errors found"
assert object.errors.on(attribute).to_a.include?('is not a number'), "Error message doesn't match"
end
end
end
# Ensures that the has_many relationship exists.
# The last parameter may be a hash of options. Currently, the only supported option
# is :through
def should_have_many(*associations)
opts = associations.last.is_a?(Hash) ? associations.pop : {}
klass = self.name.gsub(/Test$/, '').constantize
associations.each do |association|
should "have many #{association}#{" through #{opts[:through]}" if opts[:through]}" do
reflection = klass.reflect_on_association(association)
assert reflection
assert_equal :has_many, reflection.macro
assert_equal(opts[:through], reflection.options[:through]) if opts[:through]
end
end
end
# Ensures that the has_and_belongs_to_many relationship exists.
def should_have_and_belong_to_many(*associations)
klass = self.name.gsub(/Test$/, '').constantize
associations.each do |association|
should "should have and belong to many #{association}" do
assert klass.reflect_on_association(association)
assert_equal :has_and_belongs_to_many, klass.reflect_on_association(association).macro
end
end
end
# Ensure that the has_one relationship exists.
def should_have_one(*associations)
klass = self.name.gsub(/Test$/, '').constantize
associations.each do |association|
should "have one #{association}" do
assert klass.reflect_on_association(association)
assert_equal :has_one, klass.reflect_on_association(association).macro
end
end
end
# Ensure that the belongs_to relationship exists.
def should_belong_to(*associations)
klass = self.name.gsub(/Test$/, '').constantize
associations.each do |association|
should "belong_to #{association}" do
assert klass.reflect_on_association(association)
assert_equal :belongs_to, klass.reflect_on_association(association).macro
end
end
end
end
end

60
lib/should.rb Normal file
View file

@ -0,0 +1,60 @@
module TBTestHelpers
module Should
def Should.included(other)
@@_context_names = []
@@_setup_blocks = []
@@_teardown_blocks = []
end
def context(name, &context_block)
@@_context_names << name
context_block.bind(self).call
@@_context_names.pop
@@_setup_blocks.pop
@@_teardown_blocks.pop
end
def setup(&setup_block)
@@_setup_blocks << setup_block
end
def teardown(&teardown_block)
@@_teardown_blocks << teardown_block
end
# Defines a specification. Can be called either inside our outside of a context.
#
#
def should(name, opts = {}, &should_block)
unless @@_context_names.empty?
test_name = "test #{@@_context_names.join(" ")} should #{name}"
else
test_name = "test should #{name}"
end
test_name_sym = test_name.to_sym
raise ArgumentError, "'#{test_name}' is already defined" and return if self.instance_methods.include? test_name
setup_block = @@_setup_blocks.last
teardown_block = @@_teardown_blocks.last
if opts[:unimplemented]
define_method test_name_sym do |*args|
# XXX find a better way of doing this.
assert true
STDOUT.putc "X" # Tests for this model are missing.
end
else
define_method test_name_sym do |*args|
setup_block.bind(self).call if setup_block
should_block.bind(self).call(*args)
teardown_block.bind(self).call if teardown_block
end
end
end
def should_eventually(name, &block)
should("eventually #{name}", {:unimplemented => true}, &block)
end
end
end

48
lib/tb_test_helpers.rb Normal file
View file

@ -0,0 +1,48 @@
require 'active_record_helpers'
require 'should'
class Test::Unit::TestCase
class << self
include TBTestHelpers::Should
# Loads all fixture files
def load_all_fixtures
all_fixtures = Dir.glob(File.join(RAILS_ROOT, "test", "fixtures", "*.yml")).collect do |f|
File.basename(f, '.yml').to_sym
end
fixtures *all_fixtures
end
end
# Ensures that the number of items in the collection changes
def assert_difference(object, method, difference, reload = false)
initial_value = object.send(method)
yield
reload and object.send(:reload)
assert_equal initial_value + difference, object.send(method), "#{object}##{method} after block"
end
# Ensures that object.method does not change
def assert_no_difference(object, method, reload = false, &block)
assert_difference(object, method, 0, reload, &block)
end
def report!(msg = "")
@controller.logger.info("TESTING: #{caller.first}: #{msg}")
end
# asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
def assert_same_elements(a1, a2)
[:select, :inject, :size].each do |m|
[a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a} is an array?") }
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(a1, a2)
end
end

63
test/context_test.rb Normal file
View file

@ -0,0 +1,63 @@
require File.join(File.dirname(__FILE__), 'test_helper')
class ContextTest < Test::Unit::TestCase
context "context with setup block" do
setup do
@blah = "blah"
end
should "have @blah == 'blah'" do
assert_equal "blah", @blah
end
should "have name set right" do
assert_match(/^test context with setup block/, self.to_s)
end
end
context "another context with setup block" do
setup do
@blah = "foo"
end
should "have @blah == 'foo'" do
assert_equal "foo", @blah
end
should "have name set right" do
assert_match(/^test another context with setup block/, self.to_s)
end
end
context "context with method definition" do
setup do
def hello; "hi"; end
end
should "be able to read that method" do
assert_equal "hi", hello
end
should "have name set right" do
assert_match(/^test context with method definition/, self.to_s)
end
end
context "final context" do
should "not define @blah" do
assert_nil @blah
end
context "with subcontext" do
should "be named correctly" do
assert_match(/^test final context with subcontext should be named correctly/, self.to_s)
end
end
end
should_eventually "pass anyway, since it's unimplemented" do
flunk "what?"
end
end

6
test/test_helper.rb Normal file
View file

@ -0,0 +1,6 @@
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
require 'rubygems'
require 'active_support'
require 'test/unit'
require 'tb_test_helpers'