isa-friendly_id_datamapper 3.2.0.beta1

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,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