friendly_id_datamapper 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ class CachedSlugTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Generic
10
+ include FriendlyId::Test::Slugged
11
+ include FriendlyId::Test::DataMapperAdapter::Slugged
12
+ include FriendlyId::Test::DataMapperAdapter::Core
13
+
14
+ def klass
15
+ District
16
+ end
17
+
18
+ def other_class
19
+ Post
20
+ end
21
+
22
+ def cached_slug
23
+ instance.send(cache_column)
24
+ end
25
+
26
+ def cache_column
27
+ klass.friendly_id_config.cache_column
28
+ end
29
+
30
+ test "should have a cached_slug" do
31
+ assert_equal cached_slug, instance.slug.to_friendly_id
32
+ end
33
+
34
+ test "should protect the cached slug value" do
35
+ old_value = cached_slug
36
+ instance.update(cache_column => "Madrid")
37
+ assert_equal old_value, cached_slug
38
+ end
39
+
40
+ test "should update the cached slug when updating the slug" do
41
+ instance.update(:name => "new name")
42
+ assert_equal instance.slug.to_friendly_id, cached_slug
43
+ end
44
+
45
+ test "should not update the cached slug column if it has not changed" do
46
+ instance.note = "a note"
47
+ instance.expects("#{cache_column}=".to_sym).never
48
+ instance.save!
49
+ end
50
+
51
+ test "should cache the incremented sequence for duplicate slug names" do
52
+ instance_2 = klass.create(:name => instance.name)
53
+ assert_match(/2\z/, instance_2.send(cache_column))
54
+ end
55
+
56
+ test "#friendly_id should check the cached value by default" do
57
+ instance.expects(:slug).never
58
+ instance.friendly_id
59
+ end
60
+
61
+ test "#friendly_id should skip the cache if invoked with true" do
62
+ instance.expects(:slug)
63
+ instance.friendly_id(true)
64
+ end
65
+
66
+ test "should not fire callbacks when updating slug cache" do
67
+ instance.expects(:say_hello).once
68
+ instance.update(:name => "new name")
69
+ assert_equal instance.slug.to_friendly_id, cached_slug
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
data/test/core.rb ADDED
@@ -0,0 +1,72 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module DataMapper
4
+ module Model
5
+ def destroy_all!; all.destroy!; end
6
+ end
7
+ end
8
+
9
+ module FriendlyId
10
+ module Test
11
+ module DataMapperAdapter
12
+
13
+ # Core tests for any datamapper model using FriendlyId.
14
+ module Core
15
+
16
+ def teardown
17
+ klass.all.destroy!
18
+ other_class.all.destroy!
19
+ Slug.all.destroy!
20
+ end
21
+
22
+ def find_method
23
+ :get
24
+ end
25
+
26
+ def create_method
27
+ :create
28
+ end
29
+
30
+ def delete_all_method
31
+ :destroy_all!
32
+ end
33
+
34
+ def save_method
35
+ :save
36
+ end
37
+
38
+ def unfriendly_class
39
+ Unfriendly
40
+ end
41
+
42
+ def validation_exceptions
43
+ nil # DataMapper does not raise Validation Errors
44
+ end
45
+
46
+ test "should return their friendly_id for #to_param" do
47
+ assert_match(instance.friendly_id, instance.to_param)
48
+ end
49
+
50
+ # This emulates a fairly common issue where id's generated by fixtures are very high.
51
+ test "should continue to admit very large ids" do
52
+ klass.repository(:default).adapter.select("INSERT INTO #{klass.storage_name} (id, name) VALUES (2047483647, 'An instance')")
53
+ assert_nothing_raised do
54
+ klass.get(2047483647)
55
+ end
56
+ end
57
+
58
+ test "should not change failure behavior for models not using friendly_id" do
59
+ assert_raise DataMapper::ObjectNotFoundError do
60
+ unfriendly_class.get!(-1)
61
+ end
62
+ end
63
+
64
+ test "failing finds with unfriendly_id should raise errors normally" do
65
+ assert_raise DataMapper::ObjectNotFoundError do
66
+ klass.get!(0)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ class CustomNormalizerTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::DataMapperAdapter::Core
10
+ include FriendlyId::Test::DataMapperAdapter::Slugged
11
+ include FriendlyId::Test::CustomNormalizer
12
+
13
+ def klass
14
+ Person
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ class CustomTableNameTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Generic
10
+ include FriendlyId::Test::Slugged
11
+ include FriendlyId::Test::DataMapperAdapter::Slugged
12
+ include FriendlyId::Test::DataMapperAdapter::Core
13
+
14
+ def klass
15
+ Place
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,120 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+
6
+ class ScopedModelTest < ::Test::Unit::TestCase
7
+
8
+ include FriendlyId::Test::Generic
9
+ include FriendlyId::Test::Slugged
10
+ include FriendlyId::Test::DataMapperAdapter::Slugged
11
+ include FriendlyId::Test::DataMapperAdapter::Core
12
+
13
+ def setup
14
+ @user = User.create(:name => "john")
15
+ @house = House.create(:name => "123 Main", :user => @user)
16
+ @usa = Country.create(:name => "USA")
17
+ @canada = Country.create(:name => "Canada")
18
+ @resident = Resident.create(:name => "John Smith", :country => @usa)
19
+ @resident2 = Resident.create(:name => "John Smith", :country => @canada)
20
+ @owner = Company.create(:name => "Acme Events")
21
+ @site = Site.create(:name => "Downtown Venue", :owner => @owner)
22
+ end
23
+
24
+ def teardown
25
+ Resident.all.destroy!
26
+ Country.all.destroy!
27
+ User.all.destroy!
28
+ House.all.destroy!
29
+ Slug.all.destroy!
30
+ end
31
+
32
+ test "a slugged model should auto-detect that it is being used as a parent scope" do
33
+ assert_equal [Resident], Country.friendly_id_config.child_scopes
34
+ end
35
+
36
+ test "a slugged model should update its child model's scopes when its friendly_id changes" do
37
+ @usa.update(:name => "United States")
38
+ assert_equal "united-states", @usa.to_param
39
+ assert_equal "united-states", @resident.slugs.reload.first.scope
40
+ end
41
+
42
+ test "a non-slugged model should auto-detect that it is being used as a parent scope" do
43
+ assert_equal [House], User.friendly_id_config.child_scopes
44
+ end
45
+
46
+ test "should update the slug when the scope changes" do
47
+ @resident.update :country => Country.create(:name => "Argentina")
48
+ assert_equal "argentina", @resident.slugs.reload.first.scope
49
+ end
50
+
51
+ test "updating only the scope should not append sequence to friendly_id" do
52
+ old_friendly_id = @resident.friendly_id
53
+ @resident.update :country => Country.create(:name => "Argentina")
54
+ assert_equal old_friendly_id, @resident.friendly_id
55
+ end
56
+
57
+ test "updating the scope should increment sequence to avoid conflicts" do
58
+ old_friendly_id = @resident.friendly_id
59
+ @resident.update :country => @canada
60
+ assert_equal "#{old_friendly_id}--2", @resident.friendly_id
61
+ assert_equal "canada", @resident.slugs.reload.first.scope
62
+ end
63
+
64
+ test "a non-slugged model should update its child model's scopes when its friendly_id changes" do
65
+ @user.update(:name => "jack")
66
+ assert_equal "jack", @user.to_param
67
+ assert_equal "jack", @house.slugs.reload.first.scope
68
+ end
69
+
70
+ test "should should not show the scope in the friendly_id" do
71
+ assert_equal "john-smith", @resident.friendly_id
72
+ assert_equal "john-smith", @resident2.friendly_id
73
+ end
74
+
75
+ =begin
76
+ test "should find all scoped records without scope" do
77
+ assert_equal 2, Resident.find(:all, @resident.friendly_id).size
78
+ end
79
+ =end
80
+
81
+ test "should find a single scoped record with a scope as a string" do
82
+ assert Resident.get(@resident.friendly_id, :scope => @resident.country)
83
+ end
84
+
85
+ test "should find a single scoped record with a scope" do
86
+ assert Resident.get(@resident.friendly_id, :scope => @resident.country)
87
+ end
88
+
89
+ test "should raise an error when finding a single scoped record with no scope" do
90
+ assert_raises DataMapper::ObjectNotFoundError do
91
+ Resident.get!(@resident.friendly_id)
92
+ end
93
+ end
94
+
95
+ test "should append scope error info when missing scope causes a find to fail" do
96
+ begin
97
+ Resident.get!(@resident.friendly_id)
98
+ fail "The find should not have succeeded"
99
+ rescue DataMapper::ObjectNotFoundError => e
100
+ assert_match(/scope expected/i, e.message)
101
+ end
102
+ end
103
+
104
+ test "should append scope error info when the scope value causes a find to fail" do
105
+ begin
106
+ Resident.get!(@resident.friendly_id, :scope => "badscope")
107
+ fail "The find should not have succeeded"
108
+ rescue DataMapper::ObjectNotFoundError => e
109
+ assert_match(/scope \"badscope\"/, e.message)
110
+ end
111
+ end
112
+
113
+ test "should update the sluggable field when a polymorphic relationship exists" do
114
+ @site.update(:name => "Uptown Venue")
115
+ assert_equal "Uptown Venue", @site.name
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,76 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ module Simple
8
+
9
+ module SimpleTest
10
+ def klass
11
+ @klass ||= User
12
+ end
13
+
14
+ def instance
15
+ @instance ||= User.create! :name => "hello world"
16
+ end
17
+
18
+ def other_class
19
+ Author
20
+ end
21
+ end
22
+
23
+ class StatusTest < ::Test::Unit::TestCase
24
+
25
+ include SimpleTest
26
+
27
+ def setup
28
+ User.destroy_all!
29
+ end
30
+
31
+ test "should default to not friendly" do
32
+ assert !status.friendly?
33
+ end
34
+
35
+ test "should default to numeric" do
36
+ assert status.numeric?
37
+ end
38
+
39
+ test "should be friendly if name is set" do
40
+ status.name = "name"
41
+ assert status.friendly?
42
+ end
43
+
44
+ test "should be best if it is numeric, but record has no friendly_id" do
45
+ instance.send("#{klass.friendly_id_config.column}=", nil)
46
+ assert status.best?
47
+ end
48
+
49
+ def status
50
+ @status ||= instance.friendly_id_status
51
+ end
52
+
53
+ end
54
+
55
+ class BasicTest < ::Test::Unit::TestCase
56
+ include FriendlyId::Test::Generic
57
+ include FriendlyId::Test::Simple
58
+ include FriendlyId::Test::DataMapperAdapter::Core
59
+ include SimpleTest
60
+
61
+ test "status should be friendly when found using friendly id" do
62
+ record = klass.send(find_method, instance.friendly_id)
63
+ assert record.friendly_id_status.friendly?
64
+ end
65
+
66
+ test "status should not be friendly when found using numeric id" do
67
+ record = klass.send(find_method, instance.id)
68
+ assert !record.friendly_id_status.friendly?
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
data/test/slug_test.rb ADDED
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ module FriendlyId
5
+ module Test
6
+
7
+ class SlugTest < ::Test::Unit::TestCase
8
+
9
+ def teardown
10
+ Slug.all.destroy!
11
+ Post.all.destroy!
12
+ end
13
+
14
+ test "should indicate if it is the most recent slug" do
15
+ post = Post.create(:name => "test title")
16
+ post.name = "a new title"
17
+ post.save
18
+ post.slugs.reload # DM issue: collection must be reloaded for correct ordering by id desc (for #first/#last)
19
+ assert post.slugs.first.current?
20
+ assert !post.slugs.last.current?
21
+ end
22
+
23
+ test "should include the sequence if the sequence is greater than 1" do
24
+ slug = Slug.new(:name => "test", :sluggable => Post.new, :sequence => 2)
25
+ assert_equal "test--2", slug.to_friendly_id
26
+ end
27
+
28
+ test "should not include the sequence if the sequence is 1" do
29
+ slug = Slug.new(:name => "test", :sluggable => Post.new, :sequence => 1)
30
+ assert_equal "test", slug.to_friendly_id
31
+ end
32
+
33
+ end
34
+ end
35
+ end
data/test/slugged.rb ADDED
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ module Slugged
8
+
9
+ def klass
10
+ Post
11
+ end
12
+
13
+ def other_class
14
+ District
15
+ end
16
+
17
+ def instance
18
+ @instance ||= klass.create(:name => 'hello world')
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ class StatusTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Status
10
+ include FriendlyId::Test::SluggedStatus
11
+
12
+ def klass
13
+ Post
14
+ end
15
+
16
+ def instance
17
+ @instance ||= klass.create :name => "hello world"
18
+ end
19
+
20
+ def find_method
21
+ :get
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
data/test/sti_test.rb ADDED
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module DataMapperAdapter
6
+
7
+ class StiTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Generic
10
+ include FriendlyId::Test::Slugged
11
+ include FriendlyId::Test::DataMapperAdapter::Slugged
12
+ include FriendlyId::Test::DataMapperAdapter::Core
13
+
14
+ def klass
15
+ Novel
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,185 @@
1
+ # A model that uses the automagically configured "cached_slug" column
2
+ class District
3
+ include DataMapper::Resource
4
+ property :id, Serial
5
+ property :name, String
6
+ property :note, String
7
+ property :cached_slug, String, :index => :unique
8
+ has_friendly_id :name, :use_slug => true
9
+ before :save, :say_hello
10
+
11
+ private
12
+
13
+ def say_hello
14
+ @said_hello = true
15
+ end
16
+ end
17
+
18
+ # A model with optimistic locking enabled
19
+ class Region
20
+ include DataMapper::Resource
21
+ property :id, Serial
22
+ property :name, String
23
+ property :cached_slug, String, :index => :unique
24
+ property :note, String
25
+ property :lock_version, Integer, :required => true, :default => 0
26
+
27
+ has_friendly_id :name, :use_slug => true
28
+
29
+ after :create do
30
+ other_instance = Region.get(self.id)
31
+ other_instance.update_attributes(:note => name + "!")
32
+ end
33
+ end
34
+
35
+ # A model that specifies a custom cached slug column
36
+ class City
37
+ include DataMapper::Resource
38
+ property :id, Serial
39
+ property :name, String
40
+ property :my_slug, String, :index => :unique
41
+ property :population, Integer
42
+ has_friendly_id :name, :use_slug => true, :cache_column => 'my_slug'
43
+ end
44
+
45
+ # A model with a custom slug text normalizer
46
+ class Person
47
+ include DataMapper::Resource
48
+ property :id, Serial
49
+ property :name, String
50
+ property :note, String
51
+ belongs_to :country, :required => false # Prevent DataMapper from creating
52
+ # an implicit required association
53
+ has_friendly_id :name, :use_slug => true
54
+
55
+ def normalize_friendly_id(string)
56
+ string.upcase
57
+ end
58
+
59
+ end
60
+
61
+ # A model that doesn't use FriendlyId
62
+ class Unfriendly
63
+ include DataMapper::Resource
64
+ property :id, Serial
65
+ property :name, String
66
+ end
67
+
68
+ # A slugged model that uses a scope
69
+ class Resident
70
+ include DataMapper::Resource
71
+ property :id, Serial
72
+ property :name, String
73
+ belongs_to :country
74
+ has_friendly_id :name, :use_slug => true, :scope => :country
75
+ end
76
+
77
+ # A slugged model used as a scope
78
+ class Country
79
+ include DataMapper::Resource
80
+ property :id, Serial
81
+ property :name, String
82
+ has n, :people
83
+ has n, :residents
84
+ has_friendly_id :name, :use_slug => true
85
+ end
86
+
87
+ # A model that doesn't use slugs
88
+ class User
89
+ include DataMapper::Resource
90
+ property :id, Serial
91
+ property :name, String
92
+ has_friendly_id :name
93
+ has n, :houses
94
+ end
95
+
96
+ # Another model that doesn"t use slugs
97
+ class Author
98
+ include DataMapper::Resource
99
+ property :id, Serial
100
+ property :name, String
101
+ has_friendly_id :name
102
+ end
103
+
104
+
105
+ # A model that uses a non-slugged model for its scope
106
+ class House
107
+ include DataMapper::Resource
108
+ property :id, Serial
109
+ property :name, String
110
+ belongs_to :user
111
+ has_friendly_id :name, :use_slug => true, :scope => :user
112
+ end
113
+
114
+ # A model that uses default slug settings and has a named scope
115
+ class Post
116
+ include DataMapper::Resource
117
+ property :id, Serial
118
+ property :name, String
119
+ property :published, Boolean
120
+ property :note, String
121
+ has_friendly_id :name, :use_slug => true
122
+
123
+ def self.published
124
+ all(:published => true)
125
+ end
126
+ end
127
+
128
+ # Model that uses a custom table name
129
+ class Place
130
+ include DataMapper::Resource
131
+ storage_names[:default] = 'legacy_table'
132
+ property :id, Serial
133
+ property :name, String
134
+ property :note, String
135
+ has_friendly_id :name, :use_slug => true
136
+ end
137
+
138
+ # A model that uses a datetime field for its friendly_id
139
+ class Event
140
+ include DataMapper::Resource
141
+ property :id, Serial
142
+ property :name, String
143
+ property :event_date, DateTime
144
+ has_friendly_id :event_date, :use_slug => true
145
+ end
146
+
147
+ # A base model for single table inheritence
148
+ class Book
149
+ include DataMapper::Resource
150
+ property :id, Serial
151
+ property :name, String
152
+ property :type, String
153
+ property :note, String
154
+ end
155
+
156
+ # A model that uses STI
157
+ class Novel < ::Book
158
+ has_friendly_id :name, :use_slug => true
159
+ end
160
+
161
+ =begin
162
+ # A model with no table
163
+ class Question
164
+ include DataMapper::Resource
165
+ has_friendly_id :name, :use_slug => true
166
+ end
167
+ =end
168
+
169
+ # A model to test polymorphic associations
170
+ class Site
171
+ include DataMapper::Resource
172
+ property :id, Serial
173
+ property :name, String
174
+ belongs_to :owner, 'Company'
175
+ #belongs_to :owner, :polymorphic => true
176
+ has_friendly_id :name, :use_slug => true
177
+ end
178
+
179
+ # A model used as a polymorphic owner
180
+ class Company
181
+ include DataMapper::Resource
182
+ property :id, Serial
183
+ property :name, String
184
+ #has n, :sites, :as => :owner
185
+ end