forked from norman/friendly_id
/
slugged_model_test.rb
342 lines (267 loc) · 10.1 KB
/
slugged_model_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# encoding: utf-8
require File.dirname(__FILE__) + '/test_helper'
class SluggedModelTest < Test::Unit::TestCase
context "A slugged model with default FriendlyId options" do
setup do
Post.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :title, :use_slug => true)
@post = Post.new :title => "Test post", :content => "Test content", :published => true
@post.save!
end
teardown do
Post.delete_all
Person.delete_all
Slug.delete_all
Thing.delete_all
LegacyThing.delete_all
end
should "have friendly_id options" do
assert_not_nil Post.friendly_id_options
end
should "have a slug" do
assert_not_nil @post.slug
end
should "be findable by its friendly_id" do
assert Post.find(@post.friendly_id)
end
should "be findable by its regular id" do
assert Post.find(@post.id)
end
should "be findable by its regular id as a string" do
assert Post.find(@post.id.to_s)
end
should "be findable by its instance" do
assert Post.find(@post)
end
should "not be findable by its id if looking for something else" do
assert_raises ActiveRecord::RecordNotFound do
Post.find("#{@post.id}-i-dont-exists")
end
end
should "generate slug text" do
post = Post.new :title => "Test post", :content => "Test content"
assert_not_nil post.slug_text
end
should "respect finder conditions" do
assert_raises ActiveRecord::RecordNotFound do
Post.find(@post.friendly_id, :conditions => "1 = 2")
end
end
should "raise an error if the friendly_id text is reserved" do
assert_raises(FriendlyId::SlugGenerationError) do
Post.create!(:title => "new")
end
end
should "raise an error if the friendly_id text is an empty string" do
assert_raises(FriendlyId::SlugGenerationError) do
Post.create(:title => "")
end
end
should "raise an error if the friendly_id text is nil" do
assert_raises(FriendlyId::SlugGenerationError) do
Post.create(:title => nil)
end
end
should "raise an error if the normalized friendly id becomes blank" do
assert_raises(FriendlyId::SlugGenerationError) do
post = Post.create!(:title => "-.-")
end
end
should "not make a new slug unless the friendly_id method value has changed" do
@post.content = "Changed content"
@post.save!
assert_equal 1, @post.slugs.size
end
should "make a new slug if the friendly_id method value has changed" do
@post.title = "Changed title"
@post.save!
assert_equal 2, @post.slugs.size
end
should "have a slug sequence of 1 by default" do
assert_equal 1, @post.slug.sequence
end
should "increment sequence for duplicate slug names" do
@post2 = Post.create! :title => @post.title, :content => "Test content for post2"
assert_equal 2, @post2.slug.sequence
end
should "have a friendly_id that terminates with -- and the slug sequence if the sequence is greater than 1" do
@post2 = Post.create! :title => @post.title, :content => "Test content for post2"
assert_match(/--2\z/, @post2.friendly_id)
end
should "allow datetime columns to be used as slugs" do
assert Event.create(:name => "Test", :event_date => DateTime.now)
end
should "not strip diacritics" do
post = Post.new(:title => "¡Feliz año!")
assert_match(/#{'ñ'}/, post.slug_text)
end
should "not convert to ASCII" do
post = Post.new(:title => "katakana: ゲコゴサザシジ")
assert_equal "katakana-ゲコゴサザシジ", post.slug_text
end
should "allow the same friendly_id across models" do
person = Person.create!(:name => @post.title)
assert_equal person.friendly_id, @post.friendly_id
end
should "truncate slug text longer than the max length" do
post = Post.new(:title => "a" * (Post.friendly_id_options[:max_length] + 1))
assert_equal post.slug_text.length, Post.friendly_id_options[:max_length]
end
should "truncate slug in 'right way' when slug is unicode" do
post = Post.new(:title => "ё" * 100 + 'ю' *(Post.friendly_id_options[:max_length] - 100 + 1))
assert_equal post.slug_text.mb_chars[-1], 'ю'
end
should "be able to reuse an old friendly_id without incrementing the sequence" do
old_title = @post.title
old_friendly_id = @post.friendly_id
@post.title = "A changed title"
@post.save!
@post.title = old_title
@post.save!
assert_equal old_friendly_id, @post.friendly_id
end
should "allow eager loading of slugs" do
assert_nothing_raised do
Post.find(@post.friendly_id, :include => :slugs)
end
end
# This emulates a fairly common issue where id's generated by fixtures are very high.
should "continue to admit very large ids" do
Thing.connection.execute("INSERT INTO things (id, name) VALUES (2147483647, 'big')")
assert Thing.find(2147483647)
end
context "and configured to strip diacritics" do
setup do
Post.friendly_id_options = Post.friendly_id_options.merge(:strip_diacritics => true)
end
should "strip diacritics from Roman alphabet based characters" do
post = Post.new(:title => "¡Feliz año!")
assert_no_match(/#{'ñ'}/, post.slug_text)
end
should "raise an error if the friendly_id text is an empty string" do
assert_raises(FriendlyId::SlugGenerationError) do
Post.create(:title => "")
end
end
should "raise an error if the friendly_id text is nil" do
assert_raises(FriendlyId::SlugGenerationError) do
Post.create(:title => nil)
end
end
end
context "and configured to convert to ASCII" do
setup do
Post.friendly_id_options = Post.friendly_id_options.merge(:strip_non_ascii => true)
end
should "strip non-ascii characters" do
post = Post.new(:title => "katakana: ゲコゴサザシジ")
assert_equal "katakana", post.slug_text
end
end
context "that uses a custom table name" do
should "support normal CRUD operations" do
assert thing = LegacyThing.create!(:name => "a name")
thing.name = "a new name"
assert thing.save!
assert thing.destroy
end
end
context "that doesn't have a slug" do
setup do
@post.slug.destroy
@post = Post.find(@post.id)
end
should "have a to_param method that returns the id cast to a string" do
assert_equal @post.id.to_s, @post.to_param
end
end
context "when found using its friendly_id" do
setup do
@post = Post.find(@post.friendly_id)
end
should "indicate that it was found using the friendly_id" do
assert @post.found_using_friendly_id?
end
should "not indicate that it has a better id" do
assert !@post.has_better_id?
end
should "not indicate that it was found using its numeric id" do
assert !@post.found_using_numeric_id?
end
should "have a finder slug" do
assert_not_nil @post.finder_slug
end
end
context "when found using its regular id" do
setup do
@post = Post.find(@post.id)
end
should "indicate that it was not found using the friendly id" do
assert !@post.found_using_friendly_id?
end
should "indicate that it has a better id" do
assert @post.has_better_id?
end
should "indicate that it was found using its numeric id" do
assert @post.found_using_numeric_id?
end
should "not have a finder slug" do
assert_nil @post.finder_slug
end
end
context "when found using an outdated friendly id" do
setup do
old_id = @post.friendly_id
@post.title = "Title changed"
@post.save!
@post = Post.find(old_id)
end
should "indicate that it was found using a friendly_id" do
assert @post.found_using_friendly_id?
end
should "indicate that it has a better id" do
assert @post.has_better_id?
end
should "not indicate that it was found using its numeric id" do
assert !@post.found_using_numeric_id?
end
should "should have a finder slug different from its default slug" do
assert_not_equal @post.slug, @post.finder_slug
end
end
context "when using an array as the find argument" do
setup do
@post2 = Post.create!(:title => "another post", :content => "more content", :published => true)
end
should "return results when passed an array of non-friendly ids" do
assert_equal 2, Post.find([@post.id, @post2.id]).size
end
should "return results when passed an array of friendly ids" do
assert_equal 2, Post.find([@post.friendly_id, @post2.friendly_id]).size
end
should "return results when searching using a named scope" do
assert_equal 2, Post.published.find([@post.id, @post2.id]).size
end
should "return results when passed a mixed array of friendly and non-friendly ids" do
assert_equal 2, Post.find([@post.friendly_id, @post2.id]).size
end
should "return results when passed an array of non-friendly ids, of which one represents a record with multiple slugs" do
@post2.update_attributes(:title => 'another post [updated]')
assert_equal 2, Post.find([@post.id, @post2.id]).size
end
should "indicate that the results were found using a friendly_id" do
@posts = Post.find [@post.friendly_id, @post2.friendly_id]
@posts.each { |p| assert p.found_using_friendly_id? }
end
should "raise an error when all records are not found" do
assert_raises(ActiveRecord::RecordNotFound) do
Post.find([@post.friendly_id, 'non-existant-slug-record'])
end
end
should "allow eager loading of slugs" do
assert_nothing_raised do
Post.find([@post.friendly_id, @post2.friendly_id], :include => :slugs)
end
end
end
end
end