ratnikov-shoulda 2.0.6.3 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +3 -2
- data/Rakefile +1 -1
- data/lib/shoulda/active_record/assertions.rb +10 -31
- data/lib/shoulda/active_record/helpers.rb +40 -0
- data/lib/shoulda/active_record/macros.rb +171 -325
- data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
- data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
- data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
- data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
- data/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
- data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
- data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
- data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
- data/lib/shoulda/active_record/matchers.rb +42 -0
- data/lib/shoulda/active_record.rb +4 -0
- data/lib/shoulda/assertions.rb +12 -0
- data/lib/shoulda/autoload_macros.rb +46 -0
- data/lib/shoulda/rails.rb +1 -8
- data/lib/shoulda/rspec.rb +5 -0
- data/lib/shoulda/tasks/list_tests.rake +6 -1
- data/lib/shoulda/test_unit.rb +19 -0
- data/lib/shoulda.rb +5 -17
- data/rails/init.rb +1 -1
- data/test/README +2 -2
- data/test/fail_macros.rb +2 -2
- data/test/matchers/allow_mass_assignment_of_matcher_test.rb +68 -0
- data/test/matchers/allow_value_matcher_test.rb +41 -0
- data/test/matchers/association_matcher_test.rb +258 -0
- data/test/matchers/ensure_inclusion_of_matcher_test.rb +80 -0
- data/test/matchers/ensure_length_of_matcher_test.rb +158 -0
- data/test/matchers/have_db_column_matcher_test.rb +169 -0
- data/test/matchers/have_index_matcher_test.rb +74 -0
- data/test/matchers/have_named_scope_matcher_test.rb +65 -0
- data/test/matchers/have_readonly_attributes_matcher_test.rb +29 -0
- data/test/matchers/validate_acceptance_of_matcher_test.rb +44 -0
- data/test/matchers/validate_numericality_of_matcher_test.rb +52 -0
- data/test/matchers/validate_presence_of_matcher_test.rb +86 -0
- data/test/matchers/validate_uniqueness_of_matcher_test.rb +141 -0
- data/test/model_builder.rb +61 -0
- data/test/other/autoload_macro_test.rb +18 -0
- data/test/other/helpers_test.rb +58 -0
- data/test/rails_root/config/database.yml +1 -1
- data/test/rails_root/config/environments/{sqlite3.rb → test.rb} +0 -0
- data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
- data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
- data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
- data/test/test_helper.rb +3 -1
- data/test/unit/address_test.rb +1 -1
- data/test/unit/dog_test.rb +1 -1
- data/test/unit/post_test.rb +4 -4
- data/test/unit/product_test.rb +2 -2
- data/test/unit/tag_test.rb +2 -1
- data/test/unit/user_test.rb +8 -7
- metadata +49 -3
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Shoulda # :nodoc:
|
|
2
|
+
module ActiveRecord # :nodoc:
|
|
3
|
+
module Matchers
|
|
4
|
+
|
|
5
|
+
# Ensures that the model is invalid if the given attribute is not unique.
|
|
6
|
+
#
|
|
7
|
+
# Internally, this uses values from existing records to test validations,
|
|
8
|
+
# so this will always fail if you have not saved at least one record for
|
|
9
|
+
# the model being tested, like so:
|
|
10
|
+
#
|
|
11
|
+
# describe User do
|
|
12
|
+
# before(:each) { User.create!(:email => 'address@example.com') }
|
|
13
|
+
# it { should validate_uniqueness_of(:email) }
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Options:
|
|
17
|
+
#
|
|
18
|
+
# * <tt>with_message</tt> - value the test expects to find in
|
|
19
|
+
# <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
|
|
20
|
+
# Defaults to the translation for <tt>:taken</tt>.
|
|
21
|
+
# * <tt>scoped_to</tt> - field(s) to scope the uniqueness to.
|
|
22
|
+
# * <tt>case_insensitive</tt> - ensures that the validation does not
|
|
23
|
+
# check case. Off by default. Ignored by non-text attributes.
|
|
24
|
+
#
|
|
25
|
+
# Examples:
|
|
26
|
+
# it { should validate_uniqueness_of(:keyword) }
|
|
27
|
+
# it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
|
|
28
|
+
# it { should validate_uniqueness_of(:email).scoped_to(:name) }
|
|
29
|
+
# it { should validate_uniqueness_of(:email).
|
|
30
|
+
# scoped_to(:first_name, :last_name) }
|
|
31
|
+
# it { should validate_uniqueness_of(:keyword).case_insensitive }
|
|
32
|
+
#
|
|
33
|
+
def validate_uniqueness_of(attr)
|
|
34
|
+
ValidateUniquenessOfMatcher.new(attr)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class ValidateUniquenessOfMatcher < ValidationMatcher # :nodoc:
|
|
38
|
+
include Helpers
|
|
39
|
+
|
|
40
|
+
def initialize(attribute)
|
|
41
|
+
@attribute = attribute
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def scoped_to(*scopes)
|
|
45
|
+
@scopes = [*scopes].flatten
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def with_message(message)
|
|
50
|
+
@expected_message = message
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def case_insensitive
|
|
55
|
+
@case_insensitive = true
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def description
|
|
60
|
+
result = "require "
|
|
61
|
+
result << "case sensitive " unless @case_insensitive
|
|
62
|
+
result << "unique value for #{@attribute}"
|
|
63
|
+
result << " scoped to #{@scopes.join(', ')}" unless @scopes.blank?
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def matches?(subject)
|
|
68
|
+
@subject = subject.class.new
|
|
69
|
+
@expected_message ||= :taken
|
|
70
|
+
find_existing &&
|
|
71
|
+
set_scoped_attributes &&
|
|
72
|
+
validate_attribute &&
|
|
73
|
+
validate_after_scope_change
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def find_existing
|
|
79
|
+
if @existing = @subject.class.find(:first)
|
|
80
|
+
@failure_message = "Can't find first #{class_name}"
|
|
81
|
+
true
|
|
82
|
+
else
|
|
83
|
+
false
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def set_scoped_attributes
|
|
88
|
+
unless @scopes.blank?
|
|
89
|
+
@scopes.each do |scope|
|
|
90
|
+
setter = :"#{scope}="
|
|
91
|
+
unless @subject.respond_to?(setter)
|
|
92
|
+
@failure_message =
|
|
93
|
+
"#{class_name} doesn't seem to have a #{scope} attribute."
|
|
94
|
+
return false
|
|
95
|
+
end
|
|
96
|
+
@subject.send("#{scope}=", @existing.send(scope))
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
true
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def validate_attribute
|
|
103
|
+
disallows_value_of(existing_value, @expected_message)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# TODO: There is a chance that we could change the scoped field
|
|
107
|
+
# to a value that's already taken. An alternative implementation
|
|
108
|
+
# could actually find all values for scope and create a unique
|
|
109
|
+
def validate_after_scope_change
|
|
110
|
+
if @scopes.blank?
|
|
111
|
+
true
|
|
112
|
+
else
|
|
113
|
+
@scopes.all? do |scope|
|
|
114
|
+
previous_value = @existing.send(scope)
|
|
115
|
+
|
|
116
|
+
# Assume the scope is a foreign key if the field is nil
|
|
117
|
+
previous_value ||= 0
|
|
118
|
+
|
|
119
|
+
next_value = previous_value.next
|
|
120
|
+
|
|
121
|
+
@subject.send("#{scope}=", next_value)
|
|
122
|
+
|
|
123
|
+
if allows_value_of(existing_value, @expected_message)
|
|
124
|
+
@negative_failure_message <<
|
|
125
|
+
" (with different value of #{scope})"
|
|
126
|
+
true
|
|
127
|
+
else
|
|
128
|
+
@failure_message << " (with different value of #{scope})"
|
|
129
|
+
false
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def class_name
|
|
136
|
+
@subject.class.name
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def existing_value
|
|
140
|
+
value = @existing.send(@attribute)
|
|
141
|
+
value.swapcase! if @case_insensitive && value.respond_to?(:swapcase!)
|
|
142
|
+
value
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Shoulda # :nodoc:
|
|
2
|
+
module ActiveRecord # :nodoc:
|
|
3
|
+
module Matchers
|
|
4
|
+
|
|
5
|
+
class ValidationMatcher # :nodoc:
|
|
6
|
+
|
|
7
|
+
attr_reader :failure_message
|
|
8
|
+
|
|
9
|
+
def initialize(attribute)
|
|
10
|
+
@attribute = attribute
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def negative_failure_message
|
|
14
|
+
@negative_failure_message || @failure_message
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def matches?(subject)
|
|
18
|
+
@subject = subject
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def allows_value_of(value, message = nil)
|
|
25
|
+
allow = AllowValueMatcher.
|
|
26
|
+
new(value).
|
|
27
|
+
for(@attribute).
|
|
28
|
+
with_message(message)
|
|
29
|
+
if allow.matches?(@subject)
|
|
30
|
+
@negative_failure_message = allow.failure_message
|
|
31
|
+
true
|
|
32
|
+
else
|
|
33
|
+
@failure_message = allow.negative_failure_message
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def disallows_value_of(value, message = nil)
|
|
39
|
+
disallow = AllowValueMatcher.
|
|
40
|
+
new(value).
|
|
41
|
+
for(@attribute).
|
|
42
|
+
with_message(message)
|
|
43
|
+
if disallow.matches?(@subject)
|
|
44
|
+
@failure_message = disallow.negative_failure_message
|
|
45
|
+
false
|
|
46
|
+
else
|
|
47
|
+
@negative_failure_message = disallow.failure_message
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'shoulda/active_record/helpers'
|
|
2
|
+
require 'shoulda/active_record/matchers/validation_matcher'
|
|
3
|
+
require 'shoulda/active_record/matchers/allow_value_matcher'
|
|
4
|
+
require 'shoulda/active_record/matchers/ensure_length_of_matcher'
|
|
5
|
+
require 'shoulda/active_record/matchers/ensure_inclusion_of_matcher'
|
|
6
|
+
require 'shoulda/active_record/matchers/validate_presence_of_matcher'
|
|
7
|
+
require 'shoulda/active_record/matchers/validate_uniqueness_of_matcher'
|
|
8
|
+
require 'shoulda/active_record/matchers/validate_acceptance_of_matcher'
|
|
9
|
+
require 'shoulda/active_record/matchers/validate_numericality_of_matcher'
|
|
10
|
+
require 'shoulda/active_record/matchers/association_matcher'
|
|
11
|
+
require 'shoulda/active_record/matchers/have_db_column_matcher'
|
|
12
|
+
require 'shoulda/active_record/matchers/have_index_matcher'
|
|
13
|
+
require 'shoulda/active_record/matchers/have_readonly_attribute_matcher'
|
|
14
|
+
require 'shoulda/active_record/matchers/allow_mass_assignment_of_matcher'
|
|
15
|
+
require 'shoulda/active_record/matchers/have_named_scope_matcher'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
module Shoulda # :nodoc:
|
|
19
|
+
module ActiveRecord # :nodoc:
|
|
20
|
+
# = Matchers for your active record models
|
|
21
|
+
#
|
|
22
|
+
# These matchers will test most of the validations and associations for your
|
|
23
|
+
# ActiveRecord models.
|
|
24
|
+
#
|
|
25
|
+
# describe User do
|
|
26
|
+
# it { should validate_presence_of(:name) }
|
|
27
|
+
# it { should validate_presence_of(:phone_number) }
|
|
28
|
+
# %w(abcd 1234).each do |value|
|
|
29
|
+
# it { should_not allow_value(value).for(:phone_number) }
|
|
30
|
+
# end
|
|
31
|
+
# it { should allow_value("(123) 456-7890").for(:phone_number) }
|
|
32
|
+
# it { should_not allow_mass_assignment_of(:password) }
|
|
33
|
+
# it { should have_one(:profile) }
|
|
34
|
+
# it { should have_many(:dogs) }
|
|
35
|
+
# it { should have_many(:messes).through(:dogs) }
|
|
36
|
+
# it { should belong_to(:lover) }
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
module Matchers
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
require 'shoulda'
|
|
2
|
+
require 'shoulda/active_record/helpers'
|
|
3
|
+
require 'shoulda/active_record/matchers'
|
|
2
4
|
require 'shoulda/active_record/assertions'
|
|
3
5
|
require 'shoulda/active_record/macros'
|
|
4
6
|
|
|
5
7
|
module Test # :nodoc: all
|
|
6
8
|
module Unit
|
|
7
9
|
class TestCase
|
|
10
|
+
include Shoulda::ActiveRecord::Helpers
|
|
11
|
+
include Shoulda::ActiveRecord::Matchers
|
|
8
12
|
include Shoulda::ActiveRecord::Assertions
|
|
9
13
|
extend Shoulda::ActiveRecord::Macros
|
|
10
14
|
end
|
data/lib/shoulda/assertions.rb
CHANGED
|
@@ -43,5 +43,17 @@ module Shoulda # :nodoc:
|
|
|
43
43
|
assert(!collection.include?(x), msg)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
# Asserts that the given matcher returns true when +target+ is passed to #matches?
|
|
48
|
+
def assert_accepts(matcher, target)
|
|
49
|
+
success = matcher.matches?(target)
|
|
50
|
+
assert_block(matcher.failure_message) { success }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Asserts that the given matcher returns false when +target+ is passed to #matches?
|
|
54
|
+
def assert_rejects(matcher, target)
|
|
55
|
+
success = !matcher.matches?(target)
|
|
56
|
+
assert_block(matcher.negative_failure_message) { success }
|
|
57
|
+
end
|
|
46
58
|
end
|
|
47
59
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Shoulda # :nodoc:
|
|
2
|
+
# Call autoload_macros when you want to load test macros automatically in a non-Rails
|
|
3
|
+
# project (it's done automatically for Rails projects).
|
|
4
|
+
# You don't need to specify ROOT/test/shoulda_macros explicitly. Your custom macros
|
|
5
|
+
# are loaded automatically when you call autoload_macros.
|
|
6
|
+
#
|
|
7
|
+
# The first argument is the path to you application's root directory.
|
|
8
|
+
# All following arguments are directories relative to your root, which contain
|
|
9
|
+
# shoulda_macros subdirectories. These directories support the same kinds of globs as the
|
|
10
|
+
# Dir class.
|
|
11
|
+
#
|
|
12
|
+
# Basic usage (from a test_helper):
|
|
13
|
+
# Shoulda.autoload_macros(File.dirname(__FILE__) + '/..')
|
|
14
|
+
# will load everything in
|
|
15
|
+
# - your_app/test/shoulda_macros
|
|
16
|
+
#
|
|
17
|
+
# To load vendored macros as well:
|
|
18
|
+
# Shoulda.autoload_macros(APP_ROOT, 'vendor/*')
|
|
19
|
+
# will load everything in
|
|
20
|
+
# - APP_ROOT/vendor/*/shoulda_macros
|
|
21
|
+
# - APP_ROOT/test/shoulda_macros
|
|
22
|
+
#
|
|
23
|
+
# To load macros in an app with a vendor directory laid out like Rails':
|
|
24
|
+
# Shoulda.autoload_macros(APP_ROOT, 'vendor/{plugins,gems}/*')
|
|
25
|
+
# or
|
|
26
|
+
# Shoulda.autoload_macros(APP_ROOT, 'vendor/plugins/*', 'vendor/gems/*')
|
|
27
|
+
# will load everything in
|
|
28
|
+
# - APP_ROOT/vendor/plugins/*/shoulda_macros
|
|
29
|
+
# - APP_ROOT/vendor/gems/*/shoulda_macros
|
|
30
|
+
# - APP_ROOT/test/shoulda_macros
|
|
31
|
+
#
|
|
32
|
+
# If you prefer to stick testing dependencies away from your production dependencies:
|
|
33
|
+
# Shoulda.autoload_macros(APP_ROOT, 'vendor/*', 'test/vendor/*')
|
|
34
|
+
# will load everything in
|
|
35
|
+
# - APP_ROOT/vendor/*/shoulda_macros
|
|
36
|
+
# - APP_ROOT/test/vendor/*/shoulda_macros
|
|
37
|
+
# - APP_ROOT/test/shoulda_macros
|
|
38
|
+
def self.autoload_macros(root, *dirs)
|
|
39
|
+
dirs << File.join('test')
|
|
40
|
+
complete_dirs = dirs.map{|d| File.join(root, d, 'shoulda_macros')}
|
|
41
|
+
all_files = complete_dirs.inject([]){ |files, dir| files + Dir[File.join(dir, '*.rb')] }
|
|
42
|
+
all_files.each do |file|
|
|
43
|
+
require file
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/shoulda/rails.rb
CHANGED
|
@@ -8,12 +8,5 @@ require 'shoulda/action_mailer' if defined? ActionMailer::Base
|
|
|
8
8
|
|
|
9
9
|
if defined?(RAILS_ROOT)
|
|
10
10
|
# load in the 3rd party macros from vendorized plugins and gems
|
|
11
|
-
|
|
12
|
-
require macro_file_path
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# load in the local application specific macros
|
|
16
|
-
Dir[File.join(RAILS_ROOT, "test", "shoulda_macros", "*.rb")].each do |macro_file_path|
|
|
17
|
-
require macro_file_path
|
|
18
|
-
end
|
|
11
|
+
Shoulda.autoload_macros RAILS_ROOT, File.join("vendor", "{plugins,gems}", "*")
|
|
19
12
|
end
|
|
@@ -13,7 +13,12 @@ namespace :shoulda do
|
|
|
13
13
|
test_files = Dir.glob(File.join('test', '**', '*_test.rb'))
|
|
14
14
|
test_files.each do |file|
|
|
15
15
|
load file
|
|
16
|
-
klass = File.basename(file, '.rb').classify
|
|
16
|
+
klass = File.basename(file, '.rb').classify
|
|
17
|
+
unless Object.const_defined?(klass.to_s)
|
|
18
|
+
puts "Skipping #{klass} because it doesn't map to a Class"
|
|
19
|
+
next
|
|
20
|
+
end
|
|
21
|
+
klass = klass.constantize
|
|
17
22
|
|
|
18
23
|
puts klass.name.gsub('Test', '')
|
|
19
24
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'shoulda/context'
|
|
2
|
+
require 'shoulda/proc_extensions'
|
|
3
|
+
require 'shoulda/assertions'
|
|
4
|
+
require 'shoulda/macros'
|
|
5
|
+
require 'shoulda/helpers'
|
|
6
|
+
require 'shoulda/autoload_macros'
|
|
7
|
+
require 'shoulda/rails' if defined? RAILS_ROOT
|
|
8
|
+
|
|
9
|
+
module Test # :nodoc: all
|
|
10
|
+
module Unit
|
|
11
|
+
class TestCase
|
|
12
|
+
extend Shoulda::ClassMethods
|
|
13
|
+
include Shoulda::Assertions
|
|
14
|
+
extend Shoulda::Macros
|
|
15
|
+
include Shoulda::Helpers
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
data/lib/shoulda.rb
CHANGED
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
require 'shoulda/context'
|
|
2
|
-
require 'shoulda/proc_extensions'
|
|
3
|
-
require 'shoulda/assertions'
|
|
4
|
-
require 'shoulda/macros'
|
|
5
|
-
require 'shoulda/helpers'
|
|
6
|
-
require 'shoulda/rails' if defined? RAILS_ROOT
|
|
7
|
-
|
|
8
1
|
module Shoulda
|
|
9
|
-
VERSION = "2.0
|
|
2
|
+
VERSION = "2.9.0"
|
|
10
3
|
end
|
|
11
4
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
include Shoulda::Assertions
|
|
17
|
-
extend Shoulda::Macros
|
|
18
|
-
include Shoulda::Helpers
|
|
19
|
-
end
|
|
20
|
-
end
|
|
5
|
+
if defined? Spec
|
|
6
|
+
require 'shoulda/rspec'
|
|
7
|
+
else
|
|
8
|
+
require 'shoulda/test_unit'
|
|
21
9
|
end
|
data/rails/init.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require 'shoulda/rails'
|
|
1
|
+
require 'shoulda/rails' if RAILS_ENV == 'test'
|
data/test/README
CHANGED
|
@@ -6,7 +6,7 @@ The test directory contains the following files and subdirectories:
|
|
|
6
6
|
|
|
7
7
|
* rails_root - contains the stripped down rails application that the tests run against. The rails root contains:
|
|
8
8
|
** the models, controllers, and views defined under app/
|
|
9
|
-
** the
|
|
9
|
+
** the test.rb environment file
|
|
10
10
|
** a migration file for each model
|
|
11
11
|
** a shoulda initializer that simulates loading the plugin but without relying on vendor/plugins
|
|
12
12
|
* fixtures - contain the sample DB data for each model
|
|
@@ -14,7 +14,7 @@ The test directory contains the following files and subdirectories:
|
|
|
14
14
|
* unit - model tests for each of the models under rails_root/app
|
|
15
15
|
* other - tests for the shoulda contexts, should statements, and assertions
|
|
16
16
|
* test_helper.rb - responsible for initializing the test environment
|
|
17
|
-
** sets the rails_env to
|
|
17
|
+
** sets the rails_env to test
|
|
18
18
|
** sets the rails_root
|
|
19
19
|
** runs all the migrations against the in-memory sqlite3 db
|
|
20
20
|
** adds some magic to load the right fixture files
|
data/test/fail_macros.rb
CHANGED
|
@@ -8,8 +8,8 @@ module Shoulda
|
|
|
8
8
|
# example, to ensure that a set of test macros should fail, do this:
|
|
9
9
|
#
|
|
10
10
|
# should_fail do
|
|
11
|
-
#
|
|
12
|
-
#
|
|
11
|
+
# should_validate_presence_of :comments
|
|
12
|
+
# should_not_allow_mass_assignment_of :name
|
|
13
13
|
# end
|
|
14
14
|
def should_fail(&block)
|
|
15
15
|
context "should fail when trying to run:" do
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
|
2
|
+
|
|
3
|
+
class AllowMassAssignmentOfMatcherTest < Test::Unit::TestCase # :nodoc:
|
|
4
|
+
|
|
5
|
+
context "an attribute that is blacklisted from mass-assignment" do
|
|
6
|
+
setup do
|
|
7
|
+
define_model :example, :attr => :string do
|
|
8
|
+
attr_protected :attr
|
|
9
|
+
end
|
|
10
|
+
@model = Example.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
should "reject being mass-assignable" do
|
|
14
|
+
assert_rejects allow_mass_assignment_of(:attr), @model
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "an attribute that is not whitelisted for mass-assignment" do
|
|
19
|
+
setup do
|
|
20
|
+
define_model :example, :attr => :string, :other => :string do
|
|
21
|
+
attr_accessible :other
|
|
22
|
+
end
|
|
23
|
+
@model = Example.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should "reject being mass-assignable" do
|
|
27
|
+
assert_rejects allow_mass_assignment_of(:attr), @model
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "an attribute that is whitelisted for mass-assignment" do
|
|
32
|
+
setup do
|
|
33
|
+
define_model :example, :attr => :string do
|
|
34
|
+
attr_accessible :attr
|
|
35
|
+
end
|
|
36
|
+
@model = Example.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should "accept being mass-assignable" do
|
|
40
|
+
assert_accepts allow_mass_assignment_of(:attr), @model
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "an attribute not included in the mass-assignment blacklist" do
|
|
45
|
+
setup do
|
|
46
|
+
define_model :example, :attr => :string, :other => :string do
|
|
47
|
+
attr_protected :other
|
|
48
|
+
end
|
|
49
|
+
@model = Example.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
should "accept being mass-assignable" do
|
|
53
|
+
assert_accepts allow_mass_assignment_of(:attr), @model
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "an attribute on a class with no protected attributes" do
|
|
58
|
+
setup do
|
|
59
|
+
define_model :example, :attr => :string
|
|
60
|
+
@model = Example.new
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
should "accept being mass-assignable" do
|
|
64
|
+
assert_accepts allow_mass_assignment_of(:attr), @model
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
|
2
|
+
|
|
3
|
+
class AllowValueMatcherTest < Test::Unit::TestCase # :nodoc:
|
|
4
|
+
|
|
5
|
+
context "an attribute with a format validation" do
|
|
6
|
+
setup do
|
|
7
|
+
define_model :example, :attr => :string do
|
|
8
|
+
validates_format_of :attr, :with => /abc/
|
|
9
|
+
end
|
|
10
|
+
@model = Example.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
should "allow a good value" do
|
|
14
|
+
assert_accepts allow_value("abcde").for(:attr), @model
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
should "not allow a bad value" do
|
|
18
|
+
assert_rejects allow_value("xyz").for(:attr), @model
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "an attribute with a format validation and a custom message" do
|
|
23
|
+
setup do
|
|
24
|
+
define_model :example, :attr => :string do
|
|
25
|
+
validates_format_of :attr, :with => /abc/, :message => 'bad value'
|
|
26
|
+
end
|
|
27
|
+
@model = Example.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should "allow a good value" do
|
|
31
|
+
assert_accepts allow_value('abcde').for(:attr).with_message(/bad/),
|
|
32
|
+
@model
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
should "not allow a bad value" do
|
|
36
|
+
assert_rejects allow_value('xyz').for(:attr).with_message(/bad/),
|
|
37
|
+
@model
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|