friendly_id4 4.0.0.beta6 → 4.0.0.pre

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,23 @@
1
+ # Allow declarative test definitions inside modules.
2
+ class Module
3
+ def test(name, &block)
4
+ define_method("test_#{name.gsub(/[^a-z0-9]/i, "_")}".to_sym, &block)
5
+ end
6
+ end
7
+
8
+ # Use this to create models in your tests, rather than define
9
+ # a bunch of static models. This allows for much more
10
+ # flexbile and granular tests.
11
+ #
12
+ # @name The table name - make sure it is unique.
13
+ # @args The args that will be passed to +has_friendly_id+.
14
+ # @block The block that will be passed to +create_table+.
15
+ def make_model(name, *args, &block)
16
+ ActiveRecord::Migration.create_table(name, &block)
17
+ Class.new(ActiveRecord::Base) do
18
+ self.table_name = name
19
+ has_friendly_id(*args)
20
+ end
21
+ end
22
+
23
+ require "friendly_id/test/generic"
@@ -0,0 +1,84 @@
1
+ module FriendlyId
2
+ module Test
3
+ # Tests for any model that implements FriendlyId. Any test that tests model
4
+ # features should include this module.
5
+ module Generic
6
+
7
+ def teardown
8
+ klass.delete_all
9
+ end
10
+
11
+ def instance
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def klass
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def other_class
20
+ raise NotImplementedError
21
+ end
22
+
23
+ test "model classes should have a friendly id config" do
24
+ assert_not_nil klass.friendly_id_config
25
+ end
26
+
27
+ test "finds should respect conditions" do
28
+ assert_raise ActiveRecord::RecordNotFound do
29
+ klass.find(instance.friendly_id, :conditions => "1 = 2")
30
+ end
31
+ end
32
+
33
+ test "instances should have a friendly id" do
34
+ assert_not_nil instance.friendly_id
35
+ end
36
+
37
+ test "instances should be findable by their friendly id" do
38
+ assert_equal instance, klass.find(instance.friendly_id)
39
+ end
40
+
41
+ test "instances should be findable by their numeric id as an integer" do
42
+ assert_equal instance, klass.find(instance.id.to_i)
43
+ end
44
+
45
+ test "instances should be findable by their numeric id as a string" do
46
+ assert_equal instance, klass.find(instance.id.to_s)
47
+ end
48
+
49
+ test "instances should be findable by a numeric friendly_id" do
50
+ instance = klass.create! :name => "206"
51
+ assert_equal instance, klass.find(instance.friendly_id)
52
+ end
53
+
54
+ test "to_param should return the friendly_id" do
55
+ assert_equal instance.friendly_id, instance.to_param
56
+ end
57
+
58
+ test "should allow the same friendly_id across models" do
59
+ other_instance = other_class.create! :name => instance.name
60
+ assert_equal other_instance.friendly_id, instance.friendly_id
61
+ end
62
+
63
+ test "instances should be findable by themselves" do
64
+ assert_equal instance, klass.find(instance)
65
+ end
66
+
67
+ test "updating record's other values should not change the friendly_id" do
68
+ old = instance.friendly_id
69
+ instance.save
70
+ assert klass.find(old)
71
+ end
72
+
73
+ test "instances found by a single id should not be read-only" do
74
+ assert !klass.find(instance.friendly_id).readonly?, "expected instance not to be readonly"
75
+ end
76
+
77
+ test "failing finds with unfriendly_id should raise errors normally" do
78
+ assert_raise ActiveRecord::RecordNotFound do
79
+ klass.find(0)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,9 @@
1
+ module FriendlyId
2
+ module Version
3
+ MAJOR = 4
4
+ MINOR = 0
5
+ TINY = 0
6
+ BUILD = 'pre'
7
+ STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
8
+ end
9
+ end
@@ -1,30 +1,68 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require File.expand_path("../test_helper", __FILE__)
2
2
 
3
- Author, Book = 2.times.map do
4
- Class.new(ActiveRecord::Base) do
5
- extend FriendlyId
6
- friendly_id :name
3
+ class ModelTest < Test::Unit::TestCase
4
+
5
+ include FriendlyId::Test::Generic
6
+
7
+ def instance(name = "user")
8
+ @instance ||= klass.create!(:name => name)
7
9
  end
8
- end
9
10
 
10
- class CoreTest < MiniTest::Unit::TestCase
11
+ # @TODO - this kind of setup is repeated in a few places and should probably
12
+ # be abstracted.
13
+ def klass
14
+ @@klass ||= make_model("core", :name) do |t|
15
+ t.string :name, :unique => true
16
+ t.boolean :active, :default => true
17
+ end
18
+ @@klass
19
+ end
11
20
 
12
- include FriendlyId::Test
13
- include FriendlyId::Test::Shared::Core
21
+ def other_class
22
+ @@other_class ||= make_model("core_two", :name) do |t|
23
+ t.string :name, :unique => true
24
+ t.boolean :active, :default => true
25
+ end
26
+ end
14
27
 
15
- def model_class
16
- Author
28
+ def setup
29
+ klass.stubs(:name).returns("Cores")
30
+ other_class.stubs(:name).returns("CoreTwos")
17
31
  end
18
32
 
19
33
  test "models don't use friendly_id by default" do
20
- assert !Class.new(ActiveRecord::Base).respond_to?(:friendly_id)
34
+ assert !Class.new(ActiveRecord::Base).uses_friendly_id?
35
+ end
36
+
37
+ test "integers should be unfriendly ids" do
38
+ assert 1.unfriendly_id?
21
39
  end
22
40
 
23
- test "model classes should have a friendly id config" do
24
- assert model_class.friendly_id(:name).friendly_id_config
41
+ test "ActiveRecord::Base instances should be unfriendly_ids" do
42
+ assert klass.new.unfriendly_id?
25
43
  end
26
44
 
27
- test "instances should have a friendly id" do
28
- with_instance_of(model_class) {|record| assert record.friendly_id}
45
+ test "numeric strings are neither friendly nor unfriendly" do
46
+ assert_equal nil, "1".friendly_id?
47
+ assert_equal nil, "1".unfriendly_id?
29
48
  end
49
+
50
+ test "strings with letters are friendly_ids" do
51
+ assert "a".friendly_id?
52
+ end
53
+
54
+ test "should raise error when bad config options are set" do
55
+ assert_raises ArgumentError do
56
+ klass.has_friendly_id :smeg, :garbage => :in
57
+ end
58
+ end
59
+
60
+ test "reserves 'new' and 'edit' by default" do
61
+ FriendlyId::Configuration::DEFAULTS[:reserved_words].each do |word|
62
+ assert_raises ActiveRecord::RecordInvalid do
63
+ klass.create! :name => word
64
+ end
65
+ end
66
+ end
67
+
30
68
  end
@@ -1,57 +1,61 @@
1
- require File.expand_path("../helper", __FILE__)
2
-
3
- class Novelist < ActiveRecord::Base
4
- extend FriendlyId
5
- friendly_id :name, :use => :slugged
1
+ # encoding: utf-8
2
+ require File.expand_path("../test_helper", __FILE__)
3
+ require "friendly_id/scoped"
4
+
5
+ Restaurant = make_model("restaurants", :name) do |t|
6
+ t.string :name
7
+ t.string :slug
8
+ t.integer :city_id
6
9
  end
7
10
 
8
- class Novel < ActiveRecord::Base
9
- extend FriendlyId
10
- belongs_to :novelist
11
- friendly_id :name, :use => :scoped, :scope => :novelist
11
+ City = make_model("cities", :name) do |t|
12
+ t.string :name
13
+ t.string :slug
12
14
  end
13
15
 
14
- class ScopedTest < MiniTest::Unit::TestCase
16
+ Restaurant.belongs_to :city
17
+ City.has_many :restaurants
18
+ City.send :include, FriendlyId::Slugged
19
+ Restaurant.send :include, FriendlyId::Scoped
20
+ Restaurant.has_friendly_id :name, :scope => :city
15
21
 
16
- include FriendlyId::Test
17
- include FriendlyId::Test::Shared::Core
22
+ class ScopedTest < Test::Unit::TestCase
18
23
 
19
- def model_class
20
- Novel
24
+ def setup
25
+ Restaurant.delete_all
26
+ City.delete_all
21
27
  end
22
28
 
23
29
  test "should detect scope column from belongs_to relation" do
24
- assert_equal "novelist_id", Novel.friendly_id_config.scope_column
30
+ assert_equal "city_id", Restaurant.friendly_id_config.scope_column
25
31
  end
26
32
 
27
33
  test "should detect scope column from explicit column name" do
28
- model_class = Class.new(ActiveRecord::Base)
29
- model_class.extend FriendlyId
30
- model_class.friendly_id :empty, :use => :scoped, :scope => :dummy
31
- assert_equal "dummy", model_class.friendly_id_config.scope_column
34
+ klass = Class.new(ActiveRecord::Base)
35
+ klass.has_friendly_id :empty, :scope => :dummy
36
+ assert_equal "dummy", klass.friendly_id_config.scope_column
32
37
  end
33
38
 
34
39
  test "should allow duplicate slugs outside scope" do
35
- transaction do
36
- novel1 = Novel.create! :name => "a", :novelist => Novelist.create!(:name => "a")
37
- novel2 = Novel.create! :name => "a", :novelist => Novelist.create!(:name => "b")
38
- assert_equal novel1.friendly_id, novel2.friendly_id
39
- end
40
+ c1 = City.create! :name => "Nuñez"
41
+ c2 = City.create! :name => "Las Cañitas"
42
+ r1 = Restaurant.create! :name => "La Guitarrita", :city => c1
43
+ r2 = Restaurant.create! :name => "La Guitarrita", :city => c2
44
+ assert_equal r1.friendly_id, r2.friendly_id
40
45
  end
41
46
 
42
47
  test "should not allow duplicate slugs inside scope" do
43
- with_instance_of Novelist do |novelist|
44
- novel1 = Novel.create! :name => "a", :novelist => novelist
45
- novel2 = Novel.create! :name => "a", :novelist => novelist
46
- assert novel1.friendly_id != novel2.friendly_id
47
- end
48
+ c1 = City.create! :name => "Nuñez"
49
+ r1 = Restaurant.create! :name => "La Guitarrita", :city => c1
50
+ r2 = Restaurant.create! :name => "La Guitarrita", :city => c1
51
+ assert_not_equal "la-guitarrita", r2.friendly_id
48
52
  end
49
53
 
50
- test "should raise error if used with history" do
51
- model_class = Class.new(ActiveRecord::Base)
52
- model_class.extend FriendlyId
53
- assert_raises RuntimeError do
54
- model_class.friendly_id :name, :use => [:scoped, :history]
55
- end
54
+ test "updating record's other values should not change the friendly_id" do
55
+ city = City.create! :name => "Nuñez"
56
+ old = city.friendly_id
57
+ city.save!
58
+ assert_equal old, city.friendly_id
56
59
  end
60
+
57
61
  end
@@ -1,83 +1,64 @@
1
- require File.expand_path("../helper.rb", __FILE__)
1
+ require File.expand_path("../test_helper", __FILE__)
2
+ require "friendly_id/slugged"
2
3
 
3
- Journalist, Article = 2.times.map do
4
- Class.new(ActiveRecord::Base) do
5
- extend FriendlyId
6
- friendly_id :name, :use => :slugged
7
- end
8
- end
9
-
10
- class SluggedTest < MiniTest::Unit::TestCase
4
+ class SluggedTest < Test::Unit::TestCase
11
5
 
12
- include FriendlyId::Test
13
- include FriendlyId::Test::Shared::Core
14
- include FriendlyId::Test::Shared::Slugged
6
+ include FriendlyId::Test::Generic
15
7
 
16
- def model_class
17
- Journalist
8
+ def instance(name = "user")
9
+ @instance ||= klass.create!(:name => name)
18
10
  end
19
- end
20
-
21
- class SlugSequencerTest < MiniTest::Unit::TestCase
22
11
 
23
- include FriendlyId::Test
24
-
25
- test "should quote column names" do
26
- model_class = Class.new(ActiveRecord::Base)
27
- model_class.table_name = "journalists"
28
- model_class.extend FriendlyId
29
- model_class.friendly_id :name, :use => :slugged, :slug_column => "strange name"
30
- begin
31
- with_instance_of(model_class) {|record| assert model_class.find(record.friendly_id)}
32
- rescue ActiveRecord::StatementInvalid
33
- flunk "column name was not quoted"
12
+ def klass
13
+ return @@klass if defined?(@@klass)
14
+ @@klass = make_model("slugged_model", :name) do |t|
15
+ t.string :name, :unique => true
16
+ t.string :slug, :unique => true
17
+ t.boolean :active, :default => true
34
18
  end
19
+ @@klass.send :include, FriendlyId::Slugged
20
+ @@klass
35
21
  end
36
- end
37
-
38
- class SlugSeparatorTest < MiniTest::Unit::TestCase
39
-
40
- include FriendlyId::Test
41
22
 
42
- class Journalist < ActiveRecord::Base
43
- extend FriendlyId
44
- friendly_id :name, :use => :slugged, :sequence_separator => ":"
23
+ def other_class
24
+ return @@other_class if defined?(@@other_class)
25
+ @@other_class = make_model("other_slugged_model", :name) do |t|
26
+ t.string :name, :unique => true
27
+ t.string :slug, :unique => true
28
+ t.boolean :active, :default => true
29
+ end
30
+ @@other_class.send :include, FriendlyId::Slugged
31
+ @@other_class
45
32
  end
46
33
 
47
- def model_class
48
- Journalist
34
+ def setup
35
+ klass.delete_all
36
+ other_class.delete_all
49
37
  end
50
38
 
51
- test "should increment sequence with configured sequence separator" do
52
- with_instance_of model_class do |record|
53
- record2 = model_class.create! :name => record.name
54
- assert record2.friendly_id.match(/:2\z/)
55
- end
39
+ test "configuration should have a sequence_separator" do
40
+ assert_not_nil klass.friendly_id_config.sequence_separator
56
41
  end
57
42
 
58
- test "should detect when a sequenced slug has changed" do
59
- with_instance_of model_class do |record|
60
- record2 = model_class.create! :name => record.name
61
- assert !record2.slug_sequencer.slug_changed?
62
- record2.name = "hello world"
63
- assert record2.slug_sequencer.slug_changed?
64
- end
43
+ test "should make a new slug if the friendly_id method value has changed" do
44
+ instance.name = "Changed Value"
45
+ instance.save!
46
+ assert_equal "changed-value", instance.slug
65
47
  end
66
- end
67
48
 
68
- class SluggedRegressionsTest < MiniTest::Unit::TestCase
69
- include FriendlyId::Test
70
-
71
- def model_class
72
- Journalist
49
+ test "should increment the slug sequence for duplicate friendly ids" do
50
+ instance2 = klass.create! :name => instance.name
51
+ assert_match(/2\z/, instance2.friendly_id)
52
+ instance3 = klass.create! :name => instance.name
53
+ assert_match(/3\z/, instance3.friendly_id)
73
54
  end
74
55
 
75
- test "should increment the slug sequence for duplicate friendly ids beyond 10" do
76
- with_instance_of model_class do |record|
77
- (2..12).each do |i|
78
- r = model_class.create! :name => record.name
79
- assert r.friendly_id.match(/#{i}\z/)
80
- end
81
- end
56
+ test "should not add slug sequence on update after other conflicting slugs were added" do
57
+ old = instance.friendly_id
58
+ instance2 = klass.create! :name => instance.name
59
+ instance.save!
60
+ instance.reload
61
+ assert_equal old, instance.to_param
82
62
  end
83
- end
63
+
64
+ end
@@ -0,0 +1,23 @@
1
+ $VERBOSE = false
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+ require "active_record"
5
+ require "active_support"
6
+ require "friendly_id"
7
+ require "friendly_id/test"
8
+ require "test/unit"
9
+ require "mocha"
10
+
11
+ ActiveRecord::Migration.verbose = false
12
+
13
+ # Change the connection args as you see fit to test against different adapters.
14
+ ActiveRecord::Base.establish_connection(
15
+ :adapter => "sqlite3",
16
+ :database => ":memory:"
17
+ )
18
+
19
+ # If you want to see the ActiveRecord log, invoke the tests using `rake test LOG=true`
20
+ if ENV["LOG"]
21
+ require "logger"
22
+ ActiveRecord::Base.logger = Logger.new($stdout)
23
+ end