rdavila_friendly_id 2.2.6

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.
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class CustomSlugNormalizerTest < Test::Unit::TestCase
4
+
5
+ context "A slugged model using a custom slug generator" do
6
+
7
+ setup do
8
+ Person.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
9
+ end
10
+
11
+ teardown do
12
+ Person.delete_all
13
+ Slug.delete_all
14
+ end
15
+
16
+ should "invoke the block code" do
17
+ @person = Person.create!(:name => "Joe Schmoe")
18
+ assert_equal "JOE SCHMOE", @person.friendly_id
19
+ end
20
+
21
+ should "respect the max_length option" do
22
+ Person.friendly_id_options = Person.friendly_id_options.merge(:max_length => 3)
23
+ @person = Person.create!(:name => "Joe Schmoe")
24
+ assert_equal "JOE", @person.friendly_id
25
+ end
26
+
27
+ should "respect the reserved option" do
28
+ Person.friendly_id_options = Person.friendly_id_options.merge(:reserved => ["JOE"])
29
+ assert_raises FriendlyId::SlugGenerationError do
30
+ Person.create!(:name => "Joe")
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,99 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class NonSluggedTest < Test::Unit::TestCase
4
+
5
+ context "A non-slugged model with default FriendlyId options" do
6
+
7
+ setup do
8
+ @user = User.create!(:name => "joe")
9
+ end
10
+
11
+ teardown do
12
+ User.delete_all
13
+ end
14
+
15
+ should "have friendly_id options" do
16
+ assert_not_nil User.friendly_id_options
17
+ end
18
+
19
+ should "not have a slug" do
20
+ assert !@user.respond_to?(:slug)
21
+ end
22
+
23
+ should "be findable by its friendly_id" do
24
+ assert User.find(@user.friendly_id)
25
+ end
26
+
27
+ should "be findable by its regular id" do
28
+ assert User.find(@user.id)
29
+ end
30
+
31
+ should "respect finder conditions" do
32
+ assert_raises ActiveRecord::RecordNotFound do
33
+ User.find(@user.friendly_id, :conditions => "1 = 2")
34
+ end
35
+ end
36
+
37
+ should "indicate if it was found by its friendly id" do
38
+ user = User.find(@user.friendly_id)
39
+ assert user.found_using_friendly_id?
40
+ end
41
+
42
+ should "indicate if it was found by its numeric id" do
43
+ user = User.find(@user.id)
44
+ assert user.found_using_numeric_id?
45
+ end
46
+
47
+ should "indicate if it has a better id" do
48
+ user = User.find(@user.id)
49
+ assert user.has_better_id?
50
+ end
51
+
52
+ should "not validate if the friendly_id text is reserved" do
53
+ user = User.new(:name => "new")
54
+ assert !user.valid?
55
+ end
56
+
57
+ should "have always string for a friendly_id" do
58
+ assert_equal String, @user.to_param.class
59
+ end
60
+
61
+ should "return its id if the friendly_id is null" do
62
+ @user.name = nil
63
+ assert_equal @user.id.to_s, @user.to_param
64
+ end
65
+
66
+
67
+ context "when using an array as the find argument" do
68
+
69
+ setup do
70
+ @user2 = User.create(:name => "jane")
71
+ end
72
+
73
+ should "return results" do
74
+ assert_equal 2, User.find([@user.friendly_id, @user2.friendly_id]).size
75
+ end
76
+
77
+ should "not allow mixed friendly and non-friendly ids for the same record" do
78
+ assert_raises ActiveRecord::RecordNotFound do
79
+ User.find([@user.id, @user.friendly_id]).size
80
+ end
81
+ end
82
+
83
+ should "raise an error when all records are not found" do
84
+ assert_raises ActiveRecord::RecordNotFound do
85
+ User.find(['bad', 'bad2'])
86
+ end
87
+ end
88
+
89
+ should "indicate if the results were found using a friendly_id" do
90
+ users = User.find([@user.id, @user2.friendly_id], :order => "name ASC")
91
+ assert users[0].found_using_friendly_id?
92
+ assert users[1].found_using_numeric_id?
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class ScopedModelTest < Test::Unit::TestCase
5
+
6
+ context "A slugged model that uses a scope" do
7
+
8
+ setup do
9
+ @usa = Country.create!(:name => "USA")
10
+ @canada = Country.create!(:name => "Canada")
11
+ @resident = Resident.create!(:name => "John Smith", :country => @usa)
12
+ @resident2 = Resident.create!(:name => "John Smith", :country => @canada)
13
+ end
14
+
15
+ teardown do
16
+ Resident.delete_all
17
+ Country.delete_all
18
+ Slug.delete_all
19
+ end
20
+
21
+ should "should not show the scope in the friendly_id" do
22
+ assert_equal "john-smith", @resident.friendly_id
23
+ assert_equal "john-smith", @resident2.friendly_id
24
+ end
25
+
26
+ should "find all scoped records without scope" do
27
+ assert_equal 2, Resident.find(:all, @resident.friendly_id).size
28
+ end
29
+
30
+ should "find a single scoped records with a scope as a string" do
31
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country.to_param)
32
+ end
33
+
34
+ should "find a single scoped records with a scope" do
35
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country)
36
+ end
37
+
38
+ should "raise an error when finding a single scoped record with no scope" do
39
+ assert_raises ActiveRecord::RecordNotFound do
40
+ Resident.find(@resident.friendly_id)
41
+ end
42
+ end
43
+
44
+ should "append scope error info when missing scope causes a find to fail" do
45
+ begin
46
+ Resident.find(@resident.friendly_id)
47
+ fail "The find should not have succeeded"
48
+ rescue ActiveRecord::RecordNotFound => e
49
+ assert_match /expected scope/, e.message
50
+ end
51
+ end
52
+
53
+ should "append scope error info when the scope value causes a find to fail" do
54
+ begin
55
+ Resident.find(@resident.friendly_id, :scope => "badscope")
56
+ fail "The find should not have succeeded"
57
+ rescue ActiveRecord::RecordNotFound => e
58
+ assert_match /scope=badscope/, e.message
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
data/test/slug_test.rb ADDED
@@ -0,0 +1,105 @@
1
+ # encoding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class SlugTest < Test::Unit::TestCase
5
+
6
+ context "a slug" do
7
+
8
+ teardown do
9
+ Slug.delete_all
10
+ Post.delete_all
11
+ end
12
+
13
+ should "indicate if it is the most recent slug" do
14
+ post = Post.create!(:name => "test title")
15
+ post.name = "a new title"
16
+ post.save!
17
+ assert post.slugs.last.is_most_recent?
18
+ assert !post.slugs.first.is_most_recent?
19
+ end
20
+
21
+ end
22
+
23
+ context "the Slug class" do
24
+
25
+ should "parse the slug name and sequence" do
26
+ assert_equal ["test", "2"], Slug::parse("test--2")
27
+ end
28
+
29
+ should "parse with a default sequence of 1" do
30
+ assert_equal ["test", "1"], Slug::parse("test")
31
+ end
32
+
33
+ should "should strip diacritics" do
34
+ assert_equal "acai", Slug::strip_diacritics("açaí")
35
+ end
36
+
37
+ should "strip diacritics correctly " do
38
+ input = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
39
+ output = Slug::strip_diacritics(input).split(//)
40
+ expected = "AAAAAAAECEEEIIIIDNOOOOOOUUUUYThssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
41
+ output.each_index do |i|
42
+ assert_equal expected[i], output[i]
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ context "the Slug class's to_friendly_id method" do
49
+
50
+ should "include the sequence if the sequence is greater than 1" do
51
+ slug = Slug.new(:name => "test", :sequence => 2)
52
+ assert_equal "test--2", slug.to_friendly_id
53
+ end
54
+
55
+ should "not include the sequence if the sequence is 1" do
56
+ slug = Slug.new(:name => "test", :sequence => 1)
57
+ assert_equal "test", slug.to_friendly_id
58
+ end
59
+
60
+ end
61
+
62
+ context "the Slug class's normalize method" do
63
+
64
+ should "should lowercase strings" do
65
+ assert_match /abc/, Slug::normalize("ABC")
66
+ end
67
+
68
+ should "should replace whitespace with dashes" do
69
+ assert_match /a-b/, Slug::normalize("a b")
70
+ end
71
+
72
+ should "should replace 2spaces with 1dash" do
73
+ assert_match /a-b/, Slug::normalize("a b")
74
+ end
75
+
76
+ should "should remove punctuation" do
77
+ assert_match /abc/, Slug::normalize('abc!@#$%^&*•¶§∞¢££¡¿()><?"":;][]\.,/')
78
+ end
79
+
80
+ should "should strip trailing space" do
81
+ assert_match /ab/, Slug::normalize("ab ")
82
+ end
83
+
84
+ should "should strip leading space" do
85
+ assert_match /ab/, Slug::normalize(" ab")
86
+ end
87
+
88
+ should "should strip trailing slashes" do
89
+ assert_match /ab/, Slug::normalize("ab-")
90
+ end
91
+
92
+ should "should strip leading slashes" do
93
+ assert_match /ab/, Slug::normalize("-ab")
94
+ end
95
+
96
+ should "should not modify valid name strings" do
97
+ assert_match /a-b-c-d/, Slug::normalize("a-b-c-d")
98
+ end
99
+
100
+ should "work with non roman chars" do
101
+ assert_equal "検-索", Slug::normalize("検 索")
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,348 @@
1
+ # encoding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ class SluggedModelTest < Test::Unit::TestCase
5
+
6
+ context "A slugged model with default FriendlyId options" do
7
+
8
+ setup do
9
+ Post.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
10
+ @post = Post.new :name => "Test post", :published => true
11
+ @post.save!
12
+ end
13
+
14
+ teardown do
15
+ Post.delete_all
16
+ Person.delete_all
17
+ Place.delete_all
18
+ Slug.delete_all
19
+ end
20
+
21
+ should "have friendly_id options" do
22
+ assert_not_nil Post.friendly_id_options
23
+ end
24
+
25
+ should "have a slug" do
26
+ assert_not_nil @post.slug
27
+ end
28
+
29
+ should "be findable by its friendly_id" do
30
+ assert Post.find(@post.friendly_id)
31
+ end
32
+
33
+ should "be findable by its regular id" do
34
+ assert Post.find(@post.id)
35
+ end
36
+
37
+ should "be findable by its regular id as a string" do
38
+ assert Post.find(@post.id.to_s)
39
+ end
40
+
41
+ should "be findable by its instance" do
42
+ assert Post.find(@post)
43
+ end
44
+
45
+ should "not be findable by its id if looking for something else" do
46
+ assert_raises ActiveRecord::RecordNotFound do
47
+ Post.find("#{@post.id}-i-dont-exists")
48
+ end
49
+ end
50
+
51
+ should "generate slug text" do
52
+ post = Post.new :name => "Test post"
53
+ assert_not_nil post.slug_text
54
+ end
55
+
56
+ should "respect finder conditions" do
57
+ assert_raises ActiveRecord::RecordNotFound do
58
+ Post.find(@post.friendly_id, :conditions => "1 = 2")
59
+ end
60
+ end
61
+
62
+ should "raise an error if the friendly_id text is reserved" do
63
+ assert_raises(FriendlyId::SlugGenerationError) do
64
+ Post.create!(:name => "new")
65
+ end
66
+ end
67
+
68
+ should "raise an error if the friendly_id text is an empty string" do
69
+ assert_raises(FriendlyId::SlugGenerationError) do
70
+ Post.create(:name => "")
71
+ end
72
+ end
73
+
74
+ should "raise an error if the friendly_id text is nil" do
75
+ assert_raises(FriendlyId::SlugGenerationError) do
76
+ Post.create(:name => nil)
77
+ end
78
+ end
79
+
80
+ should "raise an error if the normalized friendly id becomes blank" do
81
+ assert_raises(FriendlyId::SlugGenerationError) do
82
+ post = Post.create!(:name => "-.-")
83
+ end
84
+ end
85
+
86
+ should "not make a new slug unless the friendly_id method value has changed" do
87
+ @post.published = !@post.published
88
+ @post.save!
89
+ assert_equal 1, @post.slugs.size
90
+ end
91
+
92
+ should "make a new slug if the friendly_id method value has changed" do
93
+ @post.name = "Changed title"
94
+ @post.save!
95
+ assert_equal 2, @post.slugs.size
96
+ end
97
+
98
+ should "have a slug sequence of 1 by default" do
99
+ assert_equal 1, @post.slug.sequence
100
+ end
101
+
102
+ should "increment sequence for duplicate slug names" do
103
+ @post2 = Post.create! :name => @post.name
104
+ assert_equal 2, @post2.slug.sequence
105
+ end
106
+
107
+ should "have a friendly_id that terminates with -- and the slug sequence if the sequence is greater than 1" do
108
+ @post2 = Post.create! :name => @post.name
109
+ assert_match(/--2\z/, @post2.friendly_id)
110
+ end
111
+
112
+ should "allow datetime columns to be used as slugs" do
113
+ assert Event.create(:name => "Test", :event_date => DateTime.now)
114
+ end
115
+
116
+ should "not strip diacritics" do
117
+ post = Post.new(:name => "¡Feliz año!")
118
+ assert_match(/#{'ñ'}/, post.slug_text)
119
+ end
120
+
121
+ should "not convert to ASCII" do
122
+ post = Post.new(:name => "katakana: ゲコゴサザシジ")
123
+ assert_equal "katakana-ゲコゴサザシジ", post.slug_text
124
+ end
125
+
126
+ should "allow the same friendly_id across models" do
127
+ district = District.create!(:name => @post.name)
128
+ assert_equal district.friendly_id, @post.friendly_id
129
+ end
130
+
131
+ should "truncate slug text longer than the max length" do
132
+ post = Post.new(:name => "a" * (Post.friendly_id_options[:max_length] + 1))
133
+ assert_equal post.slug_text.length, Post.friendly_id_options[:max_length]
134
+ end
135
+
136
+ should "truncate slug in 'right way' when slug is unicode" do
137
+ post = Post.new(:name => "ё" * 100 + 'ю' *(Post.friendly_id_options[:max_length] - 100 + 1))
138
+ assert_equal post.slug_text.mb_chars[-1], 'ю'
139
+ end
140
+
141
+ should "be able to reuse an old friendly_id without incrementing the sequence" do
142
+ old_title = @post.name
143
+ old_friendly_id = @post.friendly_id
144
+ @post.name = "A changed title"
145
+ @post.save!
146
+ @post.name = old_title
147
+ @post.save!
148
+ assert_equal old_friendly_id, @post.friendly_id
149
+ end
150
+
151
+ should "allow eager loading of slugs" do
152
+ assert_nothing_raised do
153
+ Post.find(@post.friendly_id, :include => :slugs)
154
+ end
155
+ end
156
+
157
+ # This emulates a fairly common issue where id's generated by fixtures are very high.
158
+ should "continue to admit very large ids" do
159
+ Person.connection.execute("INSERT INTO people (id, name) VALUES (2147483647, 'Joe Schmoe')")
160
+ assert Person.find(2147483647)
161
+ end
162
+
163
+ context "and configured to strip diacritics" do
164
+ setup do
165
+ Post.friendly_id_options = Post.friendly_id_options.merge(:strip_diacritics => true)
166
+ end
167
+
168
+ should "strip diacritics from Roman alphabet based characters" do
169
+ post = Post.new(:name => "¡Feliz año!")
170
+ assert_no_match(/#{'ñ'}/, post.slug_text)
171
+ end
172
+
173
+ should "raise an error if the friendly_id text is an empty string" do
174
+ assert_raises(FriendlyId::SlugGenerationError) do
175
+ Post.create(:name => "")
176
+ end
177
+ end
178
+
179
+ should "raise an error if the friendly_id text is nil" do
180
+ assert_raises(FriendlyId::SlugGenerationError) do
181
+ Post.create(:name => nil)
182
+ end
183
+ end
184
+
185
+ end
186
+
187
+ context "and configured to convert to ASCII" do
188
+ setup do
189
+ Post.friendly_id_options = Post.friendly_id_options.merge(:strip_non_ascii => true)
190
+ end
191
+
192
+ should "strip non-ascii characters" do
193
+ post = Post.new(:name => "katakana: ゲコゴサザシジ")
194
+ assert_equal "katakana", post.slug_text
195
+ end
196
+ end
197
+
198
+ context "that uses a custom table name" do
199
+ should "support normal CRUD operations" do
200
+ assert thing = Place.create!(:name => "a name")
201
+ thing.name = "a new name"
202
+ assert thing.save!
203
+ assert thing.destroy
204
+ end
205
+ end
206
+
207
+ context "that doesn't have a slug" do
208
+
209
+ setup do
210
+ @post.slug.destroy
211
+ @post = Post.find(@post.id)
212
+ end
213
+
214
+ should "have a to_param method that returns the id cast to a string" do
215
+ assert_equal @post.id.to_s, @post.to_param
216
+ end
217
+
218
+ end
219
+
220
+ context "when found using its friendly_id" do
221
+ setup do
222
+ @post = Post.find(@post.friendly_id)
223
+ end
224
+
225
+ should "indicate that it was found using the friendly_id" do
226
+ assert @post.found_using_friendly_id?
227
+ end
228
+
229
+ should "not indicate that it has a better id" do
230
+ assert !@post.has_better_id?
231
+ end
232
+
233
+ should "not indicate that it was found using its numeric id" do
234
+ assert !@post.found_using_numeric_id?
235
+ end
236
+
237
+ should "have a finder slug" do
238
+ assert_not_nil @post.finder_slug
239
+ end
240
+
241
+ end
242
+
243
+ context "when found using its regular id" do
244
+ setup do
245
+ @post = Post.find(@post.id)
246
+ end
247
+
248
+ should "indicate that it was not found using the friendly id" do
249
+ assert !@post.found_using_friendly_id?
250
+ end
251
+
252
+ should "indicate that it has a better id" do
253
+ assert @post.has_better_id?
254
+ end
255
+
256
+ should "indicate that it was found using its numeric id" do
257
+ assert @post.found_using_numeric_id?
258
+ end
259
+
260
+ should "not have a finder slug" do
261
+ assert_nil @post.finder_slug
262
+ end
263
+
264
+ end
265
+
266
+ context "when found using an outdated friendly id" do
267
+ setup do
268
+ old_id = @post.friendly_id
269
+ @post.name = "Title changed"
270
+ @post.save!
271
+ @post = Post.find(old_id)
272
+ end
273
+
274
+ should "indicate that it was found using a friendly_id" do
275
+ assert @post.found_using_friendly_id?
276
+ end
277
+
278
+ should "indicate that it has a better id" do
279
+ assert @post.has_better_id?
280
+ end
281
+
282
+ should "not indicate that it was found using its numeric id" do
283
+ assert !@post.found_using_numeric_id?
284
+ end
285
+
286
+ should "should have a finder slug different from its default slug" do
287
+ assert_not_equal @post.slug, @post.finder_slug
288
+ end
289
+
290
+ end
291
+
292
+ context "when table does not exist" do
293
+ should "not raise an error when doing friendly_id setup" do
294
+ assert_nothing_raised do
295
+ Question.has_friendly_id :title, :use_slug => true
296
+ end
297
+ end
298
+ end
299
+
300
+ context "when using an array as the find argument" do
301
+
302
+ setup do
303
+ @post2 = Post.create!(:name => "another post", :published => true)
304
+ end
305
+
306
+ should "return results when passed an array of non-friendly ids" do
307
+ assert_equal 2, Post.find([@post.id, @post2.id]).size
308
+ end
309
+
310
+ should "return results when passed an array of friendly ids" do
311
+ assert_equal 2, Post.find([@post.friendly_id, @post2.friendly_id]).size
312
+ end
313
+
314
+ should "return results when searching using a named scope" do
315
+ assert_equal 2, Post.published.find([@post.id, @post2.id]).size
316
+ end
317
+
318
+ should "return results when passed a mixed array of friendly and non-friendly ids" do
319
+ assert_equal 2, Post.find([@post.friendly_id, @post2.id]).size
320
+ end
321
+
322
+ should "return results when passed an array of non-friendly ids, of which one represents a record with multiple slugs" do
323
+ @post2.update_attributes(:name => 'another post [updated]')
324
+ assert_equal 2, Post.find([@post.id, @post2.id]).size
325
+ end
326
+
327
+ should "indicate that the results were found using a friendly_id" do
328
+ @posts = Post.find [@post.friendly_id, @post2.friendly_id]
329
+ @posts.each { |p| assert p.found_using_friendly_id? }
330
+ end
331
+
332
+ should "raise an error when all records are not found" do
333
+ assert_raises(ActiveRecord::RecordNotFound) do
334
+ Post.find([@post.friendly_id, 'non-existant-slug-record'])
335
+ end
336
+ end
337
+
338
+ should "allow eager loading of slugs" do
339
+ assert_nothing_raised do
340
+ Post.find([@post.friendly_id, @post2.friendly_id], :include => :slugs)
341
+ end
342
+ end
343
+
344
+ end
345
+
346
+ end
347
+
348
+ end