remarkable_activerecord 3.0.1 → 3.0.2

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.
Files changed (39) hide show
  1. data/CHANGELOG +46 -46
  2. data/LICENSE +1 -1
  3. data/README +64 -64
  4. data/lib/remarkable_activerecord.rb +1 -1
  5. data/lib/remarkable_activerecord/base.rb +40 -40
  6. data/lib/remarkable_activerecord/human_names.rb +24 -24
  7. data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +14 -14
  8. data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +70 -70
  9. data/lib/remarkable_activerecord/matchers/association_matcher.rb +197 -197
  10. data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +29 -29
  11. data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +20 -20
  12. data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +7 -7
  13. data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +34 -34
  14. data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +37 -37
  15. data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +75 -75
  16. data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +44 -44
  17. data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +17 -17
  18. data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +20 -20
  19. data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +14 -14
  20. data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +80 -61
  21. data/locale/en.yml +253 -253
  22. data/spec/allow_mass_assignment_of_matcher_spec.rb +50 -50
  23. data/spec/allow_values_for_matcher_spec.rb +45 -45
  24. data/spec/association_matcher_spec.rb +612 -612
  25. data/spec/have_column_matcher_spec.rb +67 -67
  26. data/spec/have_index_matcher_spec.rb +61 -61
  27. data/spec/have_readonly_attributes_matcher_spec.rb +40 -40
  28. data/spec/have_scope_matcher_spec.rb +60 -60
  29. data/spec/model_builder.rb +101 -101
  30. data/spec/spec_helper.rb +25 -25
  31. data/spec/validate_acceptance_of_matcher_spec.rb +64 -64
  32. data/spec/validate_associated_matcher_spec.rb +118 -118
  33. data/spec/validate_confirmation_of_matcher_spec.rb +54 -54
  34. data/spec/validate_exclusion_of_matcher_spec.rb +76 -76
  35. data/spec/validate_inclusion_of_matcher_spec.rb +72 -72
  36. data/spec/validate_numericality_of_matcher_spec.rb +100 -100
  37. data/spec/validate_presence_of_matcher_spec.rb +40 -40
  38. data/spec/validate_uniqueness_of_matcher_spec.rb +158 -139
  39. metadata +3 -3
@@ -1,57 +1,57 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe 'allow_mass_assignment_of' do
3
+ describe 'allow_mass_assignment_of' do
4
4
  include ModelBuilder
5
-
6
- def define_and_validate(options={})
7
- @model = define_model :product, :title => :string, :category => :string do
8
- attr_protected :title, :category if options[:protected]
9
-
10
- attr_accessible :title, :category if options[:accessible] == true
11
- attr_accessible *options[:accessible] if options[:accessible].is_a?(Array)
12
- end
13
-
14
- allow_mass_assignment_of(:title, :category)
15
- end
16
-
17
- describe 'messages' do
18
-
19
- it 'should contain a description' do
20
- @matcher = allow_mass_assignment_of(:title, :category)
5
+
6
+ def define_and_validate(options={})
7
+ @model = define_model :product, :title => :string, :category => :string do
8
+ attr_protected :title, :category if options[:protected]
9
+
10
+ attr_accessible :title, :category if options[:accessible] == true
11
+ attr_accessible *options[:accessible] if options[:accessible].is_a?(Array)
12
+ end
13
+
14
+ allow_mass_assignment_of(:title, :category)
15
+ end
16
+
17
+ describe 'messages' do
18
+
19
+ it 'should contain a description' do
20
+ @matcher = allow_mass_assignment_of(:title, :category)
21
21
  @matcher.description.should == 'allow mass assignment of title and category'
22
22
  end
23
-
24
- it 'should set is_protected? message' do
25
- @matcher = define_and_validate(:protected => true)
26
- @matcher.matches?(@model)
27
- @matcher.failure_message.should == 'Expected Product to allow mass assignment of title (Product is protecting title)'
28
- end
29
-
30
- it 'should set is_accessible? message' do
31
- @matcher = define_and_validate(:accessible => [:another])
32
- @matcher.matches?(@model)
33
- @matcher.failure_message.should == 'Expected Product to allow mass assignment of title (Product has not made title accessible)'
34
- end
35
-
36
- end
37
-
38
- describe 'matchers' do
39
- it { should define_and_validate }
40
- it { should define_and_validate(:accessible => true) }
41
-
42
- it { should_not define_and_validate(:protected => true) }
43
- it { should_not define_and_validate(:accessible => [:another]) }
44
- end
45
-
46
- describe 'macros' do
47
- before(:each){ define_and_validate(:accessible => true) }
48
-
49
- should_allow_mass_assignment_of :title
50
- should_allow_mass_assignment_of :category
51
- should_allow_mass_assignment_of :title, :category
52
-
53
- should_not_allow_mass_assignment_of :another
54
- should_not_allow_mass_assignment_of :title, :another
23
+
24
+ it 'should set is_protected? message' do
25
+ @matcher = define_and_validate(:protected => true)
26
+ @matcher.matches?(@model)
27
+ @matcher.failure_message.should == 'Expected Product to allow mass assignment of title (Product is protecting title)'
28
+ end
29
+
30
+ it 'should set is_accessible? message' do
31
+ @matcher = define_and_validate(:accessible => [:another])
32
+ @matcher.matches?(@model)
33
+ @matcher.failure_message.should == 'Expected Product to allow mass assignment of title (Product has not made title accessible)'
34
+ end
35
+
36
+ end
37
+
38
+ describe 'matchers' do
39
+ it { should define_and_validate }
40
+ it { should define_and_validate(:accessible => true) }
41
+
42
+ it { should_not define_and_validate(:protected => true) }
43
+ it { should_not define_and_validate(:accessible => [:another]) }
44
+ end
45
+
46
+ describe 'macros' do
47
+ before(:each){ define_and_validate(:accessible => true) }
48
+
49
+ should_allow_mass_assignment_of :title
50
+ should_allow_mass_assignment_of :category
51
+ should_allow_mass_assignment_of :title, :category
52
+
53
+ should_not_allow_mass_assignment_of :another
54
+ should_not_allow_mass_assignment_of :title, :another
55
55
  end
56
56
  end
57
-
57
+
@@ -1,56 +1,56 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe 'allow_values_for' do
3
+ describe 'allow_values_for' do
4
4
  include ModelBuilder
5
-
6
- # Defines a model, create a validation and returns a raw matcher
7
- def define_and_validate(options={})
8
- @model = define_model :product, :title => :string, :category => :string do
9
- validates_format_of :title, options
10
- end
11
-
12
- allow_values_for(:title)
13
- end
14
-
15
- describe 'messages' do
16
- before(:each){ @matcher = define_and_validate(:with => /X|Y|Z/) }
17
-
18
- it 'should contain a description' do
19
- @matcher = allow_values_for(:title, "X", "Y", "Z")
5
+
6
+ # Defines a model, create a validation and returns a raw matcher
7
+ def define_and_validate(options={})
8
+ @model = define_model :product, :title => :string, :category => :string do
9
+ validates_format_of :title, options
10
+ end
11
+
12
+ allow_values_for(:title)
13
+ end
14
+
15
+ describe 'messages' do
16
+ before(:each){ @matcher = define_and_validate(:with => /X|Y|Z/) }
17
+
18
+ it 'should contain a description' do
19
+ @matcher = allow_values_for(:title, "X", "Y", "Z")
20
20
  @matcher.description.should == 'allow "X", "Y", and "Z" as values for title'
21
21
  end
22
-
23
- it 'should set is_valid? message' do
22
+
23
+ it 'should set is_valid? message' do
24
24
  @matcher.in("A").matches?(@model)
25
- @matcher.failure_message.should == 'Expected Product to be valid when title is set to "A"'
26
- end
25
+ @matcher.failure_message.should == 'Expected Product to be valid when title is set to "A"'
26
+ end
27
27
 
28
- it 'should set allow_nil? message' do
28
+ it 'should set allow_nil? message' do
29
29
  @matcher.allow_nil.matches?(@model)
30
- @matcher.failure_message.should == 'Expected Product to allow nil values for title'
31
- end
32
-
33
- it 'should set allow_blank? message' do
30
+ @matcher.failure_message.should == 'Expected Product to allow nil values for title'
31
+ end
32
+
33
+ it 'should set allow_blank? message' do
34
34
  @matcher.allow_blank.matches?(@model)
35
- @matcher.failure_message.should == 'Expected Product to allow blank values for title'
36
- end
37
- end
38
-
39
- describe 'matchers' do
40
- it { should define_and_validate(:with => /X|Y|Z/).in('X', 'Y', 'Z') }
41
- it { should_not define_and_validate(:with => /X|Y|Z/).in('A') }
42
-
43
- it { should define_and_validate(:with => /X|Y|Z/, :message => 'valid').in('X', 'Y', 'Z').message('valid') }
44
-
45
- create_optional_boolean_specs(:allow_nil, self, :with => /X|Y|Z/)
46
- create_optional_boolean_specs(:allow_blank, self, :with => /X|Y|Z/)
47
- end
48
-
49
- describe 'macros' do
50
- before(:each){ define_and_validate(:with => /X|Y|Z/) }
51
-
52
- should_allow_values_for :title, 'X'
53
- should_not_allow_values_for :title, 'A'
35
+ @matcher.failure_message.should == 'Expected Product to allow blank values for title'
36
+ end
37
+ end
38
+
39
+ describe 'matchers' do
40
+ it { should define_and_validate(:with => /X|Y|Z/).in('X', 'Y', 'Z') }
41
+ it { should_not define_and_validate(:with => /X|Y|Z/).in('A') }
42
+
43
+ it { should define_and_validate(:with => /X|Y|Z/, :message => 'valid').in('X', 'Y', 'Z').message('valid') }
44
+
45
+ create_optional_boolean_specs(:allow_nil, self, :with => /X|Y|Z/)
46
+ create_optional_boolean_specs(:allow_blank, self, :with => /X|Y|Z/)
47
+ end
48
+
49
+ describe 'macros' do
50
+ before(:each){ define_and_validate(:with => /X|Y|Z/) }
51
+
52
+ should_allow_values_for :title, 'X'
53
+ should_not_allow_values_for :title, 'A'
54
54
  end
55
55
  end
56
-
56
+
@@ -1,616 +1,616 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe 'association_matcher' do
3
+ describe 'association_matcher' do
4
4
  include ModelBuilder
5
-
6
- describe 'belong_to' do
7
-
8
- # Defines a model, create a validation and returns a raw matcher
9
- def define_and_validate(options={})
10
- columns = options.delete(:association_columns) || { :projects_count => :integer }
11
- define_model :company, columns
12
-
13
- columns = options.delete(:model_columns) || { :company_id => :integer, :company_type => :string }
14
- @model = define_model :project, columns do
15
- belongs_to :company, options
16
- end
17
-
18
- belong_to :company
19
- end
20
-
21
- describe 'messages' do
22
- it 'should contain a description' do
23
- matcher = define_and_validate
24
- matcher.description.should == 'belong to company'
25
-
26
- matcher.class_name('Company')
27
- matcher.description.should == 'belong to company with class name "Company"'
28
-
29
- matcher.foreign_key('company_id')
30
- matcher.description.should == 'belong to company with class name "Company" and with foreign key "company_id"'
31
-
32
- matcher = belong_to(:company).dependent(:destroy)
33
- matcher.description.should == 'belong to company with dependent :destroy'
34
-
35
- matcher.readonly
36
- matcher.description.should == 'belong to company with dependent :destroy and with readonly records'
37
-
38
- matcher.polymorphic
39
- matcher.description.should == 'belong to company with dependent :destroy, with readonly records, ' <<
40
- 'and through a polymorphic interface'
41
-
42
- matcher.counter_cache('projects_count')
43
- matcher.description.should == 'belong to company with dependent :destroy, with readonly records, ' <<
44
- 'through a polymorphic interface, and with counter cache "projects_count"'
45
- end
46
-
47
- it 'should set association_exists? message' do
48
- define_and_validate
49
- matcher = belong_to('whatever')
50
- matcher.matches?(@model)
51
- matcher.failure_message.should == 'Expected Project records belong to whatever, got no association'
52
- end
53
-
54
- it 'should set macro_matches? message' do
55
- define_and_validate
56
- matcher = have_one('company')
57
- matcher.matches?(@model)
58
- matcher.failure_message.should == 'Expected Project records have one company, got Project records belong to company'
59
- end
60
-
61
- it 'should set foreign_key_exists? message' do
62
- matcher = define_and_validate(:model_columns => {})
63
- matcher.matches?(@model)
64
- matcher.failure_message.should == 'Expected foreign key "company_id" to exist on "projects", but does not'
65
- end
66
-
67
- it 'should set polymorphic_exists? message' do
68
- matcher = define_and_validate(:model_columns => { :company_id => :integer }, :polymorphic => true)
69
- matcher.polymorphic.matches?(@model)
70
- matcher.failure_message.should == 'Expected "projects" to have "company_type" as column, but does not'
71
- end
72
-
73
- it 'should set counter_cache_exists? message' do
74
- matcher = define_and_validate(:association_columns => {}, :counter_cache => true)
75
- matcher.counter_cache.matches?(@model)
76
- matcher.failure_message.should == 'Expected "companies" to have "projects_count" as column, but does not'
77
- end
78
-
79
- it 'should set validate_matches? message' do
80
- matcher = define_and_validate(:validate => false)
81
- matcher.validate.matches?(@model)
82
- matcher.failure_message.should == 'Expected company association with validate equals to true, got "false"'
83
- end
84
-
85
- it 'should set readonly_matches? message' do
86
- matcher = define_and_validate(:readonly => false)
87
- matcher.readonly.matches?(@model)
88
- matcher.failure_message.should == 'Expected company association with readonly equals to true, got "false"'
89
- end
90
-
91
- if RAILS_VERSION =~ /^2.3/
92
- it 'should set autosave_matches? message' do
93
- matcher = define_and_validate(:autosave => false)
94
- matcher.autosave.matches?(@model)
95
- matcher.failure_message.should == 'Expected company association with autosave equals to true, got "false"'
96
- end
97
- end
98
-
99
- it 'should set polymorphic_matches? message' do
100
- matcher = define_and_validate(:polymorphic => false)
101
- matcher.polymorphic.matches?(@model)
102
- matcher.failure_message.should == 'Expected company association with polymorphic equals to true, got "false"'
103
- end
104
-
105
- it 'should set counter_cache_matches? message' do
106
- matcher = define_and_validate(:counter_cache => true)
107
- matcher.counter_cache(false).matches?(@model)
108
- matcher.failure_message.should == 'Expected company association with counter cache false, got "true"'
109
- end
110
- end
111
-
112
- describe 'matchers' do
113
- describe 'without options' do
114
- before(:each){ define_and_validate }
115
-
116
- it { should belong_to(:company) }
117
- it { should_not belong_to(:project) }
118
- it { should_not have_one(:company) }
119
- it { should_not have_many(:company) }
120
- end
121
-
122
- describe 'with class name option' do
123
- it { should define_and_validate.class_name('Company') }
124
- it { should define_and_validate(:class_name => 'SuperCompany').class_name('SuperCompany') }
125
-
126
- it { should_not define_and_validate.class_name('SuperCompany') }
127
- it { should_not define_and_validate(:class_name => 'Company').class_name('SuperCompany') }
128
- end
129
-
130
- describe 'with foreign_key option' do
131
- it { should define_and_validate.foreign_key(:company_id) }
132
- it { should_not define_and_validate.foreign_key(:association_id) }
133
-
134
- # Checks whether fk exists or not
135
- it { should define_and_validate(:foreign_key => :association_id,
136
- :model_columns => { :association_id => :integer }).foreign_key(:association_id) }
137
-
138
- it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
139
- it { should_not define_and_validate(:model_columns => { :association_id => :integer }).foreign_key(:association_id) }
140
- end
141
-
142
- describe 'with dependent option' do
143
- it { should define_and_validate(:dependent => :delete).dependent(:delete) }
144
- it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
145
-
146
- it { should_not define_and_validate(:dependent => :delete).dependent(:destroy) }
147
- it { should_not define_and_validate(:dependent => :destroy).dependent(:delete) }
148
- end
149
-
150
- describe 'with counter_cache option' do
151
- # Checks whether fk exists or not
152
- it { should define_and_validate(:counter_cache => :association_count,
153
- :association_columns => { :association_count => :integer }).counter_cache(:association_count) }
154
-
155
- it { should_not define_and_validate(:counter_cache => :association_count).counter_cache(:association_count) }
156
- it { should_not define_and_validate(:association_columns => { :association_count => :integer }).counter_cache(:association_count) }
157
- end
158
-
159
- create_optional_boolean_specs(:readonly, self)
160
- create_optional_boolean_specs(:validate, self)
161
- create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
162
- create_optional_boolean_specs(:polymorphic, self)
163
- create_optional_boolean_specs(:counter_cache, self)
164
- end
165
-
166
- describe 'macros' do
167
- before(:each){ define_and_validate(:validate => true, :readonly => true) }
168
-
169
- should_belong_to :company
170
- should_belong_to :company, :readonly => true
171
- should_belong_to :company, :validate => true
172
- should_belong_to :company, :class_name => "Company"
173
- should_belong_to :company, :foreign_key => :company_id
174
-
175
- should_not_belong_to :project
176
- should_not_have_one :company
177
- should_not_have_many :companies
178
-
179
- should_not_belong_to :company, :readonly => false
180
- should_not_belong_to :company, :validate => false
181
- should_not_belong_to :company, :class_name => "Anything"
182
- should_not_belong_to :company, :foreign_key => :anything_id
183
- end
184
- end
185
-
186
- describe 'have_and_belong_to_many' do
187
-
188
- # Defines a model, create a validation and returns a raw matcher
189
- def define_and_validate(options={})
190
- define_model :label
191
-
192
- columns = options.delete(:association_columns) || [ :label_id, :project_id ]
193
- create_table(options.delete(:association_table) || :labels_projects) do |table|
194
- columns.each { |name| table.column(name, :integer) }
195
- end
196
-
197
- @model = define_model :project, options.delete(:model_columns) || {} do
198
- has_and_belongs_to_many :labels, options
199
- end
200
-
201
- have_and_belong_to_many :labels
202
- end
203
-
204
- describe 'messages' do
205
- it 'should contain a description' do
206
- matcher = define_and_validate
207
- matcher.description.should == 'have and belong to many labels'
208
-
209
- matcher.class_name('Label')
210
- matcher.description.should == 'have and belong to many labels with class name "Label"'
211
-
212
- matcher.foreign_key('label_id')
213
- matcher.description.should == 'have and belong to many labels with class name "Label" and with foreign key "label_id"'
214
-
215
- matcher = have_and_belong_to_many(:labels).autosave
216
- matcher.description.should == 'have and belong to many labels autosaving associated records'
217
-
218
- matcher.uniq
219
- matcher.description.should == 'have and belong to many labels with unique records and autosaving associated records'
220
- end
221
-
222
- it 'should set association_exists? message' do
223
- define_and_validate
224
- matcher = have_and_belong_to_many('whatever')
225
- matcher.matches?(@model)
226
- matcher.failure_message.should == 'Expected Project records have and belong to many whatever, got no association'
227
- end
228
-
229
- it 'should set macro_matches? message' do
230
- define_and_validate
231
- matcher = have_many('labels')
232
- matcher.matches?(@model)
233
- matcher.failure_message.should == 'Expected Project records have many labels, got Project records have and belong to many labels'
234
- end
235
-
236
- it 'should set join_table_exists? message' do
237
- matcher = define_and_validate(:association_table => 'another_name')
238
- matcher.matches?(@model)
239
- matcher.failure_message.should == 'Expected join table "labels_projects" to exist, but does not'
240
- end
241
-
242
- it 'should set foreign_key_exists? message' do
243
- matcher = define_and_validate(:association_columns => [])
244
- matcher.matches?(@model)
245
- matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "labels_projects", but does not'
246
- end
247
-
248
- it 'should set validate_matches? message' do
249
- matcher = define_and_validate(:validate => false)
250
- matcher.validate.matches?(@model)
251
- matcher.failure_message.should == 'Expected labels association with validate equals to true, got "false"'
252
- end
253
-
254
- it 'should set readonly_matches? message' do
255
- matcher = define_and_validate(:readonly => false)
256
- matcher.readonly.matches?(@model)
257
- matcher.failure_message.should == 'Expected labels association with readonly equals to true, got "false"'
258
- end
259
-
260
- if RAILS_VERSION =~ /^2.3/
261
- it 'should set autosave_matches? message' do
262
- matcher = define_and_validate(:autosave => false)
263
- matcher.autosave.matches?(@model)
264
- matcher.failure_message.should == 'Expected labels association with autosave equals to true, got "false"'
265
- end
266
- end
267
-
268
- it 'should set uniq_matches? message' do
269
- matcher = define_and_validate(:uniq => false)
270
- matcher.uniq.matches?(@model)
271
- matcher.failure_message.should == 'Expected labels association with uniq equals to true, got "false"'
272
- end
273
- end
274
-
275
- describe 'matchers' do
276
- describe 'without options' do
277
- before(:each){ define_and_validate }
278
-
279
- it { should have_and_belong_to_many(:labels) }
280
- it { should_not belong_to(:label) }
281
- it { should_not have_one(:label) }
282
- it { should_not have_many(:labels) }
283
- it { should_not have_and_belong_to_many(:companies) }
284
- end
285
-
286
- describe 'with class name option' do
287
- it { should define_and_validate.class_name('Label') }
288
-
289
- it { should define_and_validate(:class_name => 'SuperLabel',
290
- :association_table => 'projects_super_labels').class_name('SuperLabel') }
291
-
292
- it { should_not define_and_validate.class_name('SuperLabel') }
293
- end
294
-
295
- describe 'with foreign_key option' do
296
- it { should define_and_validate.foreign_key(:project_id) }
297
- it { should_not define_and_validate.foreign_key(:association_id) }
298
-
299
- # Checks whether fk exists or not
300
- it { should define_and_validate(:foreign_key => :association_id,
301
- :association_columns => [ :association_id ]).foreign_key(:association_id) }
302
-
303
- it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
304
- it { should_not define_and_validate(:association_columns => [ :association_id ]).foreign_key(:association_id) }
305
- end
306
-
307
- describe 'with join table option' do
308
- it { should define_and_validate.join_table('labels_projects') }
309
- it { should define_and_validate(:join_table => 'my_table',
310
- :association_table => 'my_table').join_table('my_table') }
311
-
312
- it { should_not define_and_validate.join_table('projects_labels') }
313
-
314
- it { should_not define_and_validate(:join_table => 'my_table',
315
- :association_table => 'another_table').join_table('my_table') }
316
- it { should_not define_and_validate(:join_table => 'another_table',
317
- :association_table => 'my_table').join_table('my_table') }
318
- it { should_not define_and_validate(:join_table => 'my_table',
319
- :association_table => 'my_table').join_table('another_table') }
320
- end
321
-
322
- create_optional_boolean_specs(:uniq, self)
323
- create_optional_boolean_specs(:readonly, self)
324
- create_optional_boolean_specs(:validate, self)
325
- create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
326
- end
327
-
328
- describe 'macros' do
329
- before(:each){ define_and_validate(:validate => true, :readonly => true) }
330
-
331
- should_have_and_belong_to_many :labels
332
- should_have_and_belong_to_many :labels, :readonly => true
333
- should_have_and_belong_to_many :labels, :validate => true
334
- should_have_and_belong_to_many :labels, :class_name => "Label"
335
- should_have_and_belong_to_many :labels, :foreign_key => :project_id
336
-
337
- should_not_have_and_belong_to_many :companies
338
- should_not_have_one :label
339
- should_not_have_many :labels
340
-
341
- should_not_have_and_belong_to_many :labels, :readonly => false
342
- should_not_have_and_belong_to_many :labels, :validate => false
343
- should_not_have_and_belong_to_many :labels, :class_name => "Anything"
344
- should_not_have_and_belong_to_many :labels, :foreign_key => :anything_id
345
- end
346
- end
347
-
348
- describe 'have_many' do
349
-
350
- # Defines a model, create a validation and returns a raw matcher
351
- def define_and_validate(options={})
352
- columns = options.delete(:association_columns) || { :task_id => :integer, :project_id => :integer }
353
- define_model :task, columns
354
-
355
- define_model :project_task, columns do
356
- belongs_to :task
357
- belongs_to :project
358
- end unless options.delete(:skip_through)
359
-
360
- @model = define_model :project, options.delete(:model_columns) || {} do
361
- has_many :tasks, options
362
- has_many :project_tasks
363
- end
364
-
365
- have_many :tasks
366
- end
367
-
368
- describe 'messages' do
369
- it 'should contain a description' do
370
- matcher = define_and_validate
371
- matcher.description.should == 'have many tasks'
372
-
373
- matcher.class_name('Task')
374
- matcher.description.should == 'have many tasks with class name "Task"'
375
-
376
- matcher.foreign_key('task_id')
377
- matcher.description.should == 'have many tasks with class name "Task" and with foreign key "task_id"'
378
-
379
- matcher = have_many(:tasks).autosave
380
- matcher.description.should == 'have many tasks autosaving associated records'
381
-
382
- matcher.uniq
383
- matcher.description.should == 'have many tasks with unique records and autosaving associated records'
384
- end
385
-
386
- it 'should set association_exists? message' do
387
- define_and_validate
388
- matcher = have_many('whatever')
389
- matcher.matches?(@model)
390
- matcher.failure_message.should == 'Expected Project records have many whatever, got no association'
391
- end
392
-
393
- it 'should set macro_matches? message' do
394
- define_and_validate
395
- matcher = have_and_belong_to_many('tasks')
396
- matcher.matches?(@model)
397
- matcher.failure_message.should == 'Expected Project records have and belong to many tasks, got Project records have many tasks'
398
- end
399
-
400
- it 'should set foreign_key_exists? message' do
401
- matcher = define_and_validate(:association_columns => {})
402
- matcher.matches?(@model)
403
- matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "tasks", but does not'
404
- end
405
-
406
- it 'should set through_exists? message' do
407
- matcher = define_and_validate(:through => 'project_tasks')
408
- matcher.through(:another).matches?(@model)
409
- matcher.failure_message.should == 'Expected Project records have many tasks through :another, through association does not exist'
410
- end
411
-
412
- it 'should set join_table_exists? message' do
413
- matcher = define_and_validate(:through => 'project_tasks', :skip_through => true)
414
- matcher.through(:project_tasks).matches?(@model)
415
- matcher.failure_message.should == 'Expected join table "project_tasks" to exist, but does not'
416
- end
417
- end
418
-
419
- describe 'matchers' do
420
- describe 'without options' do
421
- before(:each){ define_and_validate }
422
-
423
- it { should have_many(:tasks) }
424
- it { should_not belong_to(:task) }
425
- it { should_not have_one(:task) }
426
- it { should_not have_and_belong_to_many(:tasks) }
427
- end
428
-
429
- describe 'with class name option' do
430
- before(:each){ define_model :super_task, :project_id => :integer }
431
-
432
- it { should define_and_validate.class_name('Task') }
433
- it { should define_and_validate(:class_name => 'SuperTask').class_name('SuperTask') }
434
-
435
- it { should_not define_and_validate.class_name('SuperTask') }
436
- it { should_not define_and_validate(:class_name => 'SuperTask').class_name('Task') }
437
- end
438
-
439
- describe 'with foreign_key option' do
440
- it { should define_and_validate.foreign_key(:project_id) }
441
- it { should_not define_and_validate.foreign_key(:association_id) }
442
-
443
- # Checks whether fk exists or not
444
- it { should define_and_validate(:foreign_key => :association_id,
445
- :association_columns => { :association_id => :integer }).foreign_key(:association_id) }
446
-
447
- it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
448
- it { should_not define_and_validate(:association_columns => { :association_id => :integer }).foreign_key(:association_id) }
449
- end
450
-
451
- describe 'with dependent option' do
452
- it { should define_and_validate(:dependent => :delete_all).dependent(:delete_all) }
453
- it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
454
-
455
- it { should_not define_and_validate(:dependent => :delete_all).dependent(:destroy) }
456
- it { should_not define_and_validate(:dependent => :destroy).dependent(:delete_all) }
457
- end
458
-
459
- describe 'with through option' do
460
- it { should define_and_validate(:through => 'project_tasks') }
461
- it { should define_and_validate(:through => 'project_tasks').through(:project_tasks) }
462
-
463
- it { should_not define_and_validate(:through => 'project_tasks').through(:something) }
464
- it { should_not define_and_validate(:through => 'project_tasks', :skip_through => true).through(:project_tasks) }
465
- end
466
-
467
- create_optional_boolean_specs(:uniq, self)
468
- create_optional_boolean_specs(:readonly, self)
469
- create_optional_boolean_specs(:validate, self)
470
- create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
471
- end
472
-
473
- describe 'macros' do
474
- before(:each){ define_and_validate(:through => 'project_tasks', :readonly => true, :validate => true) }
475
-
476
- should_have_many :tasks
477
- should_have_many :tasks, :readonly => true
478
- should_have_many :tasks, :validate => true
479
- should_have_many :tasks, :through => :project_tasks
480
-
481
- should_not_have_many :tasks, :readonly => false
482
- should_not_have_many :tasks, :validate => false
483
- should_not_have_many :tasks, :through => :another_thing
484
- end
485
- end
486
-
487
- describe 'have_one' do
488
-
489
- # Defines a model, create a validation and returns a raw matcher
490
- def define_and_validate(options={})
491
- columns = options.delete(:association_columns) || { :manager_id => :integer, :project_id => :integer }
492
- define_model :manager, columns
493
-
494
- define_model :project_manager, columns do
495
- belongs_to :manager
496
- belongs_to :project
497
- end unless options.delete(:skip_through)
498
-
499
- @model = define_model :project, options.delete(:model_columns) || {} do
500
- has_one :manager, options
501
- has_many :project_managers
502
- end
503
-
504
- have_one :manager
505
- end
506
-
507
- describe 'messages' do
508
- it 'should contain a description' do
509
- matcher = define_and_validate
510
- matcher.description.should == 'have one manager'
511
-
512
- matcher.class_name('Manager')
513
- matcher.description.should == 'have one manager with class name "Manager"'
514
-
515
- matcher.foreign_key('manager_id')
516
- matcher.description.should == 'have one manager with class name "Manager" and with foreign key "manager_id"'
517
- end
518
-
519
- it 'should set association_exists? message' do
520
- define_and_validate
521
- matcher = have_one('whatever')
522
- matcher.matches?(@model)
523
- matcher.failure_message.should == 'Expected Project records have one whatever, got no association'
524
- end
525
-
526
- it 'should set macro_matches? message' do
527
- define_and_validate
528
- matcher = belong_to('manager')
529
- matcher.matches?(@model)
530
- matcher.failure_message.should == 'Expected Project records belong to manager, got Project records have one manager'
531
- end
532
-
533
- it 'should set foreign_key_exists? message' do
534
- matcher = define_and_validate(:association_columns => {})
535
- matcher.matches?(@model)
536
- matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "managers", but does not'
537
- end
538
-
539
- it 'should set through_exists? message' do
540
- matcher = define_and_validate(:through => 'project_managers')
541
- matcher.through(:another).matches?(@model)
542
- matcher.failure_message.should == 'Expected Project records have one manager through :another, through association does not exist'
543
- end
544
-
545
- it 'should set join_table_exists? message' do
546
- matcher = define_and_validate(:through => 'project_managers', :skip_through => true)
547
- matcher.through(:project_managers).matches?(@model)
548
- matcher.failure_message.should == 'Expected join table "project_managers" to exist, but does not'
549
- end
550
- end
551
-
552
- describe 'matchers' do
553
- describe 'without options' do
554
- before(:each){ define_and_validate }
555
-
556
- it { should have_one(:manager) }
557
- it { should_not belong_to(:manager) }
558
- it { should_not have_many(:managers) }
559
- it { should_not have_and_belong_to_many(:managers) }
560
- end
561
-
562
- describe 'with class name option' do
563
- before(:each){ define_model :super_manager, :project_id => :integer }
564
-
565
- it { should define_and_validate.class_name('Manager') }
566
- it { should define_and_validate(:class_name => 'SuperManager').class_name('SuperManager') }
567
-
568
- it { should_not define_and_validate.class_name('SuperManager') }
569
- it { should_not define_and_validate(:class_name => 'SuperManager').class_name('Manager') }
570
- end
571
-
572
- describe 'with foreign_key option' do
573
- it { should define_and_validate.foreign_key(:project_id) }
574
- it { should_not define_and_validate.foreign_key(:association_id) }
575
-
576
- # Checks whether fk exists or not
577
- it { should define_and_validate(:foreign_key => :association_id,
578
- :association_columns => { :association_id => :integer }).foreign_key(:association_id) }
579
-
580
- it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
581
- it { should_not define_and_validate(:association_columns => { :association_id => :integer }).foreign_key(:association_id) }
582
- end
583
-
584
- describe 'with dependent option' do
585
- it { should define_and_validate(:dependent => :delete).dependent(:delete) }
586
- it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
587
-
588
- it { should_not define_and_validate(:dependent => :delete).dependent(:destroy) }
589
- it { should_not define_and_validate(:dependent => :destroy).dependent(:delete) }
590
- end
591
-
592
- describe 'with through option' do
593
- it { should define_and_validate(:through => 'project_managers') }
594
- it { should define_and_validate(:through => 'project_managers').through(:project_managers) }
595
-
596
- it { should_not define_and_validate(:through => 'project_managers').through(:something) }
597
- it { should_not define_and_validate(:through => 'project_managers', :skip_through => true).through(:project_managers) }
598
- end
599
-
600
- create_optional_boolean_specs(:validate, self)
601
- create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
602
- end
603
-
604
- describe 'macros' do
605
- before(:each){ define_and_validate(:through => 'project_managers', :validate => true) }
606
-
607
- should_have_one :manager
608
- should_have_one :manager, :validate => true
609
- should_have_one :manager, :through => :project_managers
610
-
611
- should_not_have_one :manager, :validate => false
612
- should_not_have_one :manager, :through => :another_thing
613
- end
614
- end
615
-
5
+
6
+ describe 'belong_to' do
7
+
8
+ # Defines a model, create a validation and returns a raw matcher
9
+ def define_and_validate(options={})
10
+ columns = options.delete(:association_columns) || { :projects_count => :integer }
11
+ define_model :company, columns
12
+
13
+ columns = options.delete(:model_columns) || { :company_id => :integer, :company_type => :string }
14
+ @model = define_model :project, columns do
15
+ belongs_to :company, options
16
+ end
17
+
18
+ belong_to :company
19
+ end
20
+
21
+ describe 'messages' do
22
+ it 'should contain a description' do
23
+ matcher = define_and_validate
24
+ matcher.description.should == 'belong to company'
25
+
26
+ matcher.class_name('Company')
27
+ matcher.description.should == 'belong to company with class name "Company"'
28
+
29
+ matcher.foreign_key('company_id')
30
+ matcher.description.should == 'belong to company with class name "Company" and with foreign key "company_id"'
31
+
32
+ matcher = belong_to(:company).dependent(:destroy)
33
+ matcher.description.should == 'belong to company with dependent :destroy'
34
+
35
+ matcher.readonly
36
+ matcher.description.should == 'belong to company with dependent :destroy and with readonly records'
37
+
38
+ matcher.polymorphic
39
+ matcher.description.should == 'belong to company with dependent :destroy, with readonly records, ' <<
40
+ 'and through a polymorphic interface'
41
+
42
+ matcher.counter_cache('projects_count')
43
+ matcher.description.should == 'belong to company with dependent :destroy, with readonly records, ' <<
44
+ 'through a polymorphic interface, and with counter cache "projects_count"'
45
+ end
46
+
47
+ it 'should set association_exists? message' do
48
+ define_and_validate
49
+ matcher = belong_to('whatever')
50
+ matcher.matches?(@model)
51
+ matcher.failure_message.should == 'Expected Project records belong to whatever, got no association'
52
+ end
53
+
54
+ it 'should set macro_matches? message' do
55
+ define_and_validate
56
+ matcher = have_one('company')
57
+ matcher.matches?(@model)
58
+ matcher.failure_message.should == 'Expected Project records have one company, got Project records belong to company'
59
+ end
60
+
61
+ it 'should set foreign_key_exists? message' do
62
+ matcher = define_and_validate(:model_columns => {})
63
+ matcher.matches?(@model)
64
+ matcher.failure_message.should == 'Expected foreign key "company_id" to exist on "projects", but does not'
65
+ end
66
+
67
+ it 'should set polymorphic_exists? message' do
68
+ matcher = define_and_validate(:model_columns => { :company_id => :integer }, :polymorphic => true)
69
+ matcher.polymorphic.matches?(@model)
70
+ matcher.failure_message.should == 'Expected "projects" to have "company_type" as column, but does not'
71
+ end
72
+
73
+ it 'should set counter_cache_exists? message' do
74
+ matcher = define_and_validate(:association_columns => {}, :counter_cache => true)
75
+ matcher.counter_cache.matches?(@model)
76
+ matcher.failure_message.should == 'Expected "companies" to have "projects_count" as column, but does not'
77
+ end
78
+
79
+ it 'should set validate_matches? message' do
80
+ matcher = define_and_validate(:validate => false)
81
+ matcher.validate.matches?(@model)
82
+ matcher.failure_message.should == 'Expected company association with validate equals to true, got "false"'
83
+ end
84
+
85
+ it 'should set readonly_matches? message' do
86
+ matcher = define_and_validate(:readonly => false)
87
+ matcher.readonly.matches?(@model)
88
+ matcher.failure_message.should == 'Expected company association with readonly equals to true, got "false"'
89
+ end
90
+
91
+ if RAILS_VERSION =~ /^2.3/
92
+ it 'should set autosave_matches? message' do
93
+ matcher = define_and_validate(:autosave => false)
94
+ matcher.autosave.matches?(@model)
95
+ matcher.failure_message.should == 'Expected company association with autosave equals to true, got "false"'
96
+ end
97
+ end
98
+
99
+ it 'should set polymorphic_matches? message' do
100
+ matcher = define_and_validate(:polymorphic => false)
101
+ matcher.polymorphic.matches?(@model)
102
+ matcher.failure_message.should == 'Expected company association with polymorphic equals to true, got "false"'
103
+ end
104
+
105
+ it 'should set counter_cache_matches? message' do
106
+ matcher = define_and_validate(:counter_cache => true)
107
+ matcher.counter_cache(false).matches?(@model)
108
+ matcher.failure_message.should == 'Expected company association with counter cache false, got "true"'
109
+ end
110
+ end
111
+
112
+ describe 'matchers' do
113
+ describe 'without options' do
114
+ before(:each){ define_and_validate }
115
+
116
+ it { should belong_to(:company) }
117
+ it { should_not belong_to(:project) }
118
+ it { should_not have_one(:company) }
119
+ it { should_not have_many(:company) }
120
+ end
121
+
122
+ describe 'with class name option' do
123
+ it { should define_and_validate.class_name('Company') }
124
+ it { should define_and_validate(:class_name => 'SuperCompany').class_name('SuperCompany') }
125
+
126
+ it { should_not define_and_validate.class_name('SuperCompany') }
127
+ it { should_not define_and_validate(:class_name => 'Company').class_name('SuperCompany') }
128
+ end
129
+
130
+ describe 'with foreign_key option' do
131
+ it { should define_and_validate.foreign_key(:company_id) }
132
+ it { should_not define_and_validate.foreign_key(:association_id) }
133
+
134
+ # Checks whether fk exists or not
135
+ it { should define_and_validate(:foreign_key => :association_id,
136
+ :model_columns => { :association_id => :integer }).foreign_key(:association_id) }
137
+
138
+ it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
139
+ it { should_not define_and_validate(:model_columns => { :association_id => :integer }).foreign_key(:association_id) }
140
+ end
141
+
142
+ describe 'with dependent option' do
143
+ it { should define_and_validate(:dependent => :delete).dependent(:delete) }
144
+ it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
145
+
146
+ it { should_not define_and_validate(:dependent => :delete).dependent(:destroy) }
147
+ it { should_not define_and_validate(:dependent => :destroy).dependent(:delete) }
148
+ end
149
+
150
+ describe 'with counter_cache option' do
151
+ # Checks whether fk exists or not
152
+ it { should define_and_validate(:counter_cache => :association_count,
153
+ :association_columns => { :association_count => :integer }).counter_cache(:association_count) }
154
+
155
+ it { should_not define_and_validate(:counter_cache => :association_count).counter_cache(:association_count) }
156
+ it { should_not define_and_validate(:association_columns => { :association_count => :integer }).counter_cache(:association_count) }
157
+ end
158
+
159
+ create_optional_boolean_specs(:readonly, self)
160
+ create_optional_boolean_specs(:validate, self)
161
+ create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
162
+ create_optional_boolean_specs(:polymorphic, self)
163
+ create_optional_boolean_specs(:counter_cache, self)
164
+ end
165
+
166
+ describe 'macros' do
167
+ before(:each){ define_and_validate(:validate => true, :readonly => true) }
168
+
169
+ should_belong_to :company
170
+ should_belong_to :company, :readonly => true
171
+ should_belong_to :company, :validate => true
172
+ should_belong_to :company, :class_name => "Company"
173
+ should_belong_to :company, :foreign_key => :company_id
174
+
175
+ should_not_belong_to :project
176
+ should_not_have_one :company
177
+ should_not_have_many :companies
178
+
179
+ should_not_belong_to :company, :readonly => false
180
+ should_not_belong_to :company, :validate => false
181
+ should_not_belong_to :company, :class_name => "Anything"
182
+ should_not_belong_to :company, :foreign_key => :anything_id
183
+ end
184
+ end
185
+
186
+ describe 'have_and_belong_to_many' do
187
+
188
+ # Defines a model, create a validation and returns a raw matcher
189
+ def define_and_validate(options={})
190
+ define_model :label
191
+
192
+ columns = options.delete(:association_columns) || [ :label_id, :project_id ]
193
+ create_table(options.delete(:association_table) || :labels_projects) do |table|
194
+ columns.each { |name| table.column(name, :integer) }
195
+ end
196
+
197
+ @model = define_model :project, options.delete(:model_columns) || {} do
198
+ has_and_belongs_to_many :labels, options
199
+ end
200
+
201
+ have_and_belong_to_many :labels
202
+ end
203
+
204
+ describe 'messages' do
205
+ it 'should contain a description' do
206
+ matcher = define_and_validate
207
+ matcher.description.should == 'have and belong to many labels'
208
+
209
+ matcher.class_name('Label')
210
+ matcher.description.should == 'have and belong to many labels with class name "Label"'
211
+
212
+ matcher.foreign_key('label_id')
213
+ matcher.description.should == 'have and belong to many labels with class name "Label" and with foreign key "label_id"'
214
+
215
+ matcher = have_and_belong_to_many(:labels).autosave
216
+ matcher.description.should == 'have and belong to many labels autosaving associated records'
217
+
218
+ matcher.uniq
219
+ matcher.description.should == 'have and belong to many labels with unique records and autosaving associated records'
220
+ end
221
+
222
+ it 'should set association_exists? message' do
223
+ define_and_validate
224
+ matcher = have_and_belong_to_many('whatever')
225
+ matcher.matches?(@model)
226
+ matcher.failure_message.should == 'Expected Project records have and belong to many whatever, got no association'
227
+ end
228
+
229
+ it 'should set macro_matches? message' do
230
+ define_and_validate
231
+ matcher = have_many('labels')
232
+ matcher.matches?(@model)
233
+ matcher.failure_message.should == 'Expected Project records have many labels, got Project records have and belong to many labels'
234
+ end
235
+
236
+ it 'should set join_table_exists? message' do
237
+ matcher = define_and_validate(:association_table => 'another_name')
238
+ matcher.matches?(@model)
239
+ matcher.failure_message.should == 'Expected join table "labels_projects" to exist, but does not'
240
+ end
241
+
242
+ it 'should set foreign_key_exists? message' do
243
+ matcher = define_and_validate(:association_columns => [])
244
+ matcher.matches?(@model)
245
+ matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "labels_projects", but does not'
246
+ end
247
+
248
+ it 'should set validate_matches? message' do
249
+ matcher = define_and_validate(:validate => false)
250
+ matcher.validate.matches?(@model)
251
+ matcher.failure_message.should == 'Expected labels association with validate equals to true, got "false"'
252
+ end
253
+
254
+ it 'should set readonly_matches? message' do
255
+ matcher = define_and_validate(:readonly => false)
256
+ matcher.readonly.matches?(@model)
257
+ matcher.failure_message.should == 'Expected labels association with readonly equals to true, got "false"'
258
+ end
259
+
260
+ if RAILS_VERSION =~ /^2.3/
261
+ it 'should set autosave_matches? message' do
262
+ matcher = define_and_validate(:autosave => false)
263
+ matcher.autosave.matches?(@model)
264
+ matcher.failure_message.should == 'Expected labels association with autosave equals to true, got "false"'
265
+ end
266
+ end
267
+
268
+ it 'should set uniq_matches? message' do
269
+ matcher = define_and_validate(:uniq => false)
270
+ matcher.uniq.matches?(@model)
271
+ matcher.failure_message.should == 'Expected labels association with uniq equals to true, got "false"'
272
+ end
273
+ end
274
+
275
+ describe 'matchers' do
276
+ describe 'without options' do
277
+ before(:each){ define_and_validate }
278
+
279
+ it { should have_and_belong_to_many(:labels) }
280
+ it { should_not belong_to(:label) }
281
+ it { should_not have_one(:label) }
282
+ it { should_not have_many(:labels) }
283
+ it { should_not have_and_belong_to_many(:companies) }
284
+ end
285
+
286
+ describe 'with class name option' do
287
+ it { should define_and_validate.class_name('Label') }
288
+
289
+ it { should define_and_validate(:class_name => 'SuperLabel',
290
+ :association_table => 'projects_super_labels').class_name('SuperLabel') }
291
+
292
+ it { should_not define_and_validate.class_name('SuperLabel') }
293
+ end
294
+
295
+ describe 'with foreign_key option' do
296
+ it { should define_and_validate.foreign_key(:project_id) }
297
+ it { should_not define_and_validate.foreign_key(:association_id) }
298
+
299
+ # Checks whether fk exists or not
300
+ it { should define_and_validate(:foreign_key => :association_id,
301
+ :association_columns => [ :association_id ]).foreign_key(:association_id) }
302
+
303
+ it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
304
+ it { should_not define_and_validate(:association_columns => [ :association_id ]).foreign_key(:association_id) }
305
+ end
306
+
307
+ describe 'with join table option' do
308
+ it { should define_and_validate.join_table('labels_projects') }
309
+ it { should define_and_validate(:join_table => 'my_table',
310
+ :association_table => 'my_table').join_table('my_table') }
311
+
312
+ it { should_not define_and_validate.join_table('projects_labels') }
313
+
314
+ it { should_not define_and_validate(:join_table => 'my_table',
315
+ :association_table => 'another_table').join_table('my_table') }
316
+ it { should_not define_and_validate(:join_table => 'another_table',
317
+ :association_table => 'my_table').join_table('my_table') }
318
+ it { should_not define_and_validate(:join_table => 'my_table',
319
+ :association_table => 'my_table').join_table('another_table') }
320
+ end
321
+
322
+ create_optional_boolean_specs(:uniq, self)
323
+ create_optional_boolean_specs(:readonly, self)
324
+ create_optional_boolean_specs(:validate, self)
325
+ create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
326
+ end
327
+
328
+ describe 'macros' do
329
+ before(:each){ define_and_validate(:validate => true, :readonly => true) }
330
+
331
+ should_have_and_belong_to_many :labels
332
+ should_have_and_belong_to_many :labels, :readonly => true
333
+ should_have_and_belong_to_many :labels, :validate => true
334
+ should_have_and_belong_to_many :labels, :class_name => "Label"
335
+ should_have_and_belong_to_many :labels, :foreign_key => :project_id
336
+
337
+ should_not_have_and_belong_to_many :companies
338
+ should_not_have_one :label
339
+ should_not_have_many :labels
340
+
341
+ should_not_have_and_belong_to_many :labels, :readonly => false
342
+ should_not_have_and_belong_to_many :labels, :validate => false
343
+ should_not_have_and_belong_to_many :labels, :class_name => "Anything"
344
+ should_not_have_and_belong_to_many :labels, :foreign_key => :anything_id
345
+ end
346
+ end
347
+
348
+ describe 'have_many' do
349
+
350
+ # Defines a model, create a validation and returns a raw matcher
351
+ def define_and_validate(options={})
352
+ columns = options.delete(:association_columns) || { :task_id => :integer, :project_id => :integer }
353
+ define_model :task, columns
354
+
355
+ define_model :project_task, columns do
356
+ belongs_to :task
357
+ belongs_to :project
358
+ end unless options.delete(:skip_through)
359
+
360
+ @model = define_model :project, options.delete(:model_columns) || {} do
361
+ has_many :tasks, options
362
+ has_many :project_tasks
363
+ end
364
+
365
+ have_many :tasks
366
+ end
367
+
368
+ describe 'messages' do
369
+ it 'should contain a description' do
370
+ matcher = define_and_validate
371
+ matcher.description.should == 'have many tasks'
372
+
373
+ matcher.class_name('Task')
374
+ matcher.description.should == 'have many tasks with class name "Task"'
375
+
376
+ matcher.foreign_key('task_id')
377
+ matcher.description.should == 'have many tasks with class name "Task" and with foreign key "task_id"'
378
+
379
+ matcher = have_many(:tasks).autosave
380
+ matcher.description.should == 'have many tasks autosaving associated records'
381
+
382
+ matcher.uniq
383
+ matcher.description.should == 'have many tasks with unique records and autosaving associated records'
384
+ end
385
+
386
+ it 'should set association_exists? message' do
387
+ define_and_validate
388
+ matcher = have_many('whatever')
389
+ matcher.matches?(@model)
390
+ matcher.failure_message.should == 'Expected Project records have many whatever, got no association'
391
+ end
392
+
393
+ it 'should set macro_matches? message' do
394
+ define_and_validate
395
+ matcher = have_and_belong_to_many('tasks')
396
+ matcher.matches?(@model)
397
+ matcher.failure_message.should == 'Expected Project records have and belong to many tasks, got Project records have many tasks'
398
+ end
399
+
400
+ it 'should set foreign_key_exists? message' do
401
+ matcher = define_and_validate(:association_columns => {})
402
+ matcher.matches?(@model)
403
+ matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "tasks", but does not'
404
+ end
405
+
406
+ it 'should set through_exists? message' do
407
+ matcher = define_and_validate(:through => 'project_tasks')
408
+ matcher.through(:another).matches?(@model)
409
+ matcher.failure_message.should == 'Expected Project records have many tasks through :another, through association does not exist'
410
+ end
411
+
412
+ it 'should set join_table_exists? message' do
413
+ matcher = define_and_validate(:through => 'project_tasks', :skip_through => true)
414
+ matcher.through(:project_tasks).matches?(@model)
415
+ matcher.failure_message.should == 'Expected join table "project_tasks" to exist, but does not'
416
+ end
417
+ end
418
+
419
+ describe 'matchers' do
420
+ describe 'without options' do
421
+ before(:each){ define_and_validate }
422
+
423
+ it { should have_many(:tasks) }
424
+ it { should_not belong_to(:task) }
425
+ it { should_not have_one(:task) }
426
+ it { should_not have_and_belong_to_many(:tasks) }
427
+ end
428
+
429
+ describe 'with class name option' do
430
+ before(:each){ define_model :super_task, :project_id => :integer }
431
+
432
+ it { should define_and_validate.class_name('Task') }
433
+ it { should define_and_validate(:class_name => 'SuperTask').class_name('SuperTask') }
434
+
435
+ it { should_not define_and_validate.class_name('SuperTask') }
436
+ it { should_not define_and_validate(:class_name => 'SuperTask').class_name('Task') }
437
+ end
438
+
439
+ describe 'with foreign_key option' do
440
+ it { should define_and_validate.foreign_key(:project_id) }
441
+ it { should_not define_and_validate.foreign_key(:association_id) }
442
+
443
+ # Checks whether fk exists or not
444
+ it { should define_and_validate(:foreign_key => :association_id,
445
+ :association_columns => { :association_id => :integer }).foreign_key(:association_id) }
446
+
447
+ it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
448
+ it { should_not define_and_validate(:association_columns => { :association_id => :integer }).foreign_key(:association_id) }
449
+ end
450
+
451
+ describe 'with dependent option' do
452
+ it { should define_and_validate(:dependent => :delete_all).dependent(:delete_all) }
453
+ it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
454
+
455
+ it { should_not define_and_validate(:dependent => :delete_all).dependent(:destroy) }
456
+ it { should_not define_and_validate(:dependent => :destroy).dependent(:delete_all) }
457
+ end
458
+
459
+ describe 'with through option' do
460
+ it { should define_and_validate(:through => 'project_tasks') }
461
+ it { should define_and_validate(:through => 'project_tasks').through(:project_tasks) }
462
+
463
+ it { should_not define_and_validate(:through => 'project_tasks').through(:something) }
464
+ it { should_not define_and_validate(:through => 'project_tasks', :skip_through => true).through(:project_tasks) }
465
+ end
466
+
467
+ create_optional_boolean_specs(:uniq, self)
468
+ create_optional_boolean_specs(:readonly, self)
469
+ create_optional_boolean_specs(:validate, self)
470
+ create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
471
+ end
472
+
473
+ describe 'macros' do
474
+ before(:each){ define_and_validate(:through => 'project_tasks', :readonly => true, :validate => true) }
475
+
476
+ should_have_many :tasks
477
+ should_have_many :tasks, :readonly => true
478
+ should_have_many :tasks, :validate => true
479
+ should_have_many :tasks, :through => :project_tasks
480
+
481
+ should_not_have_many :tasks, :readonly => false
482
+ should_not_have_many :tasks, :validate => false
483
+ should_not_have_many :tasks, :through => :another_thing
484
+ end
485
+ end
486
+
487
+ describe 'have_one' do
488
+
489
+ # Defines a model, create a validation and returns a raw matcher
490
+ def define_and_validate(options={})
491
+ columns = options.delete(:association_columns) || { :manager_id => :integer, :project_id => :integer }
492
+ define_model :manager, columns
493
+
494
+ define_model :project_manager, columns do
495
+ belongs_to :manager
496
+ belongs_to :project
497
+ end unless options.delete(:skip_through)
498
+
499
+ @model = define_model :project, options.delete(:model_columns) || {} do
500
+ has_one :manager, options
501
+ has_many :project_managers
502
+ end
503
+
504
+ have_one :manager
505
+ end
506
+
507
+ describe 'messages' do
508
+ it 'should contain a description' do
509
+ matcher = define_and_validate
510
+ matcher.description.should == 'have one manager'
511
+
512
+ matcher.class_name('Manager')
513
+ matcher.description.should == 'have one manager with class name "Manager"'
514
+
515
+ matcher.foreign_key('manager_id')
516
+ matcher.description.should == 'have one manager with class name "Manager" and with foreign key "manager_id"'
517
+ end
518
+
519
+ it 'should set association_exists? message' do
520
+ define_and_validate
521
+ matcher = have_one('whatever')
522
+ matcher.matches?(@model)
523
+ matcher.failure_message.should == 'Expected Project records have one whatever, got no association'
524
+ end
525
+
526
+ it 'should set macro_matches? message' do
527
+ define_and_validate
528
+ matcher = belong_to('manager')
529
+ matcher.matches?(@model)
530
+ matcher.failure_message.should == 'Expected Project records belong to manager, got Project records have one manager'
531
+ end
532
+
533
+ it 'should set foreign_key_exists? message' do
534
+ matcher = define_and_validate(:association_columns => {})
535
+ matcher.matches?(@model)
536
+ matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "managers", but does not'
537
+ end
538
+
539
+ it 'should set through_exists? message' do
540
+ matcher = define_and_validate(:through => 'project_managers')
541
+ matcher.through(:another).matches?(@model)
542
+ matcher.failure_message.should == 'Expected Project records have one manager through :another, through association does not exist'
543
+ end
544
+
545
+ it 'should set join_table_exists? message' do
546
+ matcher = define_and_validate(:through => 'project_managers', :skip_through => true)
547
+ matcher.through(:project_managers).matches?(@model)
548
+ matcher.failure_message.should == 'Expected join table "project_managers" to exist, but does not'
549
+ end
550
+ end
551
+
552
+ describe 'matchers' do
553
+ describe 'without options' do
554
+ before(:each){ define_and_validate }
555
+
556
+ it { should have_one(:manager) }
557
+ it { should_not belong_to(:manager) }
558
+ it { should_not have_many(:managers) }
559
+ it { should_not have_and_belong_to_many(:managers) }
560
+ end
561
+
562
+ describe 'with class name option' do
563
+ before(:each){ define_model :super_manager, :project_id => :integer }
564
+
565
+ it { should define_and_validate.class_name('Manager') }
566
+ it { should define_and_validate(:class_name => 'SuperManager').class_name('SuperManager') }
567
+
568
+ it { should_not define_and_validate.class_name('SuperManager') }
569
+ it { should_not define_and_validate(:class_name => 'SuperManager').class_name('Manager') }
570
+ end
571
+
572
+ describe 'with foreign_key option' do
573
+ it { should define_and_validate.foreign_key(:project_id) }
574
+ it { should_not define_and_validate.foreign_key(:association_id) }
575
+
576
+ # Checks whether fk exists or not
577
+ it { should define_and_validate(:foreign_key => :association_id,
578
+ :association_columns => { :association_id => :integer }).foreign_key(:association_id) }
579
+
580
+ it { should_not define_and_validate(:foreign_key => :association_id).foreign_key(:association_id) }
581
+ it { should_not define_and_validate(:association_columns => { :association_id => :integer }).foreign_key(:association_id) }
582
+ end
583
+
584
+ describe 'with dependent option' do
585
+ it { should define_and_validate(:dependent => :delete).dependent(:delete) }
586
+ it { should define_and_validate(:dependent => :destroy).dependent(:destroy) }
587
+
588
+ it { should_not define_and_validate(:dependent => :delete).dependent(:destroy) }
589
+ it { should_not define_and_validate(:dependent => :destroy).dependent(:delete) }
590
+ end
591
+
592
+ describe 'with through option' do
593
+ it { should define_and_validate(:through => 'project_managers') }
594
+ it { should define_and_validate(:through => 'project_managers').through(:project_managers) }
595
+
596
+ it { should_not define_and_validate(:through => 'project_managers').through(:something) }
597
+ it { should_not define_and_validate(:through => 'project_managers', :skip_through => true).through(:project_managers) }
598
+ end
599
+
600
+ create_optional_boolean_specs(:validate, self)
601
+ create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
602
+ end
603
+
604
+ describe 'macros' do
605
+ before(:each){ define_and_validate(:through => 'project_managers', :validate => true) }
606
+
607
+ should_have_one :manager
608
+ should_have_one :manager, :validate => true
609
+ should_have_one :manager, :through => :project_managers
610
+
611
+ should_not_have_one :manager, :validate => false
612
+ should_not_have_one :manager, :through => :another_thing
613
+ end
614
+ end
615
+
616
616
  end