technicalpickles-shoulda 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/shoulda/active_record/assertions.rb +2 -1
- data/lib/shoulda/active_record/macros.rb +44 -25
- data/lib/shoulda/context.rb +1 -1
- data/lib/shoulda/controller/macros.rb +95 -0
- data/lib/shoulda/controller.rb +0 -1
- data/test/functional/posts_controller_test.rb +25 -0
- data/test/rails_root/app/controllers/posts_controller.rb +8 -1
- data/test/rails_root/app/models/user.rb +1 -1
- data/test/rails_root/config/environment.rb +2 -2
- data/test/test_helper.rb +6 -4
- data/test/unit/tag_test.rb +4 -0
- data/test/unit/user_test.rb +5 -0
- metadata +1 -1
- data/lib/shoulda/controller/routing/macros.rb +0 -47
- data/lib/shoulda/controller/routing.rb +0 -10
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rake/testtask'
|
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
require 'rake/gempackagetask'
|
5
5
|
require 'lib/shoulda/context'
|
6
|
-
|
6
|
+
load 'tasks/shoulda.rake'
|
7
7
|
|
8
8
|
# Test::Unit::UI::VERBOSE
|
9
9
|
test_files_pattern = 'test/{unit,functional,other}/**/*_test.rb'
|
@@ -56,7 +56,8 @@ module ThoughtBot # :nodoc:
|
|
56
56
|
#
|
57
57
|
# @product = Product.new(:tangible => true)
|
58
58
|
# assert_bad_value(Product, :price, "0")
|
59
|
-
def assert_bad_value(object_or_klass, attribute, value,
|
59
|
+
def assert_bad_value(object_or_klass, attribute, value,
|
60
|
+
error_message_to_expect = DEFAULT_ERROR_MESSAGES[:invalid])
|
60
61
|
object = get_instance_of(object_or_klass)
|
61
62
|
object.send("#{attribute}=", value)
|
62
63
|
assert !object.valid?, "#{object.class} allowed #{value.inspect} as a value for #{attribute}"
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module ThoughtBot # :nodoc:
|
2
2
|
module Shoulda # :nodoc:
|
3
3
|
module ActiveRecord # :nodoc:
|
4
|
+
DEFAULT_ERROR_MESSAGES =
|
5
|
+
if Object.const_defined?(:I18n)
|
6
|
+
I18n.translate('active_record.error_messages')
|
7
|
+
else
|
8
|
+
::ActiveRecord::Errors.default_error_messages
|
9
|
+
end
|
10
|
+
|
4
11
|
# = Macro test helpers for your active record models
|
5
12
|
#
|
6
13
|
# These helpers will test most of the validations and associations for your ActiveRecord models.
|
@@ -36,14 +43,14 @@ module ThoughtBot # :nodoc:
|
|
36
43
|
#
|
37
44
|
# Options:
|
38
45
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
39
|
-
# Regexp or string. Default = <tt
|
46
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:blank]</tt>
|
40
47
|
#
|
41
48
|
# Example:
|
42
49
|
# should_require_attributes :name, :phone_number
|
43
50
|
#
|
44
51
|
def should_require_attributes(*attributes)
|
45
52
|
message = get_options!(attributes, :message)
|
46
|
-
message ||=
|
53
|
+
message ||= DEFAULT_ERROR_MESSAGES[:blank]
|
47
54
|
klass = model_class
|
48
55
|
|
49
56
|
attributes.each do |attribute|
|
@@ -58,7 +65,7 @@ module ThoughtBot # :nodoc:
|
|
58
65
|
#
|
59
66
|
# Options:
|
60
67
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
61
|
-
# Regexp or string. Default = <tt
|
68
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:taken]</tt>
|
62
69
|
# * <tt>:scoped_to</tt> - field(s) to scope the uniqueness to.
|
63
70
|
#
|
64
71
|
# Examples:
|
@@ -70,7 +77,7 @@ module ThoughtBot # :nodoc:
|
|
70
77
|
def should_require_unique_attributes(*attributes)
|
71
78
|
message, scope = get_options!(attributes, :message, :scoped_to)
|
72
79
|
scope = [*scope].compact
|
73
|
-
message ||=
|
80
|
+
message ||= DEFAULT_ERROR_MESSAGES[:taken]
|
74
81
|
|
75
82
|
klass = model_class
|
76
83
|
attributes.each do |attribute|
|
@@ -118,7 +125,8 @@ module ThoughtBot # :nodoc:
|
|
118
125
|
protected = klass.protected_attributes || []
|
119
126
|
accessible = klass.accessible_attributes || []
|
120
127
|
|
121
|
-
assert protected.include?(attribute.to_s) ||
|
128
|
+
assert protected.include?(attribute.to_s) ||
|
129
|
+
(!accessible.empty? && !accessible.include?(attribute.to_s)),
|
122
130
|
(accessible.empty? ?
|
123
131
|
"#{klass} is protecting #{protected.to_a.to_sentence}, but not #{attribute}." :
|
124
132
|
"#{klass} has made #{attribute} accessible")
|
@@ -155,14 +163,14 @@ module ThoughtBot # :nodoc:
|
|
155
163
|
#
|
156
164
|
# Options:
|
157
165
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
158
|
-
# Regexp or string. Default = <tt
|
166
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:invalid]</tt>
|
159
167
|
#
|
160
168
|
# Example:
|
161
169
|
# should_not_allow_values_for :isbn, "bad 1", "bad 2"
|
162
170
|
#
|
163
171
|
def should_not_allow_values_for(attribute, *bad_values)
|
164
172
|
message = get_options!(bad_values, :message)
|
165
|
-
message ||=
|
173
|
+
message ||= DEFAULT_ERROR_MESSAGES[:invalid]
|
166
174
|
klass = model_class
|
167
175
|
bad_values.each do |v|
|
168
176
|
should "not allow #{attribute} to be set to #{v.inspect}" do
|
@@ -198,17 +206,17 @@ module ThoughtBot # :nodoc:
|
|
198
206
|
#
|
199
207
|
# Options:
|
200
208
|
# * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
201
|
-
# Regexp or string. Default = <tt
|
209
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:too_short] % range.first</tt>
|
202
210
|
# * <tt>:long_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
203
|
-
# Regexp or string. Default = <tt
|
211
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:too_long] % range.last</tt>
|
204
212
|
#
|
205
213
|
# Example:
|
206
214
|
# should_ensure_length_in_range :password, (6..20)
|
207
215
|
#
|
208
216
|
def should_ensure_length_in_range(attribute, range, opts = {})
|
209
217
|
short_message, long_message = get_options!([opts], :short_message, :long_message)
|
210
|
-
short_message ||=
|
211
|
-
long_message ||=
|
218
|
+
short_message ||= DEFAULT_ERROR_MESSAGES[:too_short] % range.first
|
219
|
+
long_message ||= DEFAULT_ERROR_MESSAGES[:too_long] % range.last
|
212
220
|
|
213
221
|
klass = model_class
|
214
222
|
min_length = range.first
|
@@ -250,14 +258,14 @@ module ThoughtBot # :nodoc:
|
|
250
258
|
#
|
251
259
|
# Options:
|
252
260
|
# * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
253
|
-
# Regexp or string. Default = <tt
|
261
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:too_short] % min_length</tt>
|
254
262
|
#
|
255
263
|
# Example:
|
256
264
|
# should_ensure_length_at_least :name, 3
|
257
265
|
#
|
258
266
|
def should_ensure_length_at_least(attribute, min_length, opts = {})
|
259
267
|
short_message = get_options!([opts], :short_message)
|
260
|
-
short_message ||=
|
268
|
+
short_message ||= DEFAULT_ERROR_MESSAGES[:too_short] % min_length
|
261
269
|
|
262
270
|
klass = model_class
|
263
271
|
|
@@ -281,14 +289,14 @@ module ThoughtBot # :nodoc:
|
|
281
289
|
#
|
282
290
|
# Options:
|
283
291
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
284
|
-
# Regexp or string. Default = <tt
|
292
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:wrong_length] % length</tt>
|
285
293
|
#
|
286
294
|
# Example:
|
287
295
|
# should_ensure_length_is :ssn, 9
|
288
296
|
#
|
289
297
|
def should_ensure_length_is(attribute, length, opts = {})
|
290
298
|
message = get_options!([opts], :message)
|
291
|
-
message ||=
|
299
|
+
message ||= DEFAULT_ERROR_MESSAGES[:wrong_length] % length
|
292
300
|
|
293
301
|
klass = model_class
|
294
302
|
|
@@ -316,17 +324,17 @@ module ThoughtBot # :nodoc:
|
|
316
324
|
#
|
317
325
|
# Options:
|
318
326
|
# * <tt>:low_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
319
|
-
# Regexp or string. Default = <tt
|
327
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:inclusion]</tt>
|
320
328
|
# * <tt>:high_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
321
|
-
# Regexp or string. Default = <tt
|
329
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:inclusion]</tt>
|
322
330
|
#
|
323
331
|
# Example:
|
324
332
|
# should_ensure_value_in_range :age, (0..100)
|
325
333
|
#
|
326
334
|
def should_ensure_value_in_range(attribute, range, opts = {})
|
327
335
|
low_message, high_message = get_options!([opts], :low_message, :high_message)
|
328
|
-
low_message ||=
|
329
|
-
high_message ||=
|
336
|
+
low_message ||= DEFAULT_ERROR_MESSAGES[:inclusion]
|
337
|
+
high_message ||= DEFAULT_ERROR_MESSAGES[:inclusion]
|
330
338
|
|
331
339
|
klass = model_class
|
332
340
|
min = range.first
|
@@ -361,14 +369,14 @@ module ThoughtBot # :nodoc:
|
|
361
369
|
#
|
362
370
|
# Options:
|
363
371
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
364
|
-
# Regexp or string. Default = <tt
|
372
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:not_a_number]</tt>
|
365
373
|
#
|
366
374
|
# Example:
|
367
375
|
# should_only_allow_numeric_values_for :age
|
368
376
|
#
|
369
377
|
def should_only_allow_numeric_values_for(*attributes)
|
370
378
|
message = get_options!(attributes, :message)
|
371
|
-
message ||=
|
379
|
+
message ||= DEFAULT_ERROR_MESSAGES[:not_a_number]
|
372
380
|
klass = model_class
|
373
381
|
attributes.each do |attribute|
|
374
382
|
attribute = attribute.to_sym
|
@@ -439,14 +447,19 @@ module ThoughtBot # :nodoc:
|
|
439
447
|
# associated table has the required columns. Works with polymorphic
|
440
448
|
# associations.
|
441
449
|
#
|
450
|
+
# Options:
|
451
|
+
# * <tt>:dependent</tt> - tests that the association makes use of the dependent option.
|
452
|
+
#
|
442
453
|
# Example:
|
443
454
|
# should_have_one :god # unless hindu
|
444
455
|
#
|
445
456
|
def should_have_one(*associations)
|
446
|
-
get_options!(associations)
|
457
|
+
dependent = get_options!(associations, :dependent)
|
447
458
|
klass = model_class
|
448
459
|
associations.each do |association|
|
449
|
-
|
460
|
+
name = "have one #{association}"
|
461
|
+
name += " dependent => #{dependent}" if dependent
|
462
|
+
should name do
|
450
463
|
reflection = klass.reflect_on_association(association)
|
451
464
|
assert reflection, "#{klass.name} does not have any relationship to #{association}"
|
452
465
|
assert_equal :has_one, reflection.macro
|
@@ -465,6 +478,12 @@ module ThoughtBot # :nodoc:
|
|
465
478
|
end
|
466
479
|
assert associated_klass.column_names.include?(fk.to_s),
|
467
480
|
"#{associated_klass.name} does not have a #{fk} foreign key."
|
481
|
+
|
482
|
+
if dependent
|
483
|
+
assert_equal dependent.to_s,
|
484
|
+
reflection.options[:dependent].to_s,
|
485
|
+
"#{association} should have #{dependent} dependency"
|
486
|
+
end
|
468
487
|
end
|
469
488
|
end
|
470
489
|
end
|
@@ -604,14 +623,14 @@ module ThoughtBot # :nodoc:
|
|
604
623
|
#
|
605
624
|
# Options:
|
606
625
|
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
607
|
-
# Regexp or string. Default = <tt
|
626
|
+
# Regexp or string. Default = <tt>I18n.translate('active_record.error_messages')[:accepted]</tt>
|
608
627
|
#
|
609
628
|
# Example:
|
610
629
|
# should_require_acceptance_of :eula
|
611
630
|
#
|
612
631
|
def should_require_acceptance_of(*attributes)
|
613
632
|
message = get_options!(attributes, :message)
|
614
|
-
message ||=
|
633
|
+
message ||= DEFAULT_ERROR_MESSAGES[:accepted]
|
615
634
|
klass = model_class
|
616
635
|
|
617
636
|
attributes.each do |attribute|
|
data/lib/shoulda/context.rb
CHANGED
@@ -134,6 +134,37 @@ module ThoughtBot # :nodoc:
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
|
+
# Macro that creates a test asserting that the response content type was 'content_type'.
|
138
|
+
# Example:
|
139
|
+
#
|
140
|
+
# should_respond_with_content_type 'application/rss+xml'
|
141
|
+
def should_respond_with_content_type(content_type)
|
142
|
+
should "respond with content type of #{content_type}" do
|
143
|
+
content_type = Mime::EXTENSION_LOOKUP[content_type.to_s].to_s if content_type.is_a? Symbol
|
144
|
+
if content_type.is_a? Regexp
|
145
|
+
assert_match content_type, @response.content_type, "Expected to match #{content_type} but was actually #{@response.content_type}"
|
146
|
+
else
|
147
|
+
assert_equal content_type, @response.content_type, "Expected #{content_type} but was actually #{@response.content_type}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Macro that creates a test asserting that a value returned from the session is correct.
|
153
|
+
# The given string is evaled to produce the resulting redirect path. All of the instance variables
|
154
|
+
# set by the controller are available to the evaled string.
|
155
|
+
# Example:
|
156
|
+
#
|
157
|
+
# should_return_from_session :user_id, '@user.id'
|
158
|
+
# should_return_from_session :message, '"Free stuff"'
|
159
|
+
def should_return_from_session(key, expected)
|
160
|
+
should "return the correct value from the session for key #{key}" do
|
161
|
+
instantiate_variables_from_assigns do
|
162
|
+
expected_value = eval(expected, self.send(:binding), __FILE__, __LINE__)
|
163
|
+
assert_equal expected_value, session[key], "Expected #{expected_value.inspect} but was #{session[key]}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
137
168
|
# Macro that creates a test asserting that the controller rendered the given template.
|
138
169
|
# Example:
|
139
170
|
#
|
@@ -144,6 +175,32 @@ module ThoughtBot # :nodoc:
|
|
144
175
|
end
|
145
176
|
end
|
146
177
|
|
178
|
+
# Macro that creates a test asserting that the controller rendered with the given layout.
|
179
|
+
# Example:
|
180
|
+
#
|
181
|
+
# should_render_with_layout 'special'
|
182
|
+
def should_render_with_layout(expected_layout = 'application')
|
183
|
+
if expected_layout
|
184
|
+
should "render with #{expected_layout} layout" do
|
185
|
+
response_layout = @response.layout.blank? ? "" : @response.layout.split('/').last
|
186
|
+
assert_equal expected_layout,
|
187
|
+
response_layout,
|
188
|
+
"Expected to render with layout #{expected_layout} but was rendered with #{response_layout}"
|
189
|
+
end
|
190
|
+
else
|
191
|
+
should "render without layout" do
|
192
|
+
assert_nil @response.layout,
|
193
|
+
"Expected no layout, but was rendered using #{@response.layout}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Macro that creates a test asserting that the controller rendered without a layout.
|
199
|
+
# Same as @should_render_with_layout false@
|
200
|
+
def should_render_without_layout
|
201
|
+
should_render_with_layout nil
|
202
|
+
end
|
203
|
+
|
147
204
|
# Macro that creates a test asserting that the controller returned a redirect to the given path.
|
148
205
|
# The given string is evaled to produce the resulting redirect path. All of the instance variables
|
149
206
|
# set by the controller are available to the evaled string.
|
@@ -165,6 +222,44 @@ module ThoughtBot # :nodoc:
|
|
165
222
|
assert_select "form", true, "The template doesn't contain a <form> element"
|
166
223
|
end
|
167
224
|
end
|
225
|
+
|
226
|
+
# Macro that creates a routing test. It tries to use the given HTTP
|
227
|
+
# +method+ on the given +path+, and asserts that it routes to the
|
228
|
+
# given +options+.
|
229
|
+
#
|
230
|
+
# If you don't specify a :controller, it will try to guess the controller
|
231
|
+
# based on the current test.
|
232
|
+
#
|
233
|
+
# +to_param+ is called on the +options+ given.
|
234
|
+
#
|
235
|
+
# Examples:
|
236
|
+
#
|
237
|
+
# should_route :get, '/posts', :action => :index
|
238
|
+
# should_route :post, '/posts', :controller => :posts, :action => :create
|
239
|
+
# should_route :get, '/posts/1', :action => :show, :id => 1
|
240
|
+
# should_route :put, '/posts/1', :action => :update, :id => "1"
|
241
|
+
# should_route :delete, '/posts/1', :action => :destroy, :id => 1
|
242
|
+
# should_route :get, '/posts/new', :action => :new
|
243
|
+
#
|
244
|
+
def should_route(method, path, options)
|
245
|
+
unless options[:controller]
|
246
|
+
options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
|
247
|
+
end
|
248
|
+
options[:controller] = options[:controller].to_s
|
249
|
+
options[:action] = options[:action].to_s
|
250
|
+
|
251
|
+
populated_path = path.dup
|
252
|
+
options.each do |key, value|
|
253
|
+
options[key] = value.to_param if value.respond_to? :to_param
|
254
|
+
populated_path.gsub!(key.inspect, value.to_s)
|
255
|
+
end
|
256
|
+
|
257
|
+
should_name = "route #{method.to_s.upcase} #{populated_path} to/from #{options.inspect}"
|
258
|
+
|
259
|
+
should should_name do
|
260
|
+
assert_routing({:method => method, :path => populated_path}, options)
|
261
|
+
end
|
262
|
+
end
|
168
263
|
end
|
169
264
|
end
|
170
265
|
end
|
data/lib/shoulda/controller.rb
CHANGED
@@ -67,6 +67,31 @@ class PostsControllerTest < Test::Unit::TestCase
|
|
67
67
|
should_assign_to :user, :posts
|
68
68
|
should_not_assign_to :foo, :bar
|
69
69
|
end
|
70
|
+
|
71
|
+
context "viewing posts for a user with rss format" do
|
72
|
+
setup do
|
73
|
+
get :index, :user_id => users(:first), :format => 'rss'
|
74
|
+
@user = users(:first)
|
75
|
+
end
|
76
|
+
should_respond_with :success
|
77
|
+
should_respond_with_content_type 'application/rss+xml'
|
78
|
+
should_respond_with_content_type :rss
|
79
|
+
should_respond_with_content_type /rss/
|
80
|
+
should_return_from_session :special, "'$2 off your next purchase'"
|
81
|
+
should_return_from_session :special_user_id, '@user.id'
|
82
|
+
should_assign_to :user, :posts
|
83
|
+
should_not_assign_to :foo, :bar
|
84
|
+
end
|
85
|
+
|
86
|
+
context "viewing a post on GET to #show" do
|
87
|
+
setup { get :show, :user_id => users(:first), :id => posts(:first) }
|
88
|
+
should_render_with_layout 'wide'
|
89
|
+
end
|
90
|
+
|
91
|
+
context "on GET to #new" do
|
92
|
+
setup { get :new, :user_id => users(:first) }
|
93
|
+
should_render_without_layout
|
94
|
+
end
|
70
95
|
end
|
71
96
|
|
72
97
|
end
|
@@ -8,6 +8,12 @@ class PostsController < ApplicationController
|
|
8
8
|
respond_to do |format|
|
9
9
|
format.html # index.rhtml
|
10
10
|
format.xml { render :xml => @posts.to_xml }
|
11
|
+
format.rss do
|
12
|
+
headers['Content-Type'] = 'application/rss+xml'
|
13
|
+
session[:special] = '$2 off your next purchase'
|
14
|
+
session[:special_user_id] = @user.id
|
15
|
+
head :ok
|
16
|
+
end
|
11
17
|
end
|
12
18
|
end
|
13
19
|
|
@@ -15,13 +21,14 @@ class PostsController < ApplicationController
|
|
15
21
|
@post = @user.posts.find(params[:id])
|
16
22
|
|
17
23
|
respond_to do |format|
|
18
|
-
format.html
|
24
|
+
format.html { render :layout => 'wide' }
|
19
25
|
format.xml { render :xml => @post.to_xml }
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
29
|
def new
|
24
30
|
@post = @user.posts.build
|
31
|
+
render :layout => false
|
25
32
|
end
|
26
33
|
|
27
34
|
def edit
|
@@ -5,7 +5,7 @@ class User < ActiveRecord::Base
|
|
5
5
|
has_many :friendships
|
6
6
|
has_many :friends, :through => :friendships
|
7
7
|
|
8
|
-
has_one :address, :as => :addressable
|
8
|
+
has_one :address, :as => :addressable, :dependent => :destroy
|
9
9
|
|
10
10
|
named_scope :old, :conditions => "age > 50"
|
11
11
|
named_scope :eighteen, :conditions => { :age => 18 }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Specifies gem version of Rails to use when vendor/rails is not present
|
2
2
|
old_verbose, $VERBOSE = $VERBOSE, nil
|
3
|
-
RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
|
3
|
+
RAILS_GEM_VERSION = '>= 2.1.0' unless defined? RAILS_GEM_VERSION
|
4
4
|
$VERBOSE = old_verbose
|
5
5
|
|
6
6
|
require File.join(File.dirname(__FILE__), 'boot')
|
@@ -10,5 +10,5 @@ Rails::Initializer.run do |config|
|
|
10
10
|
config.cache_classes = false
|
11
11
|
config.whiny_nils = true
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
# Dependencies.log_activity = true
|
data/test/test_helper.rb
CHANGED
@@ -5,15 +5,15 @@ ENV['RAILS_ENV'] = 'sqlite3'
|
|
5
5
|
rails_root = File.dirname(__FILE__) + '/rails_root'
|
6
6
|
|
7
7
|
require "#{rails_root}/config/environment.rb"
|
8
|
-
|
8
|
+
|
9
9
|
# Load the testing framework
|
10
10
|
require 'test_help'
|
11
11
|
silence_warnings { RAILS_ENV = ENV['RAILS_ENV'] }
|
12
|
-
|
12
|
+
|
13
13
|
# Run the migrations
|
14
14
|
ActiveRecord::Migration.verbose = false
|
15
15
|
ActiveRecord::Migrator.migrate("#{RAILS_ROOT}/db/migrate")
|
16
|
-
|
16
|
+
|
17
17
|
# Setup the fixtures path
|
18
18
|
Test::Unit::TestCase.fixture_path = File.join(File.dirname(__FILE__), "fixtures")
|
19
19
|
|
@@ -25,7 +25,9 @@ class Test::Unit::TestCase #:nodoc:
|
|
25
25
|
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
self.use_transactional_fixtures = false
|
30
30
|
self.use_instantiated_fixtures = false
|
31
31
|
end
|
32
|
+
|
33
|
+
require 'test/fail_macros'
|
data/test/unit/tag_test.rb
CHANGED
data/test/unit/user_test.rb
CHANGED
@@ -10,6 +10,7 @@ class UserTest < Test::Unit::TestCase
|
|
10
10
|
should_have_many :friends
|
11
11
|
|
12
12
|
should_have_one :address
|
13
|
+
should_have_one :address, :dependent => :destroy
|
13
14
|
|
14
15
|
should_have_indices :email, :name, [:email, :name]
|
15
16
|
should_have_index :age
|
@@ -44,4 +45,8 @@ class UserTest < Test::Unit::TestCase
|
|
44
45
|
should_only_allow_numeric_values_for :ssn
|
45
46
|
|
46
47
|
should_have_readonly_attributes :name
|
48
|
+
|
49
|
+
should_fail do
|
50
|
+
should_protect_attributes :name, :age
|
51
|
+
end
|
47
52
|
end
|
metadata
CHANGED
@@ -1,47 +0,0 @@
|
|
1
|
-
module ThoughtBot
|
2
|
-
module Shoulda
|
3
|
-
module Controller
|
4
|
-
module Routing
|
5
|
-
module Macros
|
6
|
-
# Macro that creates a routing test. It tries to use the given HTTP
|
7
|
-
# +method+ on the given +path+, and asserts that it routes to the
|
8
|
-
# given +options+.
|
9
|
-
#
|
10
|
-
# If you don't specify a :controller, it will try to guess the controller
|
11
|
-
# based on the current test.
|
12
|
-
#
|
13
|
-
# +to_param+ is called on the +options+ given.
|
14
|
-
#
|
15
|
-
# Examples:
|
16
|
-
#
|
17
|
-
# should_route :get, '/posts', :action => :index
|
18
|
-
# should_route :post, '/posts', :controller => :posts, :action => :create
|
19
|
-
# should_route :get, '/posts/1', :action => :show, :id => 1
|
20
|
-
# should_route :put, '/posts/1', :action => :update, :id => "1"
|
21
|
-
# should_route :delete, '/posts/1', :action => :destroy, :id => 1
|
22
|
-
# should_route :get, '/posts/new', :action => :new
|
23
|
-
#
|
24
|
-
def should_route(method, path, options)
|
25
|
-
unless options[:controller]
|
26
|
-
options[:controller] = self.name.gsub(/ControllerTest$/, '').tableize
|
27
|
-
end
|
28
|
-
options[:controller] = options[:controller].to_s
|
29
|
-
options[:action] = options[:action].to_s
|
30
|
-
|
31
|
-
populated_path = path.dup
|
32
|
-
options.each do |key, value|
|
33
|
-
options[key] = value.to_param if value.respond_to? :to_param
|
34
|
-
populated_path.gsub!(key.inspect, value.to_s)
|
35
|
-
end
|
36
|
-
|
37
|
-
should_name = "route #{method.to_s.upcase} #{populated_path} to/from #{options.inspect}"
|
38
|
-
|
39
|
-
should should_name do
|
40
|
-
assert_routing({:method => method, :path => populated_path}, options)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|