Tons of documentation

git-svn-id: https://svn.thoughtbot.com/plugins/shoulda/trunk@146 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
This commit is contained in:
tsaleh 2007-07-24 20:16:01 +00:00
parent f00bddd001
commit 0ea1fc75c0
7 changed files with 443 additions and 145 deletions

130
README
View File

@ -1,17 +1,123 @@
= ThoughtBot Test Helpers
= Shoulda
A collection of Test::Unit helper methods.
Shoulda makes it easy to write elegant, understandable, and maintainable tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework. It's fully compatible with your existing tests, and requires no retooling to use.
Adds helpers for
Helpers:: #context and #should give you rSpec like test blocks.
In addition, you get nested contexts and a much more readable syntax.
Macros:: Generate hundreds of lines of Controller and ActiveRecord tests with these powerful macros.
They get you started quickly, and can help you ensure that your application is conforming to best practices.
Assertions:: Many common rails testing idioms have been distilled into a set of useful assertions.
* context and should statements
* Common ActiveRecord model tests
* A few general purpose assertions
= Usage
=== Context Helpers (ThoughtBot::Shoulda::Context)
Stop killing your fingers with all of those underscores... Name your tests with plain sentences!
class UserTest << Test::Unit
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
Produces the following test methods:
"test: A User instance should return its full name."
"test: A User instance with a profile should return true when sent #has_profile?."
So readable!
=== ActiveRecord Tests (ThoughtBot::Shoulda::ActiveRecord)
Quick macro tests for your ActiveRecord associations and validations:
class PostTest < Test::Unit::TestCase
load_all_fixtures
should_belong_to :user
should_have_many :tags, :through => :taggings
should_require_unique_attributes :title
should_require_attributes :body, :message => /wtf/
should_require_attributes :title
should_only_allow_numeric_values_for :user_id
end
class UserTest < Test::Unit::TestCase
load_all_fixtures
should_have_many :posts
should_not_allow_values_for :email, "blah", "b lah"
should_allow_values_for :email, "a@b.com", "asdf@asdf.com"
should_ensure_length_in_range :email, 1..100
should_ensure_value_in_range :age, 1..100
should_protect_attributes :password
end
Makes TDD so much easier.
=== Controller Tests (ThoughtBot::Shoulda::Controller::ClassMethods)
Macros to test the most common controller patterns...
context "on GET to :show for first record" do
setup do
get :show, :id => 1
end
== Todo
should_assign_to :user
should_respond_with :success
should_render_template :show
should_not_set_the_flash
* Many more tests (of the tests). Specifically, the ActiveRecord macros need to be tested.
* Controller test helpers
* General code cleanups
* More options for AR helpers
should "do something else really cool" do
assert_equal 1, assigns(:user).id
end
end
Test entire controllers in a few lines...
class PostsControllerTest < Test::Unit::TestCase
should_be_restful do |resource|
resource.parent = :user
resource.create.params = { :title => "first post", :body => 'blah blah blah'}
resource.update.params = { :title => "changed" }
end
end
should_be_restful generates 40 tests on the fly, for both html and xml requests.
=== Helpful Assertions (ThoughtBot::Shoulda::General)
More to come here, but have fun with what's there.
load_all_fixtures
assert_same_elements([:a, :b, :c], [:c, :a, :b])
assert_contains(['a', '1'], /\d/)
assert_contains(['a', '1'], 'a')
= Credits
Shoulda is maintained by {Tammer Saleh}[mailto:tsaleh@thoughtbot.com], and is funded by Thoughtbot[http://www.thoughtbot.com], inc.
= License
Shoulda is Copyright © 2006-2007 Tammer Saleh, Thoughtbot. It is free software, and may be redistributed under the terms specified in the README file of the Ruby distribution.

View File

@ -22,9 +22,9 @@ end
require 'shoulda/color' if shoulda_options[:color]
module Test # :nodoc:
module Unit # :nodoc:
class TestCase # :nodoc:
module Test # :nodoc: all
module Unit
class TestCase
include ThoughtBot::Shoulda::Controller
include ThoughtBot::Shoulda::General
@ -38,10 +38,10 @@ module Test # :nodoc:
end
end
module ActionController #:nodoc:
module Integration #:nodoc:
class Session #:nodoc:
include ThoughtBot::Shoulda::General::InstanceMethods
module ActionController #:nodoc: all
module Integration
class Session
include ThoughtBot::Shoulda::General
end
end
end

View File

@ -3,7 +3,7 @@ require 'test/unit/ui/console/testrunner'
# Completely stolen from redgreen gem
#
# Adds colored output to your tests. Specify <tt>color: true</tt> in
# your <tt>test/shoulda.conf</tt> file to enable.
# your <tt>~/.shoulda.conf</tt> 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.

View File

@ -2,9 +2,9 @@ module ThoughtBot # :nodoc:
module Shoulda # :nodoc:
# = context and should blocks
#
# A context block can exist next to normal <tt>def test_blah</tt> statements,
# meaning you do not have to fully commit to the context/should syntax in a test file. We have been
# using this syntax at ThoughtBot, though, and find it very readable.
# A context block groups should statements under a common setup/teardown method.
# 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.
#
@ -20,7 +20,7 @@ module ThoughtBot # :nodoc:
# end
# end
#
# This code will produce the method <tt>"test a User instance should return its full name"</tt> (yes, with spaces in the name).
# This code will produce the method <tt>"test a User instance should return its full name"</tt>.
#
# Contexts may be nested. Nested contexts run their setup blocks from out to in before each test.
# They then run their teardown blocks from in to out after each test.
@ -48,8 +48,11 @@ module ThoughtBot # :nodoc:
# end
#
# This code will produce the following methods
# * <tt>"test a User instance should return its full name"</tt>
# * <tt>"test a User instance with a profile should return true when sent :has_profile?"</tt> (which will have both setup blocks run before it.)
# * <tt>"test: a User instance should return its full name."</tt>
# * <tt>"test: a User instance with a profile should return true when sent :has_profile?."</tt>
#
# <b>A context block can exist next to normal <tt>def test_the_old_way; end</tt> tests</b>,
# meaning you do not have to fully commit to the context/should syntax in a test file.
#
module Context
@ -59,32 +62,20 @@ module ThoughtBot # :nodoc:
@@teardown_blocks = []
end
# Creates a context block with the given name.
def context(name, &context_block)
saved_setups = @@setup_blocks.dup
saved_teardowns = @@teardown_blocks.dup
saved_contexts = @@context_names.dup
@@context_names << name
context_block.bind(self).call
@@context_names = saved_contexts
@@setup_blocks = saved_setups
@@teardown_blocks = saved_teardowns
end
# Run before every should block in the current context
def setup(&setup_block)
@@setup_blocks << setup_block
end
# Run after every should block in the current context
def teardown(&teardown_block)
@@teardown_blocks << teardown_block
end
# Defines a test. Can be called either inside our outside of a context.
# Optionally specify <tt>:unimplimented => true</tt> (see should_eventually)
# Defines a test method. Can be called either inside our outside of a context.
# Optionally specify <tt>:unimplimented => true</tt> (see should_eventually).
#
# Example:
#
# class UserTest << Test::Unit
# should "return first user on find(:first)"
# assert_equal users(:first), User.find(:first)
# end
# end
#
# Would create a test named
# 'test: should return first user on find(:first)'
#
def should(name, opts = {}, &should_block)
test_name = ["test:", @@context_names, "should", "#{name}. "].flatten.join(' ').to_sym
@ -112,8 +103,38 @@ module ThoughtBot # :nodoc:
end
end
# Creates a context block with the given name.
def context(name, &context_block)
saved_setups = @@setup_blocks.dup
saved_teardowns = @@teardown_blocks.dup
saved_contexts = @@context_names.dup
@@context_names << name
context_block.bind(self).call
@@context_names = saved_contexts
@@setup_blocks = saved_setups
@@teardown_blocks = saved_teardowns
end
# Run before every should block in the current context.
# If a setup block appears in a nested context, it will be run after the setup blocks
# in the parent contexts.
def setup(&setup_block)
@@setup_blocks << setup_block
end
# Run after every should block in the current context.
# If a teardown block appears in a nested context, it will be run before the teardown
# blocks in the parent contexts.
def teardown(&teardown_block)
@@teardown_blocks << teardown_block
end
# Defines a specification that is not yet implemented.
# Will be displayed as an 'X' when running tests, and failures will not be shown.
# This is equivalent to:
# should(name, {:unimplemented => true}, &block)
def should_eventually(name, &block)
should("eventually #{name}", {:unimplemented => true}, &block)
end

View File

@ -1,6 +1,5 @@
module ThoughtBot # :nodoc:
module Shoulda # :nodoc:
# = Macro test helpers for your controllers
module Controller
def self.included(other) # :nodoc:
other.class_eval do
@ -12,6 +11,30 @@ module ThoughtBot # :nodoc:
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', '*')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
@ -20,26 +43,108 @@ module ThoughtBot # :nodoc:
# 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 eval'd to get the target of the redirection
# 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
# 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
# Hash describing the params that should be sent in with this action.
attr_accessor :params
# Actions that should be denied (only used by resource.denied)
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). <i>Note that these actions will
# only be tested if they are also listed in +resource.actions+</i>
attr_accessor :actions
end
# Name of key in params that references the primary key. Will almost always be :id (default)
# 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.
# 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.
@ -47,33 +152,62 @@ module ThoughtBot # :nodoc:
attr_accessor :object
# Name of the parent AR objects.
#
# 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
# 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.
#
# 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
# Formats that should be tested. Must be a subset of VALID_FORMATS (default).
# Each action will be tested against the formats listed here.
#
# Example:
# resource.actions = [:html, :xml]
attr_accessor :formats
# ActionOptions object
# ActionOptions object specifying options for the create action.
attr_accessor :create
# ActionOptions object
# ActionOptions object specifying options for the update action.
attr_accessor :update
# ActionOptions object
# ActionOptions object specifying options for the desrtoy action.
attr_accessor :destroy
# ActionOptions object
# 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 = ActionOptions.new
@denied = DeniedOptions.new
@actions = VALID_ACTIONS
@formats = VALID_FORMATS
@denied.actions = []
@ -119,7 +253,31 @@ module ThoughtBot # :nodoc:
end
end
# Bunch of documentation and examples for this one.
# :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 <user/> 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)
@ -138,8 +296,14 @@ module ThoughtBot # :nodoc:
end
end
# :section: Test macros
# Macro that creates a test asserting that the flash contains the given value.
# val can be a String or a Regex
#
# Example:
#
# should_set_the_flash_to /created/i
def should_set_the_flash_to(val)
should "have #{val.inspect} in the flash" do
assert_contains flash.values, val, ", Flash: #{flash.inspect}"
@ -154,6 +318,10 @@ module ThoughtBot # :nodoc:
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 show action isn't assigning to @#{name}"
@ -161,6 +329,10 @@ module ThoughtBot # :nodoc:
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"
@ -187,8 +359,12 @@ module ThoughtBot # :nodoc:
end
end
# Macro that creates a test asserting that the controller returned a redirect to the given path.
# Example:
#
# should_redirect_to "/"
def should_redirect_to(url)
should "redirect to #{url}" do
should "redirect to \"#{url}\"" do
instantiate_variables_from_assigns do
assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
end
@ -196,9 +372,9 @@ module ThoughtBot # :nodoc:
end
end
module InstanceMethods
private
module InstanceMethods # :nodoc:
private # :enddoc:
SPECIAL_INSTANCE_VARIABLES = %w{
_cookies
@ -248,11 +424,8 @@ module ThoughtBot # :nodoc:
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.id }.merge(make_parent_params(resource, parent, parent_names))

View File

@ -1,8 +1,8 @@
module ThoughtBot # :nodoc:
module Shoulda # :nodoc:
module Controller # :nodoc:
module XML # :nodoc:
def self.included(other)
module XML
def self.included(other) #:nodoc:
other.class_eval do
extend ThoughtBot::Shoulda::Controller::XML::ClassMethods
end
@ -27,7 +27,7 @@ module ThoughtBot # :nodoc:
protected
def make_show_xml_tests(res)
def make_show_xml_tests(res) # :nodoc:
context "on GET to :show as xml" do
setup do
request_xml
@ -47,15 +47,15 @@ module ThoughtBot # :nodoc:
end
end
def make_edit_xml_tests(res)
def make_edit_xml_tests(res) # :nodoc:
# XML doesn't need an :edit action
end
def make_new_xml_tests(res)
def make_new_xml_tests(res) # :nodoc:
# XML doesn't need a :new action
end
def make_index_xml_tests(res)
def make_index_xml_tests(res) # :nodoc:
context "on GET to :index as xml" do
setup do
request_xml
@ -74,7 +74,7 @@ module ThoughtBot # :nodoc:
end
end
def make_destroy_xml_tests(res)
def make_destroy_xml_tests(res) # :nodoc:
context "on DELETE to :destroy as xml" do
setup do
request_xml
@ -97,7 +97,7 @@ module ThoughtBot # :nodoc:
end
end
def make_create_xml_tests(res)
def make_create_xml_tests(res) # :nodoc:
context "on POST to :create as xml" do
setup do
request_xml
@ -123,7 +123,7 @@ module ThoughtBot # :nodoc:
end
end
def make_update_xml_tests(res)
def make_update_xml_tests(res) # :nodoc:
context "on PUT to :update as xml" do
setup do
request_xml

View File

@ -1,10 +1,10 @@
module ThoughtBot # :nodoc:
module Shoulda # :nodoc:
module General # :nodoc:
def self.included(other)
module General
def self.included(other) # :nodoc:
other.class_eval do
extend ThoughtBot::Shoulda::General::ClassMethods
include ThoughtBot::Shoulda::General::InstanceMethods
# include ThoughtBot::Shoulda::General::InstanceMethods
end
end
@ -18,69 +18,67 @@ module ThoughtBot # :nodoc:
end
end
module InstanceMethods
# Prints a message to stdout, tagged with the name of the calling method.
def report!(msg = "")
puts("#{caller.first}: #{msg}")
# Prints a message to stdout, tagged with the name of the calling method.
def report!(msg = "")
puts("#{caller.first}: #{msg}")
end
# Ensures that the number of items in the collection changes
#
# assert_difference(User, :count, 1) { User.create }
# assert_difference(User.packages, :size, 3, true) { User.add_three_packages }
#
# Setting reload to true will call <tt>object.reload</tt> after the block (for ActiveRecord associations)
def assert_difference(object, method, difference, reload = false, msg = nil)
initial_value = object.send(method)
yield
object.send(:reload) if reload
assert_equal initial_value + difference, object.send(method), (msg || "#{object}##{method} after block")
end
# Ensures that object.method does not change. See assert_difference for usage.
def assert_no_difference(object, method, reload = false, msg = nil, &block)
assert_difference(object, method, 0, reload, msg, &block)
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
# Ensures that the number of items in the collection changes
#
# assert_difference(User, :count, 1) { User.create }
# assert_difference(User.packages, :size, 3, true) { User.add_three_packages }
#
# Setting reload to true will call <tt>object.reload</tt> after the block (for ActiveRecord associations)
def assert_difference(object, method, difference, reload = false, msg = nil)
initial_value = object.send(method)
yield
object.send(:reload) if reload
assert_equal initial_value + difference, object.send(method), (msg || "#{object}##{method} after block")
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 }
# Ensures that object.method does not change. See assert_difference for usage.
def assert_no_difference(object, method, reload = false, msg = nil, &block)
assert_difference(object, method, 0, reload, msg, &block)
end
assert_equal(a1h, a2h, 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
# 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
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 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
end
end