activerecord 1.13.0 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (68) hide show
  1. data/CHANGELOG +91 -0
  2. data/lib/active_record.rb +2 -2
  3. data/lib/active_record/acts/list.rb +16 -12
  4. data/lib/active_record/acts/tree.rb +2 -2
  5. data/lib/active_record/aggregations.rb +6 -0
  6. data/lib/active_record/associations.rb +38 -16
  7. data/lib/active_record/associations/has_many_association.rb +2 -1
  8. data/lib/active_record/associations/has_one_association.rb +1 -1
  9. data/lib/active_record/base.rb +46 -33
  10. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +33 -9
  11. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -2
  12. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -0
  13. data/lib/active_record/connection_adapters/abstract_adapter.rb +41 -21
  14. data/lib/active_record/connection_adapters/firebird_adapter.rb +414 -0
  15. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -29
  16. data/lib/active_record/connection_adapters/oci_adapter.rb +141 -21
  17. data/lib/active_record/connection_adapters/postgresql_adapter.rb +82 -21
  18. data/lib/active_record/connection_adapters/sqlite_adapter.rb +3 -3
  19. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +39 -6
  20. data/lib/active_record/fixtures.rb +1 -0
  21. data/lib/active_record/migration.rb +30 -13
  22. data/lib/active_record/validations.rb +18 -7
  23. data/lib/active_record/vendor/mysql.rb +89 -12
  24. data/lib/active_record/version.rb +2 -2
  25. data/rakefile +38 -3
  26. data/test/abstract_unit.rb +5 -0
  27. data/test/aggregations_test.rb +19 -0
  28. data/test/associations_go_eager_test.rb +26 -2
  29. data/test/associations_test.rb +29 -10
  30. data/test/base_test.rb +57 -6
  31. data/test/binary_test.rb +3 -3
  32. data/test/connections/native_db2/connection.rb +1 -1
  33. data/test/connections/native_firebird/connection.rb +24 -0
  34. data/test/connections/native_mysql/connection.rb +1 -1
  35. data/test/connections/native_oci/connection.rb +1 -1
  36. data/test/connections/native_postgresql/connection.rb +6 -6
  37. data/test/connections/native_sqlite/connection.rb +1 -1
  38. data/test/connections/native_sqlite3/connection.rb +1 -1
  39. data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
  40. data/test/connections/native_sqlserver/connection.rb +1 -1
  41. data/test/connections/native_sqlserver_odbc/connection.rb +1 -1
  42. data/test/default_test_firebird.rb +16 -0
  43. data/test/deprecated_associations_test.rb +1 -1
  44. data/test/finder_test.rb +11 -1
  45. data/test/fixtures/author.rb +30 -30
  46. data/test/fixtures/comment.rb +1 -1
  47. data/test/fixtures/company.rb +3 -1
  48. data/test/fixtures/customer.rb +4 -0
  49. data/test/fixtures/db_definitions/firebird.drop.sql +54 -0
  50. data/test/fixtures/db_definitions/firebird.sql +259 -0
  51. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  52. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  53. data/test/fixtures/db_definitions/oci.sql +8 -0
  54. data/test/fixtures/db_definitions/postgresql.sql +3 -2
  55. data/test/fixtures/developer.rb +10 -0
  56. data/test/fixtures/fixture_database.sqlite +0 -0
  57. data/test/fixtures/fixture_database_2.sqlite +0 -0
  58. data/test/fixtures/mixin.rb +11 -1
  59. data/test/fixtures/mixins.yml +20 -1
  60. data/test/fixtures_test.rb +65 -45
  61. data/test/inheritance_test.rb +1 -1
  62. data/test/migration_test.rb +7 -1
  63. data/test/mixin_test.rb +267 -98
  64. data/test/multiple_db_test.rb +13 -1
  65. data/test/pk_test.rb +1 -0
  66. metadata +11 -5
  67. data/lib/active_record/vendor/mysql411.rb +0 -311
  68. data/test/debug.log +0 -2857
@@ -0,0 +1,2 @@
1
+ DROP TABLE courses;
2
+ DROP GENERATOR courses_seq;
@@ -0,0 +1,6 @@
1
+ CREATE TABLE courses (
2
+ id BIGINT NOT NULL PRIMARY KEY,
3
+ name VARCHAR(255) NOT NULL
4
+ );
5
+ CREATE GENERATOR courses_seq;
6
+ SET GENERATOR courses_seq TO 10000;
@@ -261,3 +261,11 @@ create table keyboards (
261
261
  );
262
262
  create sequence keyboards_seq minvalue 10000;
263
263
 
264
+ create table test_oci_defaults (
265
+ id integer not null primary key,
266
+ test_char char(1) default 'X' not null,
267
+ test_string varchar2(20) default 'hello' not null,
268
+ test_int integer default 3 not null
269
+ );
270
+ create sequence test_oci_defaults_seq minvalue 10000;
271
+
@@ -1,10 +1,11 @@
1
+ CREATE SEQUENCE public.accounts_id_seq START 100;
2
+
1
3
  CREATE TABLE accounts (
2
- id serial,
4
+ id integer DEFAULT nextval('public.accounts_id_seq'),
3
5
  firm_id integer,
4
6
  credit_limit integer,
5
7
  PRIMARY KEY (id)
6
8
  );
7
- SELECT setval('accounts_id_seq', 100);
8
9
 
9
10
  CREATE SEQUENCE companies_nonstd_seq START 101;
10
11
 
@@ -28,3 +28,13 @@ class DeveloperWithAggregate < ActiveRecord::Base
28
28
  self.table_name = 'developers'
29
29
  composed_of :salary, :class_name => 'DeveloperSalary', :mapping => [%w(salary amount)]
30
30
  end
31
+
32
+ class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base
33
+ self.table_name = 'developers'
34
+ has_and_belongs_to_many :projects, :join_table => 'developers_projects', :foreign_key => 'developer_id'
35
+ before_destroy :raise_if_projects_empty!
36
+
37
+ def raise_if_projects_empty!
38
+ raise if projects.empty?
39
+ end
40
+ end
@@ -6,12 +6,22 @@ class TreeMixin < Mixin
6
6
  acts_as_tree :foreign_key => "parent_id", :order => "id"
7
7
  end
8
8
 
9
+ class TreeMixinWithoutOrder < Mixin
10
+ acts_as_tree :foreign_key => "parent_id"
11
+ end
12
+
9
13
  class ListMixin < Mixin
10
14
  acts_as_list :column => "pos", :scope => :parent
11
15
 
12
16
  def self.table_name() "mixins" end
13
17
  end
14
18
 
19
+ class ListMixinSub1 < ListMixin
20
+ end
21
+
22
+ class ListMixinSub2 < ListMixin
23
+ end
24
+
15
25
 
16
26
  class ListWithStringScopeMixin < ActiveRecord::Base
17
27
  acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}'
@@ -35,4 +45,4 @@ class NestedSetWithSymbolScope < Mixin
35
45
  acts_as_nested_set :scope => :root
36
46
 
37
47
  def self.table_name() "mixins" end
38
- end
48
+ end
@@ -28,7 +28,17 @@ tree3_1:
28
28
  id: 1006
29
29
  type: TreeMixin
30
30
  parent_id:
31
-
31
+
32
+ tree_without_order_1:
33
+ id: 1101
34
+ type: TreeMixinWithoutOrder
35
+ parent_id:
36
+
37
+ tree_without_order_2:
38
+ id: 1100
39
+ type: TreeMixinWithoutOrder
40
+ parent_id:
41
+
32
42
  # List mixins
33
43
 
34
44
  <% (1..4).each do |counter| %>
@@ -68,3 +78,12 @@ tree_<%= set[0] %>:
68
78
  root_id: 42
69
79
 
70
80
  <% end %>
81
+
82
+ # subclasses of list items
83
+ <% (1..4).each do |i| %>
84
+ list_sub_<%= i %>:
85
+ id: <%= i + 5000 %>
86
+ pos: <%= i %>
87
+ parent_id: 5000
88
+ type: <%= (i % 2 == 1) ? ListMixinSub1 : ListMixinSub2 %>
89
+ <% end %>
@@ -51,42 +51,44 @@ class FixturesTest < Test::Unit::TestCase
51
51
  assert_nil(secondRow["author_email_address"])
52
52
  end
53
53
 
54
- def test_inserts_with_pre_and_suffix
55
- ActiveRecord::Base.connection.create_table :prefix_topics_suffix do |t|
56
- t.column :title, :string
57
- t.column :author_name, :string
58
- t.column :author_email_address, :string
59
- t.column :written_on, :datetime
60
- t.column :bonus_time, :time
61
- t.column :last_read, :date
62
- t.column :content, :text
63
- t.column :approved, :boolean, :default => true
64
- t.column :replies_count, :integer, :default => 0
65
- t.column :parent_id, :integer
66
- t.column :type, :string, :limit => 50
67
- end
54
+ if ActiveRecord::Base.connection.supports_migrations?
55
+ def test_inserts_with_pre_and_suffix
56
+ ActiveRecord::Base.connection.create_table :prefix_topics_suffix do |t|
57
+ t.column :title, :string
58
+ t.column :author_name, :string
59
+ t.column :author_email_address, :string
60
+ t.column :written_on, :datetime
61
+ t.column :bonus_time, :time
62
+ t.column :last_read, :date
63
+ t.column :content, :text
64
+ t.column :approved, :boolean, :default => true
65
+ t.column :replies_count, :integer, :default => 0
66
+ t.column :parent_id, :integer
67
+ t.column :type, :string, :limit => 50
68
+ end
68
69
 
69
- # Store existing prefix/suffix
70
- old_prefix = ActiveRecord::Base.table_name_prefix
71
- old_suffix = ActiveRecord::Base.table_name_suffix
70
+ # Store existing prefix/suffix
71
+ old_prefix = ActiveRecord::Base.table_name_prefix
72
+ old_suffix = ActiveRecord::Base.table_name_suffix
72
73
 
73
- # Set a prefix/suffix we can test against
74
- ActiveRecord::Base.table_name_prefix = 'prefix_'
75
- ActiveRecord::Base.table_name_suffix = '_suffix'
74
+ # Set a prefix/suffix we can test against
75
+ ActiveRecord::Base.table_name_prefix = 'prefix_'
76
+ ActiveRecord::Base.table_name_suffix = '_suffix'
76
77
 
77
- topics = create_fixtures("topics")
78
+ topics = create_fixtures("topics")
78
79
 
79
- # Restore prefix/suffix to its previous values
80
- ActiveRecord::Base.table_name_prefix = old_prefix
81
- ActiveRecord::Base.table_name_suffix = old_suffix
80
+ # Restore prefix/suffix to its previous values
81
+ ActiveRecord::Base.table_name_prefix = old_prefix
82
+ ActiveRecord::Base.table_name_suffix = old_suffix
82
83
 
83
- firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'David'")
84
- assert_equal("The First Topic", firstRow["title"])
84
+ firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'David'")
85
+ assert_equal("The First Topic", firstRow["title"])
85
86
 
86
- secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
87
- assert_nil(secondRow["author_email_address"])
88
- ensure
89
- ActiveRecord::Base.connection.drop_table :prefix_topics_suffix rescue nil
87
+ secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
88
+ assert_nil(secondRow["author_email_address"])
89
+ ensure
90
+ ActiveRecord::Base.connection.drop_table :prefix_topics_suffix rescue nil
91
+ end
90
92
  end
91
93
 
92
94
  def test_insert_with_datetime
@@ -173,27 +175,45 @@ end
173
175
  if Account.connection.respond_to?(:reset_pk_sequence!)
174
176
  class FixturesResetPkSequenceTest < Test::Unit::TestCase
175
177
  fixtures :accounts
178
+ fixtures :companies
179
+
180
+ def setup
181
+ @instances = [Account.new(:credit_limit => 50), Company.new(:name => 'RoR Consulting')]
182
+ end
176
183
 
177
- def test_resets_to_min_pk
178
- Account.delete_all
179
- Account.connection.reset_pk_sequence!(Account.table_name)
184
+ def test_resets_to_min_pk_with_specified_pk_and_sequence
185
+ @instances.each do |instance|
186
+ model = instance.class
187
+ model.delete_all
188
+ model.connection.reset_pk_sequence!(model.table_name, model.primary_key, model.sequence_name)
180
189
 
181
- one = Account.new(:credit_limit => 50)
182
- one.save!
183
- assert_equal 1, one.id
190
+ instance.save!
191
+ assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
192
+ end
184
193
  end
185
194
 
186
- def test_create_fixtures_resets_sequences
187
- # create_fixtures performs reset_pk_sequence!
188
- max_id = create_fixtures('accounts').inject(0) do |max_id, (name, fixture)|
189
- fixture_id = fixture['id'].to_i
190
- fixture_id > max_id ? fixture_id : max_id
195
+ def test_resets_to_min_pk_with_default_pk_and_sequence
196
+ @instances.each do |instance|
197
+ model = instance.class
198
+ model.delete_all
199
+ model.connection.reset_pk_sequence!(model.table_name)
200
+
201
+ instance.save!
202
+ assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
191
203
  end
204
+ end
192
205
 
193
- # Clone the last fixture to check that it gets the next greatest id.
194
- another = Account.new(:credit_limit => 1200)
195
- another.save!
196
- assert_equal max_id + 1, another.id
206
+ def test_create_fixtures_resets_sequences
207
+ @instances.each do |instance|
208
+ max_id = create_fixtures(instance.class.table_name).inject(0) do |max_id, (name, fixture)|
209
+ fixture_id = fixture['id'].to_i
210
+ fixture_id > max_id ? fixture_id : max_id
211
+ end
212
+
213
+ # Clone the last fixture to check that it gets the next greatest id.
214
+ instance.save!
215
+ assert_equal max_id + 1, instance.id, "Sequence reset for #{instance.class.table_name} failed."
216
+ end
197
217
  end
198
218
  end
199
219
  end
@@ -11,7 +11,7 @@ class InheritanceTest < Test::Unit::TestCase
11
11
  if current_adapter?(:SQLServerAdapter)
12
12
  Company.connection.execute "SET IDENTITY_INSERT companies ON"
13
13
  end
14
- Company.connection.insert "INSERT INTO companies (id, type, name) VALUES(100, 'bad_class!', 'Not happening')"
14
+ Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
15
15
 
16
16
  #We then need to turn it back Off before continuing.
17
17
  if current_adapter?(:SQLServerAdapter)
@@ -362,6 +362,9 @@ if ActiveRecord::Base.connection.supports_migrations?
362
362
  ActiveRecord::Base.table_name_suffix = ""
363
363
  Reminder.reset_table_name
364
364
  assert_equal "schema_info", ActiveRecord::Migrator.schema_info_table_name
365
+ ensure
366
+ ActiveRecord::Base.table_name_prefix = ""
367
+ ActiveRecord::Base.table_name_suffix = ""
365
368
  end
366
369
 
367
370
  def test_proper_table_name
@@ -398,17 +401,20 @@ if ActiveRecord::Base.connection.supports_migrations?
398
401
  ActiveRecord::Base.table_name_prefix = 'prefix_'
399
402
  ActiveRecord::Base.table_name_suffix = '_suffix'
400
403
  Reminder.reset_table_name
404
+ Reminder.reset_sequence_name
401
405
  WeNeedReminders.up
402
406
  assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
403
407
  assert_equal "hello world", Reminder.find(:first).content
404
408
 
405
409
  WeNeedReminders.down
406
410
  assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
411
+ ensure
407
412
  ActiveRecord::Base.table_name_prefix = ''
408
413
  ActiveRecord::Base.table_name_suffix = ''
409
414
  Reminder.reset_table_name
415
+ Reminder.reset_sequence_name
410
416
  end
411
-
417
+
412
418
  def test_migrator_with_duplicates
413
419
  assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
414
420
  ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
@@ -6,96 +6,95 @@ require 'fixtures/mixin'
6
6
 
7
7
  class ListTest < Test::Unit::TestCase
8
8
  fixtures :mixins
9
-
9
+
10
10
  def test_reordering
11
-
12
- assert_equal [mixins(:list_1),
13
- mixins(:list_2),
14
- mixins(:list_3),
15
- mixins(:list_4)],
11
+ assert_equal [mixins(:list_1),
12
+ mixins(:list_2),
13
+ mixins(:list_3),
14
+ mixins(:list_4)],
16
15
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
17
-
16
+
18
17
  mixins(:list_2).move_lower
19
-
20
- assert_equal [mixins(:list_1),
21
- mixins(:list_3),
22
- mixins(:list_2),
23
- mixins(:list_4)],
18
+
19
+ assert_equal [mixins(:list_1),
20
+ mixins(:list_3),
21
+ mixins(:list_2),
22
+ mixins(:list_4)],
24
23
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
25
-
24
+
26
25
  mixins(:list_2).move_higher
27
26
 
28
- assert_equal [mixins(:list_1),
29
- mixins(:list_2),
30
- mixins(:list_3),
31
- mixins(:list_4)],
27
+ assert_equal [mixins(:list_1),
28
+ mixins(:list_2),
29
+ mixins(:list_3),
30
+ mixins(:list_4)],
32
31
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
33
-
32
+
34
33
  mixins(:list_1).move_to_bottom
35
34
 
36
- assert_equal [mixins(:list_2),
37
- mixins(:list_3),
38
- mixins(:list_4),
39
- mixins(:list_1)],
35
+ assert_equal [mixins(:list_2),
36
+ mixins(:list_3),
37
+ mixins(:list_4),
38
+ mixins(:list_1)],
40
39
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
41
40
 
42
41
  mixins(:list_1).move_to_top
43
42
 
44
- assert_equal [mixins(:list_1),
45
- mixins(:list_2),
46
- mixins(:list_3),
43
+ assert_equal [mixins(:list_1),
44
+ mixins(:list_2),
45
+ mixins(:list_3),
47
46
  mixins(:list_4)],
48
47
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
49
-
50
-
48
+
49
+
51
50
  mixins(:list_2).move_to_bottom
52
-
53
- assert_equal [mixins(:list_1),
54
- mixins(:list_3),
55
- mixins(:list_4),
51
+
52
+ assert_equal [mixins(:list_1),
53
+ mixins(:list_3),
54
+ mixins(:list_4),
56
55
  mixins(:list_2)],
57
56
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
58
57
 
59
58
  mixins(:list_4).move_to_top
60
59
 
61
- assert_equal [mixins(:list_4),
62
- mixins(:list_1),
63
- mixins(:list_3),
60
+ assert_equal [mixins(:list_4),
61
+ mixins(:list_1),
62
+ mixins(:list_3),
64
63
  mixins(:list_2)],
65
64
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
66
-
65
+
67
66
  end
68
67
 
69
68
  def test_move_to_bottom_with_next_to_last_item
70
- assert_equal [mixins(:list_1),
71
- mixins(:list_2),
72
- mixins(:list_3),
73
- mixins(:list_4)],
69
+ assert_equal [mixins(:list_1),
70
+ mixins(:list_2),
71
+ mixins(:list_3),
72
+ mixins(:list_4)],
74
73
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
75
74
 
76
75
  mixins(:list_3).move_to_bottom
77
76
 
78
- assert_equal [mixins(:list_1),
79
- mixins(:list_2),
80
- mixins(:list_4),
81
- mixins(:list_3)],
77
+ assert_equal [mixins(:list_1),
78
+ mixins(:list_2),
79
+ mixins(:list_4),
80
+ mixins(:list_3)],
82
81
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
83
82
  end
84
-
83
+
85
84
  def test_next_prev
86
85
  assert_equal mixins(:list_2), mixins(:list_1).lower_item
87
86
  assert_nil mixins(:list_1).higher_item
88
87
  assert_equal mixins(:list_3), mixins(:list_4).higher_item
89
88
  assert_nil mixins(:list_4).lower_item
90
89
  end
91
-
92
-
90
+
91
+
93
92
  def test_injection
94
93
  item = ListMixin.new("parent_id"=>1)
95
94
  assert_equal "parent_id = 1", item.scope_condition
96
95
  assert_equal "pos", item.position_column
97
- end
98
-
96
+ end
97
+
99
98
  def test_insert
100
99
  new = ListMixin.create("parent_id"=>20)
101
100
  assert_equal 1, new.pos
@@ -106,37 +105,37 @@ class ListTest < Test::Unit::TestCase
106
105
  assert_equal 2, new.pos
107
106
  assert !new.first?
108
107
  assert new.last?
109
-
108
+
110
109
  new = ListMixin.create("parent_id"=>20)
111
- assert_equal 3, new.pos
110
+ assert_equal 3, new.pos
112
111
  assert !new.first?
113
112
  assert new.last?
114
-
113
+
115
114
  new = ListMixin.create("parent_id"=>0)
116
115
  assert_equal 1, new.pos
117
116
  assert new.first?
118
117
  assert new.last?
119
- end
118
+ end
120
119
 
121
120
  def test_insert_at
122
121
  new = ListMixin.create("parent_id" => 20)
123
122
  assert_equal 1, new.pos
124
123
 
125
- new = ListMixin.create("parent_id" => 20)
126
- assert_equal 2, new.pos
127
-
128
- new = ListMixin.create("parent_id" => 20)
129
- assert_equal 3, new.pos
124
+ new = ListMixin.create("parent_id" => 20)
125
+ assert_equal 2, new.pos
126
+
127
+ new = ListMixin.create("parent_id" => 20)
128
+ assert_equal 3, new.pos
129
+
130
+ new4 = ListMixin.create("parent_id" => 20)
131
+ assert_equal 4, new4.pos
130
132
 
131
- new4 = ListMixin.create("parent_id" => 20)
132
- assert_equal 4, new4.pos
133
+ new4.insert_at(3)
134
+ assert_equal 3, new4.pos
133
135
 
134
- new4.insert_at(3)
135
- assert_equal 3, new4.pos
136
+ new.reload
137
+ assert_equal 4, new.pos
136
138
 
137
- new.reload
138
- assert_equal 4, new.pos
139
-
140
139
  new.insert_at(2)
141
140
  assert_equal 2, new.pos
142
141
 
@@ -152,54 +151,54 @@ class ListTest < Test::Unit::TestCase
152
151
  new4.reload
153
152
  assert_equal 5, new4.pos
154
153
  end
155
-
154
+
156
155
  def test_delete_middle
157
-
158
- assert_equal [mixins(:list_1),
159
- mixins(:list_2),
160
- mixins(:list_3),
161
- mixins(:list_4)],
156
+ assert_equal [mixins(:list_1),
157
+ mixins(:list_2),
158
+ mixins(:list_3),
159
+ mixins(:list_4)],
162
160
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
163
-
161
+
164
162
  mixins(:list_2).destroy
165
-
166
- assert_equal [mixins(:list_1, :reload),
167
- mixins(:list_3, :reload),
168
- mixins(:list_4, :reload)],
163
+
164
+ assert_equal [mixins(:list_1, :reload),
165
+ mixins(:list_3, :reload),
166
+ mixins(:list_4, :reload)],
169
167
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
170
-
168
+
171
169
  assert_equal 1, mixins(:list_1).pos
172
170
  assert_equal 2, mixins(:list_3).pos
173
171
  assert_equal 3, mixins(:list_4).pos
174
172
 
175
173
  mixins(:list_1).destroy
176
174
 
177
- assert_equal [mixins(:list_3, :reload),
178
- mixins(:list_4, :reload)],
175
+ assert_equal [mixins(:list_3, :reload),
176
+ mixins(:list_4, :reload)],
179
177
  ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos')
180
-
178
+
181
179
  assert_equal 1, mixins(:list_3).pos
182
180
  assert_equal 2, mixins(:list_4).pos
183
-
184
- end
181
+
182
+ end
185
183
 
186
184
  def test_with_string_based_scope
187
185
  new = ListWithStringScopeMixin.create("parent_id"=>500)
188
186
  assert_equal 1, new.pos
189
187
  assert new.first?
190
188
  assert new.last?
191
- end
189
+ end
192
190
 
193
191
  def test_nil_scope
194
192
  new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
195
193
  new2.move_higher
196
194
  assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos')
197
195
  end
196
+
198
197
  end
199
198
 
200
199
  class TreeTest < Test::Unit::TestCase
201
200
  fixtures :mixins
202
-
201
+
203
202
  def test_has_child
204
203
  assert_equal true, mixins(:tree_1).has_children?
205
204
  assert_equal true, mixins(:tree_2).has_children?
@@ -226,7 +225,7 @@ class TreeTest < Test::Unit::TestCase
226
225
  assert_equal mixins(:tree_2).parent, mixins(:tree_4).parent
227
226
  assert_nil mixins(:tree_1).parent
228
227
  end
229
-
228
+
230
229
  def test_delete
231
230
  assert_equal 6, TreeMixin.count
232
231
  mixins(:tree_1).destroy
@@ -238,9 +237,9 @@ class TreeTest < Test::Unit::TestCase
238
237
 
239
238
  def test_insert
240
239
  @extra = mixins(:tree_1).children.create
241
-
240
+
242
241
  assert @extra
243
-
242
+
244
243
  assert_equal @extra.parent, mixins(:tree_1)
245
244
 
246
245
  assert_equal 3, mixins(:tree_1).children.size
@@ -257,7 +256,7 @@ class TreeTest < Test::Unit::TestCase
257
256
  assert_equal [], mixins(:tree2_1).ancestors
258
257
  assert_equal [], mixins(:tree3_1).ancestors
259
258
  end
260
-
259
+
261
260
  def test_root
262
261
  assert_equal mixins(:tree_1), TreeMixin.root
263
262
  assert_equal mixins(:tree_1), mixins(:tree_1).root
@@ -266,7 +265,7 @@ class TreeTest < Test::Unit::TestCase
266
265
  assert_equal mixins(:tree_1), mixins(:tree_4).root
267
266
  assert_equal mixins(:tree2_1), mixins(:tree2_1).root
268
267
  assert_equal mixins(:tree3_1), mixins(:tree3_1).root
269
- end
268
+ end
270
269
 
271
270
  def test_roots
272
271
  assert_equal [mixins(:tree_1), mixins(:tree2_1), mixins(:tree3_1)], TreeMixin.roots
@@ -291,40 +290,50 @@ class TreeTest < Test::Unit::TestCase
291
290
  end
292
291
  end
293
292
 
293
+ class TreeTestWithoutOrder < Test::Unit::TestCase
294
+ fixtures :mixins
295
+
296
+ def test_root
297
+ assert [mixins(:tree_without_order_1), mixins(:tree_without_order_2)].include?(TreeMixinWithoutOrder.root)
298
+ end
299
+
300
+ def test_roots
301
+ assert_equal [], [mixins(:tree_without_order_1), mixins(:tree_without_order_2)] - TreeMixinWithoutOrder.roots
302
+ end
303
+ end
304
+
294
305
  class TouchTest < Test::Unit::TestCase
295
306
  fixtures :mixins
296
-
307
+
297
308
  def test_update
298
-
299
- stamped = Mixin.new
300
-
309
+ stamped = Mixin.new
310
+
301
311
  assert_nil stamped.updated_at
302
312
  assert_nil stamped.created_at
303
313
  stamped.save
304
314
  assert_not_nil stamped.updated_at
305
315
  assert_not_nil stamped.created_at
306
- end
316
+ end
307
317
 
308
318
  def test_create
309
319
  @obj = Mixin.create
310
320
  assert_not_nil @obj.updated_at
311
321
  assert_not_nil @obj.created_at
312
- end
322
+ end
313
323
 
314
324
  def test_many_updates
315
-
316
- stamped = Mixin.new
325
+ stamped = Mixin.new
317
326
 
318
327
  assert_nil stamped.updated_at
319
328
  assert_nil stamped.created_at
320
329
  stamped.save
321
330
  assert_not_nil stamped.created_at
322
331
  assert_not_nil stamped.updated_at
323
-
332
+
324
333
  old_updated_at = stamped.updated_at
325
334
 
326
335
  sleep 1
327
- stamped.save
336
+ stamped.save
328
337
  assert_not_equal stamped.created_at, stamped.updated_at
329
338
  assert_not_equal old_updated_at, stamped.updated_at
330
339
 
@@ -341,3 +350,163 @@ class TouchTest < Test::Unit::TestCase
341
350
  end
342
351
 
343
352
  end
353
+
354
+
355
+ class ListSubTest < Test::Unit::TestCase
356
+ fixtures :mixins
357
+
358
+ def test_reordering
359
+ assert_equal [mixins(:list_sub_1),
360
+ mixins(:list_sub_2),
361
+ mixins(:list_sub_3),
362
+ mixins(:list_sub_4)],
363
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
364
+
365
+ mixins(:list_sub_2).move_lower
366
+
367
+ assert_equal [mixins(:list_sub_1),
368
+ mixins(:list_sub_3),
369
+ mixins(:list_sub_2),
370
+ mixins(:list_sub_4)],
371
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
372
+
373
+ mixins(:list_sub_2).move_higher
374
+
375
+ assert_equal [mixins(:list_sub_1),
376
+ mixins(:list_sub_2),
377
+ mixins(:list_sub_3),
378
+ mixins(:list_sub_4)],
379
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
380
+
381
+ mixins(:list_sub_1).move_to_bottom
382
+
383
+ assert_equal [mixins(:list_sub_2),
384
+ mixins(:list_sub_3),
385
+ mixins(:list_sub_4),
386
+ mixins(:list_sub_1)],
387
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
388
+
389
+ mixins(:list_sub_1).move_to_top
390
+
391
+ assert_equal [mixins(:list_sub_1),
392
+ mixins(:list_sub_2),
393
+ mixins(:list_sub_3),
394
+ mixins(:list_sub_4)],
395
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
396
+
397
+
398
+ mixins(:list_sub_2).move_to_bottom
399
+
400
+ assert_equal [mixins(:list_sub_1),
401
+ mixins(:list_sub_3),
402
+ mixins(:list_sub_4),
403
+ mixins(:list_sub_2)],
404
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
405
+
406
+ mixins(:list_sub_4).move_to_top
407
+
408
+ assert_equal [mixins(:list_sub_4),
409
+ mixins(:list_sub_1),
410
+ mixins(:list_sub_3),
411
+ mixins(:list_sub_2)],
412
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
413
+
414
+ end
415
+
416
+ def test_move_to_bottom_with_next_to_last_item
417
+ assert_equal [mixins(:list_sub_1),
418
+ mixins(:list_sub_2),
419
+ mixins(:list_sub_3),
420
+ mixins(:list_sub_4)],
421
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
422
+
423
+ mixins(:list_sub_3).move_to_bottom
424
+
425
+ assert_equal [mixins(:list_sub_1),
426
+ mixins(:list_sub_2),
427
+ mixins(:list_sub_4),
428
+ mixins(:list_sub_3)],
429
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
430
+ end
431
+
432
+ def test_next_prev
433
+ assert_equal mixins(:list_sub_2), mixins(:list_sub_1).lower_item
434
+ assert_nil mixins(:list_sub_1).higher_item
435
+ assert_equal mixins(:list_sub_3), mixins(:list_sub_4).higher_item
436
+ assert_nil mixins(:list_sub_4).lower_item
437
+ end
438
+
439
+
440
+ def test_injection
441
+ item = ListMixin.new("parent_id"=>1)
442
+ assert_equal "parent_id = 1", item.scope_condition
443
+ assert_equal "pos", item.position_column
444
+ end
445
+
446
+
447
+ def test_insert_at
448
+ new = ListMixin.create("parent_id" => 20)
449
+ assert_equal 1, new.pos
450
+
451
+ new = ListMixinSub1.create("parent_id" => 20)
452
+ assert_equal 2, new.pos
453
+
454
+ new = ListMixinSub2.create("parent_id" => 20)
455
+ assert_equal 3, new.pos
456
+
457
+ new4 = ListMixin.create("parent_id" => 20)
458
+ assert_equal 4, new4.pos
459
+
460
+ new4.insert_at(3)
461
+ assert_equal 3, new4.pos
462
+
463
+ new.reload
464
+ assert_equal 4, new.pos
465
+
466
+ new.insert_at(2)
467
+ assert_equal 2, new.pos
468
+
469
+ new4.reload
470
+ assert_equal 4, new4.pos
471
+
472
+ new5 = ListMixinSub1.create("parent_id" => 20)
473
+ assert_equal 5, new5.pos
474
+
475
+ new5.insert_at(1)
476
+ assert_equal 1, new5.pos
477
+
478
+ new4.reload
479
+ assert_equal 5, new4.pos
480
+ end
481
+
482
+ def test_delete_middle
483
+ assert_equal [mixins(:list_sub_1),
484
+ mixins(:list_sub_2),
485
+ mixins(:list_sub_3),
486
+ mixins(:list_sub_4)],
487
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
488
+
489
+ mixins(:list_sub_2).destroy
490
+
491
+ assert_equal [mixins(:list_sub_1, :reload),
492
+ mixins(:list_sub_3, :reload),
493
+ mixins(:list_sub_4, :reload)],
494
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
495
+
496
+ assert_equal 1, mixins(:list_sub_1).pos
497
+ assert_equal 2, mixins(:list_sub_3).pos
498
+ assert_equal 3, mixins(:list_sub_4).pos
499
+
500
+ mixins(:list_sub_1).destroy
501
+
502
+ assert_equal [mixins(:list_sub_3, :reload),
503
+ mixins(:list_sub_4, :reload)],
504
+ ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos')
505
+
506
+ assert_equal 1, mixins(:list_sub_3).pos
507
+ assert_equal 2, mixins(:list_sub_4).pos
508
+
509
+ end
510
+
511
+ end
512
+