Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: thoughtbot/shoulda-matchers
...
head fork: thoughtbot/shoulda-matchers
  • 20 commits
  • 27 files changed
  • 1 commit comment
  • 12 contributors
Commits on Sep 13, 2012
@jferris jferris Extract ValidationMessageFinder from AllowValueMatcher 3dbf5d4
@jferris jferris Extract ExceptionMessageFinder from AllowValueMatcher
* Replaces repeated conditional with polymorphism
87327c2
@jferris jferris Fix failure on 1.8.7 1ca1f72
Commits on Sep 14, 2012
@jferris jferris Add documentation for strict validation testing fde078d
Adarsh Pandit Update Copyright year a74cee3
@grosser grosser Protect against unmatchable classes in flash matcher 27841b7
Commits on Sep 21, 2012
@steveklabnik steveklabnik Refactor have_db_index_matcher#correct_unique?
Currently, there is an assumption that `matched_index.unique` will
be `true` and not truthy. This is not always the case. This can
cause tests to fail, even though they should pass. This allows
`matched_index.unique` to be truthy.
d56d4fe
@gauravs gauravs Don't assume that the column is of integer type
Postgres adapter does not convert integers to string upon assignment, so initialize with correct value.
f6edb15
@karledurante karledurante Using ActiveRecord::Base.connection is presumptuous. You must infer t…
…he home of the join table using the parent model. This allows developers to define HABTM relationships in other databases and still use the 'have_and_belong_to_many' matcher.
41c763d
@grk grk Add in_array to ensure_exclusion_of 8a477a9
@jacobsimeon jacobsimeon add custom foreign key test cf6452d
@jacobsimeon jacobsimeon don't conflict with the pre-existing method 1b31a06
@jacobsimeon jacobsimeon allow testing of :foreign_key option for has_one relationships ca8a1e5
@jesseplusplus jesseplusplus Fix ensure_length_of matcher to work for is_equal_to cases when the a…
…ttribute has other validations on it.

Now that the upper bound matchers are not being skipped for the is_equal_to case, the expected error message needs to be set for the upper bound.
777f42d
@grantovich grantovich Don't lock Bundler at minor version b658c4b
@grantovich grantovich Whoops, don't use Bundler 1.0 2c214e4
@grantovich grantovich [#120] Test more blank values with allow_blank 12121b8
Commits on Sep 28, 2012
@drapergeek drapergeek Model must only allow values inside of array for EnsureInclusionOf dc5daca
@gabebw gabebw Use `all?`. 7f208e7
Commits on Oct 01, 2012
@drapergeek drapergeek Try next values in array only.
If we can't find a valid next value outside of each item
in the array, throw a custom exception.
f621667
Showing with 583 additions and 127 deletions.
  1. +1 −1  Gemfile.lock
  2. +1 −1  README.md
  3. +2 −2 gemfiles/3.0.gemfile.lock
  4. +5 −5 gemfiles/3.1.gemfile.lock
  5. +5 −5 gemfiles/3.2.gemfile.lock
  6. +3 −0  lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb
  7. +14 −0 lib/shoulda/matchers/active_model.rb
  8. +17 −89 lib/shoulda/matchers/active_model/allow_value_matcher.rb
  9. +28 −6 lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb
  10. +22 −4 lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb
  11. +1 −0  lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb
  12. +7 −0 lib/shoulda/matchers/active_model/errors.rb
  13. +58 −0 lib/shoulda/matchers/active_model/exception_message_finder.rb
  14. +9 −1 lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb
  15. +69 −0 lib/shoulda/matchers/active_model/validation_message_finder.rb
  16. +14 −5 lib/shoulda/matchers/active_record/association_matcher.rb
  17. +8 −5 lib/shoulda/matchers/active_record/have_db_index_matcher.rb
  18. +1 −1  shoulda-matchers.gemspec
  19. +6 −0 spec/shoulda/action_controller/set_the_flash_matcher_spec.rb
  20. +1 −1  spec/shoulda/active_model/allow_value_matcher_spec.rb
  21. +23 −1 spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb
  22. +31 −0 spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb
  23. +13 −0 spec/shoulda/active_model/ensure_length_of_matcher_spec.rb
  24. +112 −0 spec/shoulda/active_model/exception_message_finder_spec.rb
  25. +107 −0 spec/shoulda/active_model/validation_message_finder_spec.rb
  26. +8 −0 spec/shoulda/active_record/association_matcher_spec.rb
  27. +17 −0 spec/shoulda/active_record/have_db_index_matcher_spec.rb
View
2  Gemfile.lock
@@ -138,7 +138,7 @@ DEPENDENCIES
appraisal (~> 0.4.0)
aruba
bourne (~> 1.1.2)
- bundler (~> 1.1.0)
+ bundler (~> 1.1)
cucumber (~> 1.1.9)
jdbc-sqlite3
jruby-openssl
View
2  README.md
@@ -80,5 +80,5 @@ Thank you to all the [contributors](https://github.com/thoughtbot/shoulda-matche
## License
-Shoulda is Copyright © 2006-2010 thoughtbot, inc.
+Shoulda is Copyright © 2006-2012 thoughtbot, inc.
It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
View
4 gemfiles/3.0.gemfile.lock
@@ -1,5 +1,5 @@
PATH
- remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
+ remote: /Users/alex/projects/shoulda-matchers
specs:
shoulda-matchers (1.3.0)
activesupport (>= 3.0.0)
@@ -125,7 +125,7 @@ DEPENDENCIES
appraisal (~> 0.4.0)
aruba
bourne (~> 1.1.2)
- bundler (~> 1.1.0)
+ bundler (~> 1.1)
cucumber (~> 1.1.9)
jdbc-sqlite3
jruby-openssl
View
10 gemfiles/3.1.gemfile.lock
@@ -1,5 +1,5 @@
PATH
- remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
+ remote: /Users/alex/projects/shoulda-matchers
specs:
shoulda-matchers (1.3.0)
activesupport (>= 3.0.0)
@@ -46,7 +46,7 @@ GEM
rspec (>= 2.7.0)
bourne (1.1.2)
mocha (= 0.10.5)
- builder (3.0.0)
+ builder (3.0.3)
childprocess (0.3.5)
ffi (~> 1.0, >= 1.0.6)
cucumber (1.1.9)
@@ -61,8 +61,8 @@ GEM
gherkin (2.9.3)
json (>= 1.4.6)
hike (1.2.1)
- i18n (0.6.0)
- jquery-rails (2.1.1)
+ i18n (0.6.1)
+ jquery-rails (2.1.2)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
json (1.7.5)
@@ -145,7 +145,7 @@ DEPENDENCIES
appraisal (~> 0.4.0)
aruba
bourne (~> 1.1.2)
- bundler (~> 1.1.0)
+ bundler (~> 1.1)
cucumber (~> 1.1.9)
jdbc-sqlite3
jquery-rails
View
10 gemfiles/3.2.gemfile.lock
@@ -1,5 +1,5 @@
PATH
- remote: /Users/joshuaclayton/dev/gems/shoulda-matchers
+ remote: /Users/alex/projects/shoulda-matchers
specs:
shoulda-matchers (1.3.0)
activesupport (>= 3.0.0)
@@ -45,7 +45,7 @@ GEM
rspec (>= 2.7.0)
bourne (1.1.2)
mocha (= 0.10.5)
- builder (3.0.0)
+ builder (3.0.3)
childprocess (0.3.5)
ffi (~> 1.0, >= 1.0.6)
cucumber (1.1.9)
@@ -60,9 +60,9 @@ GEM
gherkin (2.9.3)
json (>= 1.4.6)
hike (1.2.1)
- i18n (0.6.0)
+ i18n (0.6.1)
journey (1.0.4)
- jquery-rails (2.1.1)
+ jquery-rails (2.1.2)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
json (1.7.5)
@@ -142,7 +142,7 @@ DEPENDENCIES
appraisal (~> 0.4.0)
aruba
bourne (~> 1.1.2)
- bundler (~> 1.1.0)
+ bundler (~> 1.1)
cucumber (~> 1.1.9)
jdbc-sqlite3
jquery-rails
View
3  lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb
@@ -25,6 +25,9 @@ def initialize
attr_reader :failure_message, :negative_failure_message
def to(value)
+ if !value.is_a?(String) && !value.is_a?(Regexp)
+ raise "cannot match against #{value.inspect}"
+ end
@value = value
self
end
View
14 lib/shoulda/matchers/active_model.rb
@@ -1,5 +1,7 @@
require 'shoulda/matchers/active_model/helpers'
require 'shoulda/matchers/active_model/validation_matcher'
+require 'shoulda/matchers/active_model/validation_message_finder'
+require 'shoulda/matchers/active_model/exception_message_finder'
require 'shoulda/matchers/active_model/allow_value_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
@@ -11,6 +13,7 @@
require 'shoulda/matchers/active_model/validate_confirmation_of_matcher'
require 'shoulda/matchers/active_model/validate_numericality_of_matcher'
require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher'
+require 'shoulda/matchers/active_model/errors'
module Shoulda
@@ -27,8 +30,19 @@ module Matchers
# end
# it { should allow_value("(123) 456-7890").for(:phone_number) }
# it { should_not allow_mass_assignment_of(:password) }
+ # it { should allow_value('Activated', 'Pending').for(:status).strict }
+ # it { should_not allow_value('Amazing').for(:status).strict }
# end
#
+ # These tests work with the following model:
+ #
+ # class User < ActiveRecord::Base
+ # validates_presence_of :name
+ # validates_presence_of :phone_number
+ # validates_format_of :phone_number, :with => /\\(\\d{3}\\) \\d{3}\\-\\d{4}/
+ # validates_inclusion_of :status, :in => %w(Activated Pending), :strict => true
+ # attr_accessible :name, :phone_number
+ # end
module ActiveModel
end
end
View
106 lib/shoulda/matchers/active_model/allow_value_matcher.rb
@@ -11,6 +11,9 @@ module ActiveModel # :nodoc:
# * <tt>with_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. If omitted,
# the test looks for any errors in <tt>errors.on(:attribute)</tt>.
+ # * <tt>strict</tt> - expects the model to raise an exception when the
+ # validation fails rather than adding to the errors collection. Used for
+ # testing `validates!` and the `:strict => true` validation options.
#
# Example:
# it { should_not allow_value('bad').for(:isbn) }
@@ -29,7 +32,7 @@ class AllowValueMatcher # :nodoc:
def initialize(*values)
@values_to_match = values
- @strict = false
+ @message_finder_factory = ValidationMessageFinder
@options = {}
end
@@ -44,7 +47,7 @@ def with_message(message)
end
def strict
- @strict = true
+ @message_finder_factory = ExceptionMessageFinder
self
end
@@ -66,39 +69,17 @@ def negative_failure_message
end
def description
- base = "allow #{@attribute} to be set to #{allowed_values}"
-
- if strict?
- "strictly #{base}"
- else
- base
- end
+ message_finder.allow_description(allowed_values)
end
private
def errors_match?
- if strict?
- exception_message_matches?
- else
- validation_messages_match?
- end
+ has_messages? && errors_for_attribute_match?
end
- def exception_message_matches?
- @instance.valid?
- false
- rescue ::ActiveModel::StrictValidationFailed => exception
- @strict_exception = exception
- errors_for_attribute_match?
- end
-
- def validation_messages_match?
- if @instance.valid?
- false
- else
- errors_for_attribute_match?
- end
+ def has_messages?
+ message_finder.has_messages?
end
def errors_for_attribute_match?
@@ -110,28 +91,7 @@ def errors_for_attribute_match?
end
def errors_for_attribute
- if strict?
- [strict_exception_message]
- else
- validation_messages_for_attribute
- end
- end
-
- def strict_exception_message
- @strict_exception.message
- end
-
- def validation_messages_for_attribute
- if @instance.errors.respond_to?(:[])
- errors = @instance.errors[@attribute]
- else
- errors = @instance.errors.on(@attribute)
- end
- Array.wrap(errors)
- end
-
- def strict?
- @strict
+ message_finder.messages
end
def errors_match_regexp?
@@ -152,35 +112,11 @@ def expectation
end
def error_source
- if strict?
- 'exception'
- else
- 'errors'
- end
+ message_finder.source_description
end
def error_description
- if strict?
- exception_description
- else
- validation_error_description
- end
- end
-
- def exception_description
- if @strict_exception
- strict_exception_message
- else
- 'no exception'
- end
- end
-
- def validation_error_description
- if @instance.errors.empty?
- "no errors"
- else
- "errors: #{pretty_error_messages(@instance)}"
- end
+ message_finder.messages_description
end
def allowed_values
@@ -202,19 +138,7 @@ def expected_message
end
def default_expected_message
- if strict?
- default_full_message
- else
- default_attribute_message
- end
- end
-
- def default_full_message
- "#{human_attribute_name} #{default_attribute_message}"
- end
-
- def human_attribute_name
- @instance.class.human_attribute_name(@attribute)
+ message_finder.expected_message_from(default_attribute_message)
end
def default_attribute_message
@@ -228,6 +152,10 @@ def default_attribute_message
def model_name
@instance.class.to_s.underscore
end
+
+ def message_finder
+ @message_finder ||= @message_finder_factory.new(@instance, @attribute)
+ end
end
end
end
View
34 lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb
@@ -5,6 +5,7 @@ module ActiveModel # :nodoc:
# Ensure that the attribute's value is not in the range specified
#
# Options:
+ # * <tt>in_array</tt> - the array of not allowed values for this attribute
# * <tt>in_range</tt> - the range of not allowed values for this attribute
# * <tt>with_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
@@ -18,6 +19,10 @@ def ensure_exclusion_of(attr)
end
class EnsureExclusionOfMatcher < ValidationMatcher # :nodoc:
+ def in_array(array)
+ @array = array
+ self
+ end
def in_range(range)
@range = range
@@ -32,20 +37,30 @@ def with_message(message)
end
def description
- "ensure exclusion of #{@attribute} in #{@range.inspect}"
+ "ensure exclusion of #{@attribute} in #{inspect_message}"
end
def matches?(subject)
super(subject)
- allows_lower_value &&
- disallows_minimum_value &&
- allows_higher_value &&
- disallows_maximum_value
+ if @range
+ allows_lower_value &&
+ disallows_minimum_value &&
+ allows_higher_value &&
+ disallows_maximum_value
+ elsif @array
+ disallows_all_values_in_array?
+ end
end
private
+ def disallows_all_values_in_array?
+ @array.all? do |value|
+ disallows_value_of(value, expected_message)
+ end
+ end
+
def allows_lower_value
@minimum == 0 || allows_value_of(@minimum - 1, expected_message)
end
@@ -65,8 +80,15 @@ def disallows_maximum_value
def expected_message
@expected_message || :exclusion
end
- end
+ def inspect_message
+ if @range
+ @range.inspect
+ else
+ @array.inspect
+ end
+ end
+ end
end
end
end
View
26 lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb
@@ -5,7 +5,7 @@ module ActiveModel # :nodoc:
# Ensure that the attribute's value is in the range specified
#
# Options:
- # * <tt>in_array</tt> - the range of allowed values for this attribute
+ # * <tt>in_array</tt> - the array of allowed values for this attribute
# * <tt>in_range</tt> - the range of allowed values for this attribute
# * <tt>with_low_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
@@ -83,7 +83,7 @@ def matches?(subject)
disallows_higher_value &&
allows_maximum_value
elsif @array
- if allows_all_values_in_array? && allows_blank_value? && allows_nil_value?
+ if allows_all_values_in_array? && allows_blank_value? && allows_nil_value? && disallows_value_outside_of_array?
true
else
@failure_message = "#{@array} doesn't match array in validation"
@@ -96,7 +96,8 @@ def matches?(subject)
def allows_blank_value?
if @options.key?(:allow_blank)
- @options[:allow_blank] == allows_value_of('')
+ blank_values = ['', ' ', "\n", "\r", "\t", "\f"]
+ @options[:allow_blank] == blank_values.all? { |value| allows_value_of(value) }
else
true
end
@@ -135,8 +136,25 @@ def allows_minimum_value
def allows_maximum_value
allows_value_of(@maximum, @high_message)
end
- end
+ def disallows_value_outside_of_array?
+ if value_outside_of_array
+ disallows_value_of(value_outside_of_array)
+ else
+ raise CouldNotDetermineValueOutsideOfArray
+ end
+ end
+
+ def value_outside_of_array
+ found = @array.detect do |item|
+ !@array.include?(item.next)
+ end
+
+ if found
+ found.next
+ end
+ end
+ end
end
end
end
View
1  lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb
@@ -58,6 +58,7 @@ def is_equal_to(length)
@options[:minimum] = length
@options[:maximum] = length
@short_message ||= :wrong_length
+ @long_message ||= :wrong_length
self
end
View
7 lib/shoulda/matchers/active_model/errors.rb
@@ -0,0 +1,7 @@
+module Shoulda # :nodoc:
+ module Matchers
+ module ActiveModel # :nodoc:
+ class CouldNotDetermineValueOutsideOfArray < RuntimeError; end
+ end
+ end
+end
View
58 lib/shoulda/matchers/active_model/exception_message_finder.rb
@@ -0,0 +1,58 @@
+module Shoulda
+ module Matchers
+ module ActiveModel
+
+ # Finds message information from exceptions thrown by #valid?
+ class ExceptionMessageFinder
+ def initialize(instance, attribute)
+ @instance = instance
+ @attribute = attribute
+ end
+
+ def allow_description(allowed_values)
+ "doesn't raise when #{@attribute} is set to #{allowed_values}"
+ end
+
+ def messages_description
+ if has_messages?
+ messages.join
+ else
+ 'no exception'
+ end
+ end
+
+ def has_messages?
+ messages.any?
+ end
+
+ def messages
+ @messages ||= validate_and_rescue
+ end
+
+ def source_description
+ 'exception'
+ end
+
+ def expected_message_from(attribute_message)
+ "#{human_attribute_name} #{attribute_message}"
+ end
+
+ private
+
+ def validate_and_rescue
+ @instance.valid?
+ []
+ rescue ::ActiveModel::StrictValidationFailed => exception
+ [exception.message]
+ end
+
+ def human_attribute_name
+ @instance.class.human_attribute_name(@attribute)
+ end
+ end
+
+ end
+ end
+end
+
+
View
10 lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb
@@ -122,7 +122,7 @@ def validate_after_scope_change?
previous_value = existing.send(scope)
# Assume the scope is a foreign key if the field is nil
- previous_value ||= 0
+ previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
next_value = if previous_value.respond_to?(:next)
previous_value.next
@@ -146,6 +146,14 @@ def validate_after_scope_change?
end
end
+ def correct_type_for_column(column)
+ if column.type == :string
+ '0'
+ else
+ 0
+ end
+ end
+
def class_name
@subject.class.name
end
View
69 lib/shoulda/matchers/active_model/validation_message_finder.rb
@@ -0,0 +1,69 @@
+module Shoulda
+ module Matchers
+ module ActiveModel
+
+ # Finds message information from a model's #errors method.
+ class ValidationMessageFinder
+ include Helpers
+
+ def initialize(instance, attribute)
+ @instance = instance
+ @attribute = attribute
+ end
+
+ def allow_description(allowed_values)
+ "allow #{@attribute} to be set to #{allowed_values}"
+ end
+
+ def expected_message_from(attribute_message)
+ attribute_message
+ end
+
+ def has_messages?
+ errors.present?
+ end
+
+ def source_description
+ 'errors'
+ end
+
+ def messages_description
+ if errors.empty?
+ "no errors"
+ else
+ "errors: #{pretty_error_messages(validated_instance)}"
+ end
+ end
+
+ def messages
+ Array.wrap(messages_for_attribute)
+ end
+
+ private
+
+ def messages_for_attribute
+ if errors.respond_to?(:[])
+ errors[@attribute]
+ else
+ errors.on(@attribute)
+ end
+ end
+
+ def errors
+ validated_instance.errors
+ end
+
+ def validated_instance
+ @validated_instance ||= validate_instance
+ end
+
+ def validate_instance
+ @instance.valid?
+ @instance
+ end
+ end
+
+ end
+ end
+end
+
View
19 lib/shoulda/matchers/active_record/association_matcher.rb
@@ -100,6 +100,11 @@ def class_name(class_name)
self
end
+ def with_foreign_key(foreign_key)
+ @options[:foreign_key] = foreign_key
+ self
+ end
+
def validate(validate = true)
@validate = validate
self
@@ -243,7 +248,7 @@ def conditions_correct?
def join_table_exists?
if @macro != :has_and_belongs_to_many ||
- ::ActiveRecord::Base.connection.tables.include?(join_table)
+ model_class.connection.tables.include?(join_table)
true
else
@missing = "join table #{join_table} doesn't exist"
@@ -261,11 +266,15 @@ def validate_correct?
end
def class_has_foreign_key?(klass)
- if klass.column_names.include?(foreign_key)
- true
+ if @options.key?(:foreign_key)
+ reflection.options[:foreign_key] == @options[:foreign_key]
else
- @missing = "#{klass} does not have a #{foreign_key} foreign key."
- false
+ if klass.column_names.include?(foreign_key)
+ true
+ else
+ @missing = "#{klass} does not have a #{foreign_key} foreign key."
+ false
+ end
end
end
View
13 lib/shoulda/matchers/active_record/have_db_index_matcher.rb
@@ -62,13 +62,16 @@ def index_exists?
def correct_unique?
return true unless @options.key?(:unique)
- if matched_index.unique == @options[:unique]
- true
- else
+ is_unique = matched_index.unique
+
+ is_unique = !is_unique unless @options[:unique]
+
+ unless is_unique
@missing = "#{table_name} has an index named #{matched_index.name} " <<
- "of unique #{matched_index.unique}, not #{@options[:unique]}."
- false
+ "of unique #{matched_index.unique}, not #{@options[:unique]}."
end
+
+ is_unique
end
def matched_index
View
2  shoulda-matchers.gemspec
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_development_dependency('appraisal', '~> 0.4.0')
s.add_development_dependency('aruba')
s.add_development_dependency('bourne', '~> 1.1.2')
- s.add_development_dependency('bundler', '~> 1.1.0')
+ s.add_development_dependency('bundler', '~> 1.1')
s.add_development_dependency('cucumber', '~> 1.1.9')
s.add_development_dependency('rails', '~> 3.0')
s.add_development_dependency('rake', '~> 0.9.2')
View
6 spec/shoulda/action_controller/set_the_flash_matcher_spec.rb
@@ -1,6 +1,12 @@
require 'spec_helper'
describe Shoulda::Matchers::ActionController::SetTheFlashMatcher do
+ it "should fail with unmatchable to" do
+ expect{
+ set_the_flash.to(1).should
+ }.to raise_error("cannot match against 1")
+ end
+
context "a controller that sets a flash message" do
let(:controller) { build_response { flash[:notice] = 'value' } }
View
2  spec/shoulda/active_model/allow_value_matcher_spec.rb
@@ -107,7 +107,7 @@
it "describes itself" do
allow_value("xyz").for(:attr).strict.description.
- should == 'strictly allow attr to be set to "xyz"'
+ should == %{doesn't raise when attr is set to "xyz"}
end
it "provides a useful negative failure message" do
View
24 spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb
@@ -51,7 +51,29 @@ def custom_validation
it "should accept ensuring the correct range and messages" do
@model.should ensure_exclusion_of(:attr).in_range(2..5).with_message(/shoud be out of this range/)
end
-
end
+ context "an attribute which must be excluded in an array" do
+ before do
+ @model = define_model(:example, :attr => :string) do
+ validates_exclusion_of :attr, :in => %w(one two)
+ end.new
+ end
+
+ it "accepts with correct array" do
+ @model.should ensure_exclusion_of(:attr).in_array(%w(one two))
+ end
+
+ it "rejects when only part of array matches" do
+ @model.should_not ensure_exclusion_of(:attr).in_array(%w(one wrong_value))
+ end
+
+ it "rejects when array doesn't match at all" do
+ @model.should_not ensure_exclusion_of(:attr).in_array(%w(cat dog))
+ end
+
+ it "has correct description" do
+ ensure_exclusion_of(:attr).in_array([true, 'dog']).description.should == 'ensure exclusion of attr in [true, "dog"]'
+ end
+ end
end
View
31 spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb
@@ -1,6 +1,24 @@
require 'spec_helper'
describe Shoulda::Matchers::ActiveModel::EnsureInclusionOfMatcher do
+ context "with no validations" do
+ before do
+ @model = define_model(:example, :attr => :string) do
+ end.new
+ end
+
+ it "should reject an array which does not have a validator defined" do
+ @model.should_not ensure_inclusion_of(:attr).in_array(%w(Yes No))
+ end
+ end
+
+ context "where we cannot determine a value outside the array" do
+ it "should raise a custom exception" do
+ @model = define_model(:example, :attr => :string).new
+
+ expect { @model.should ensure_inclusion_of(:attr).in_array([""]) }.to raise_error Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray
+ end
+ end
context "an attribute which must be included in a range" do
before do
@@ -121,6 +139,19 @@ def custom_validation
end
end
+ context "an attribute allowing some blank values but not others" do
+ before do
+ @model = define_model(:example, :attr => :string) do
+ validates_inclusion_of :attr, :in => ['one', 'two', '']
+ end.new
+ end
+
+ it "rejects allow_blank" do
+ @model.should_not ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(true)
+ @model.should ensure_inclusion_of(:attr).in_array(['one', 'two', '']).allow_blank(false)
+ end
+ end
+
if Rails::VERSION::STRING.to_f >= 3.2
context "a strict attribute which must be included in a range" do
before do
View
13 spec/shoulda/active_model/ensure_length_of_matcher_spec.rb
@@ -86,6 +86,19 @@
end
end
+ context "an attribute with a required exact length and another validation" do
+ before do
+ @model = define_model(:example, :attr => :string) do
+ validates_length_of :attr, :is => 4
+ validates_numericality_of :attr
+ end.new
+ end
+
+ it "should accept ensuring the correct length" do
+ @model.should ensure_length_of(:attr).is_equal_to(4)
+ end
+ end
+
context "an attribute with a custom minimum length validation" do
before do
@model = define_model(:example, :attr => :string) do
View
112 spec/shoulda/active_model/exception_message_finder_spec.rb
@@ -0,0 +1,112 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::ExceptionMessageFinder do
+ if Rails::VERSION::STRING.to_f >= 3.2
+ context '#allow_description' do
+ it 'describes its attribute' do
+ finder = build_finder(:attribute => :attr)
+
+ description = finder.allow_description('allowed values')
+
+ description.should == "doesn't raise when attr is set to allowed values"
+ end
+ end
+
+ context '#expected_message_from' do
+ it 'returns the message with the attribute name prefixed' do
+ finder = build_finder(:attribute => :attr)
+
+ message = finder.expected_message_from('some message')
+
+ message.should == 'Attr some message'
+ end
+ end
+
+ context '#has_messages?' do
+ it 'has messages when some validations fail' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ result = finder.has_messages?
+
+ result.should be_true
+ end
+
+ it 'has no messages when all validations pass' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ result = finder.has_messages?
+
+ result.should be_false
+ end
+ end
+
+ context '#messages' do
+ it 'returns errors for the given attribute' do
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ messages = finder.messages
+
+ messages.should == ['Attr is invalid']
+ end
+ end
+
+ context '#messages_description' do
+ it 'describes errors for the given attribute' do
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ description = finder.messages_description
+
+ description.should == 'Attr is invalid'
+ end
+
+ it 'describes errors when there are none' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ description = finder.messages_description
+
+ description.should == 'no exception'
+ end
+ end
+
+ context '#source_description' do
+ it 'describes the source of its messages' do
+ finder = build_finder
+
+ description = finder.source_description
+
+ description.should == 'exception'
+ end
+ end
+ end
+
+ def build_finder(arguments = {})
+ arguments[:attribute] ||= :attr
+ instance = build_instance_validating(
+ arguments[:attribute],
+ arguments[:format] || /abc/,
+ arguments[:value] || 'abc'
+ )
+ Shoulda::Matchers::ActiveModel::ExceptionMessageFinder.new(
+ instance,
+ arguments[:attribute]
+ )
+ end
+
+ def build_instance_validating(attribute, format, value)
+ model_class = define_model(:example, attribute => :string) do
+ attr_accessible attribute
+ validates_format_of attribute, :with => format, :strict => true
+ end
+
+ model_class.new(attribute => value)
+ end
+end
+
View
107 spec/shoulda/active_model/validation_message_finder_spec.rb
@@ -0,0 +1,107 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
+ context '#allow_description' do
+ it 'describes its attribute' do
+ finder = build_finder(:attribute => :attr)
+
+ description = finder.allow_description('allowed values')
+
+ description.should == 'allow attr to be set to allowed values'
+ end
+ end
+
+ context '#expected_message_from' do
+ it 'returns the message as-is' do
+ finder = build_finder
+
+ message = finder.expected_message_from('some message')
+
+ message.should == 'some message'
+ end
+ end
+
+ context '#has_messages?' do
+ it 'has messages when some validations fail' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ result = finder.has_messages?
+
+ result.should be_true
+ end
+
+ it 'has no messages when all validations pass' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ result = finder.has_messages?
+
+ result.should be_false
+ end
+ end
+
+ context '#messages' do
+ it 'returns errors for the given attribute' do
+ finder = build_finder(:format => /abc/, :value => 'xyz')
+
+ messages = finder.messages
+
+ messages.should == ['is invalid']
+ end
+ end
+
+ context '#messages_description' do
+ it 'describes errors for the given attribute' do
+ value = 'xyz'
+ finder = build_finder(
+ :attribute => :attr,
+ :format => /abc/,
+ :value => 'xyz'
+ )
+
+ description = finder.messages_description
+
+ expected_messages = ['attr is invalid ("xyz")']
+ description.should == "errors: #{expected_messages}"
+ end
+
+ it 'describes errors when there are none' do
+ finder = build_finder(:format => /abc/, :value => 'abc')
+
+ description = finder.messages_description
+
+ description.should == 'no errors'
+ end
+ end
+
+ context '#source_description' do
+ it 'describes the source of its messages' do
+ finder = build_finder
+
+ description = finder.source_description
+
+ description.should == 'errors'
+ end
+ end
+
+ def build_finder(arguments = {})
+ arguments[:attribute] ||= :attr
+ instance = build_instance_validating(
+ arguments[:attribute],
+ arguments[:format] || /abc/,
+ arguments[:value] || 'abc'
+ )
+ Shoulda::Matchers::ActiveModel::ValidationMessageFinder.new(
+ instance,
+ arguments[:attribute]
+ )
+ end
+
+ def build_instance_validating(attribute, format, value)
+ model_class = define_model(:example, attribute => :string) do
+ attr_accessible attribute
+ validates_format_of attribute, :with => format
+ end
+
+ model_class.new(attribute => value)
+ end
+end
View
8 spec/shoulda/active_record/association_matcher_spec.rb
@@ -370,6 +370,14 @@
Person.new.should_not @matcher
end
+ it "should accept an association with an existing custom foreign key" do
+ define_model :detail, :detailed_person_id => :integer
+ define_model :person do
+ has_one :detail, :foreign_key => :detailed_person_id
+ end
+ Person.new.should @matcher.with_foreign_key(:detailed_person_id)
+ end
+
it "should reject an association with a bad :as option" do
define_model :detail, :detailable_id => :integer,
:detailable_type => :string
View
17 spec/shoulda/active_record/have_db_index_matcher_spec.rb
@@ -85,4 +85,21 @@
it "should not context an index's uniqueness when it isn't important" do
have_db_index(:user_id).description.should_not =~ /unique/
end
+
+ it "allows an IndexDefinition to have a truthy value for unique" do
+ db_connection = create_table 'superheros' do |table|
+ table.integer :age
+ end
+ db_connection.add_index :superheros, :age
+ define_model_class 'Superhero'
+
+ @matcher = have_db_index(:age).unique(true)
+
+ index_definition = stub("ActiveRecord::ConnectionAdapters::IndexDefinition",
+ :unique => 7,
+ :name => :age)
+ @matcher.stubs(:matched_index => index_definition)
+
+ Superhero.new.should @matcher
+ end
end

Showing you all comments on commits in this comparison.

@rmm5t
Owner

columns_hash is ActiveRecord only. It's not a standard ActiveModel method.

Something went wrong with that request. Please try again.