jeffrafter-factory_girl 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +9 -0
  2. data/Changelog +29 -0
  3. data/LICENSE +19 -0
  4. data/README.rdoc +265 -0
  5. data/Rakefile +81 -0
  6. data/lib/factory_girl.rb +35 -0
  7. data/lib/factory_girl/aliases.rb +50 -0
  8. data/lib/factory_girl/attribute.rb +29 -0
  9. data/lib/factory_girl/attribute/association.rb +20 -0
  10. data/lib/factory_girl/attribute/callback.rb +16 -0
  11. data/lib/factory_girl/attribute/dynamic.rb +20 -0
  12. data/lib/factory_girl/attribute/static.rb +17 -0
  13. data/lib/factory_girl/factory.rb +430 -0
  14. data/lib/factory_girl/proxy.rb +79 -0
  15. data/lib/factory_girl/proxy/attributes_for.rb +21 -0
  16. data/lib/factory_girl/proxy/build.rb +30 -0
  17. data/lib/factory_girl/proxy/create.rb +12 -0
  18. data/lib/factory_girl/proxy/stub.rb +50 -0
  19. data/lib/factory_girl/sequence.rb +63 -0
  20. data/lib/factory_girl/step_definitions.rb +54 -0
  21. data/lib/factory_girl/syntax.rb +12 -0
  22. data/lib/factory_girl/syntax/blueprint.rb +42 -0
  23. data/lib/factory_girl/syntax/generate.rb +68 -0
  24. data/lib/factory_girl/syntax/make.rb +39 -0
  25. data/lib/factory_girl/syntax/sham.rb +42 -0
  26. data/spec/factory_girl/aliases_spec.rb +29 -0
  27. data/spec/factory_girl/attribute/association_spec.rb +29 -0
  28. data/spec/factory_girl/attribute/callback_spec.rb +23 -0
  29. data/spec/factory_girl/attribute/dynamic_spec.rb +49 -0
  30. data/spec/factory_girl/attribute/static_spec.rb +29 -0
  31. data/spec/factory_girl/attribute_spec.rb +30 -0
  32. data/spec/factory_girl/factory_spec.rb +605 -0
  33. data/spec/factory_girl/proxy/attributes_for_spec.rb +52 -0
  34. data/spec/factory_girl/proxy/build_spec.rb +81 -0
  35. data/spec/factory_girl/proxy/create_spec.rb +94 -0
  36. data/spec/factory_girl/proxy/stub_spec.rb +79 -0
  37. data/spec/factory_girl/proxy_spec.rb +84 -0
  38. data/spec/factory_girl/sequence_spec.rb +66 -0
  39. data/spec/factory_girl/syntax/blueprint_spec.rb +34 -0
  40. data/spec/factory_girl/syntax/generate_spec.rb +57 -0
  41. data/spec/factory_girl/syntax/make_spec.rb +35 -0
  42. data/spec/factory_girl/syntax/sham_spec.rb +35 -0
  43. data/spec/integration_spec.rb +304 -0
  44. data/spec/models.rb +43 -0
  45. data/spec/spec_helper.rb +18 -0
  46. metadata +128 -0
@@ -0,0 +1,39 @@
1
+ class Factory
2
+ module Syntax
3
+
4
+ # Extends ActiveRecord::Base to provide a make class method, which is a
5
+ # shortcut for Factory.create.
6
+ #
7
+ # Usage:
8
+ #
9
+ # require 'factory_girl/syntax/make'
10
+ #
11
+ # Factory.define :user do |factory|
12
+ # factory.name 'Billy Bob'
13
+ # factory.email 'billy@bob.example.com'
14
+ # end
15
+ #
16
+ # User.make(:name => 'Johnny')
17
+ #
18
+ # This syntax was derived from Pete Yandell's machinist.
19
+ module Make
20
+ module ActiveRecord #:nodoc:
21
+
22
+ def self.included(base) # :nodoc:
23
+ base.extend ClassMethods
24
+ end
25
+
26
+ module ClassMethods #:nodoc:
27
+
28
+ def make(overrides = {})
29
+ Factory.create(name.underscore, overrides)
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ ActiveRecord::Base.send(:include, Factory::Syntax::Make::ActiveRecord)
@@ -0,0 +1,42 @@
1
+ class Factory
2
+ module Syntax
3
+
4
+ # Adds a Sham module, which provides an alternate interface to
5
+ # Factory::Sequence.
6
+ #
7
+ # Usage:
8
+ #
9
+ # require 'factory_girl/syntax/sham'
10
+ #
11
+ # Sham.email {|n| "somebody#{n}@example.com" }
12
+ #
13
+ # Factory.define :user do |factory|
14
+ # factory.email { Sham.email }
15
+ # end
16
+ #
17
+ # Note that you can also use Faker, but it is recommended that you simply
18
+ # use a sequence as in the above example, as factory_girl does not provide
19
+ # protection against duplication in randomized sequences, and a randomized
20
+ # value does not provide any tangible benefits over an ascending sequence.
21
+ #
22
+ # This syntax was derived from Pete Yandell's machinist.
23
+ module Sham
24
+ module Sham #:nodoc:
25
+ def self.method_missing(name, &block)
26
+ if block_given?
27
+ Factory.sequence(name, &block)
28
+ else
29
+ Factory.next(name)
30
+ end
31
+ end
32
+
33
+ # overrides name on Module
34
+ def self.name(&block)
35
+ method_missing('name', &block)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ include Factory::Syntax::Sham
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe Factory, "aliases" do
4
+
5
+ it "should include an attribute as an alias for itself by default" do
6
+ Factory.aliases_for(:test).should include(:test)
7
+ end
8
+
9
+ it "should include the root of a foreign key as an alias by default" do
10
+ Factory.aliases_for(:test_id).should include(:test)
11
+ end
12
+
13
+ it "should include an attribute's foreign key as an alias by default" do
14
+ Factory.aliases_for(:test).should include(:test_id)
15
+ end
16
+
17
+ describe "after adding an alias" do
18
+
19
+ before do
20
+ Factory.alias(/(.*)_suffix/, '\1')
21
+ end
22
+
23
+ it "should return the alias in the aliases list" do
24
+ Factory.aliases_for(:test_suffix).should include(:test)
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe Factory::Attribute::Association do
4
+ before do
5
+ @name = :author
6
+ @factory = :user
7
+ @overrides = { :first_name => 'John' }
8
+ @attr = Factory::Attribute::Association.new(@name, @factory, @overrides)
9
+ end
10
+
11
+ it "should have a name" do
12
+ @attr.name.should == @name
13
+ end
14
+
15
+ it "should have a factory" do
16
+ @attr.factory.should == @factory
17
+ end
18
+
19
+ it "should tell the proxy to associate when being added to a proxy" do
20
+ proxy = "proxy"
21
+ stub(proxy).associate
22
+ @attr.add_to(proxy)
23
+ proxy.should have_received.associate(@name, @factory, @overrides)
24
+ end
25
+
26
+ it "should convert names to symbols" do
27
+ Factory::Attribute::Association.new('name', :user, {}).name.should == :name
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe Factory::Attribute::Callback do
4
+ before do
5
+ @name = :after_create
6
+ @block = proc{ 'block' }
7
+ @attr = Factory::Attribute::Callback.new(@name, @block)
8
+ end
9
+
10
+ it "should have a name" do
11
+ @attr.name.should == @name
12
+ end
13
+
14
+ it "should set its callback on a proxy" do
15
+ @proxy = "proxy"
16
+ mock(@proxy).add_callback(@name, @block)
17
+ @attr.add_to(@proxy)
18
+ end
19
+
20
+ it "should convert names to symbols" do
21
+ Factory::Attribute::Callback.new('name', nil).name.should == :name
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe Factory::Attribute::Dynamic do
4
+ before do
5
+ @name = :first_name
6
+ @block = lambda { 'value' }
7
+ @attr = Factory::Attribute::Dynamic.new(@name, @block)
8
+ end
9
+
10
+ it "should have a name" do
11
+ @attr.name.should == @name
12
+ end
13
+
14
+ it "should call the block to set a value" do
15
+ @proxy = "proxy"
16
+ stub(@proxy).set
17
+ @attr.add_to(@proxy)
18
+ @proxy.should have_received.set(@name, 'value')
19
+ end
20
+
21
+ it "should yield the proxy to the block when adding its value to a proxy" do
22
+ @block = lambda {|a| a }
23
+ @attr = Factory::Attribute::Dynamic.new(:user, @block)
24
+ @proxy = "proxy"
25
+ stub(@proxy).set
26
+ @attr.add_to(@proxy)
27
+ @proxy.should have_received.set(:user, @proxy)
28
+ end
29
+
30
+ it "should raise an error when defining an attribute writer" do
31
+ lambda {
32
+ Factory::Attribute::Dynamic.new('test=', nil)
33
+ }.should raise_error(Factory::AttributeDefinitionError)
34
+ end
35
+
36
+ it "should raise an error when returning a sequence" do
37
+ stub(Factory).sequence { Factory::Sequence.new }
38
+ block = lambda { Factory.sequence(:email) }
39
+ attr = Factory::Attribute::Dynamic.new(:email, block)
40
+ proxy = stub!.set.subject
41
+ lambda {
42
+ attr.add_to(proxy)
43
+ }.should raise_error(Factory::SequenceAbuseError)
44
+ end
45
+
46
+ it "should convert names to symbols" do
47
+ Factory::Attribute::Dynamic.new('name', nil).name.should == :name
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe Factory::Attribute::Static do
4
+ before do
5
+ @name = :first_name
6
+ @value = 'John'
7
+ @attr = Factory::Attribute::Static.new(@name, @value)
8
+ end
9
+
10
+ it "should have a name" do
11
+ @attr.name.should == @name
12
+ end
13
+
14
+ it "should set its static value on a proxy" do
15
+ @proxy = "proxy"
16
+ mock(@proxy).set(@name, @value)
17
+ @attr.add_to(@proxy)
18
+ end
19
+
20
+ it "should raise an error when defining an attribute writer" do
21
+ lambda {
22
+ Factory::Attribute::Static.new('test=', nil)
23
+ }.should raise_error(Factory::AttributeDefinitionError)
24
+ end
25
+
26
+ it "should convert names to symbols" do
27
+ Factory::Attribute::Static.new('name', nil).name.should == :name
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe Factory::Attribute do
4
+ before do
5
+ @name = :user
6
+ @attr = Factory::Attribute.new(@name)
7
+ end
8
+
9
+ it "should have a name" do
10
+ @attr.name.should == @name
11
+ end
12
+
13
+ it "should do nothing when being added to a proxy" do
14
+ @proxy = "proxy"
15
+ stub(@proxy).set
16
+ @attr.add_to(@proxy)
17
+ @proxy.should have_received.set.never
18
+ end
19
+
20
+ it "should raise an error when defining an attribute writer" do
21
+ error_message = %{factory_girl uses 'f.test value' syntax rather than 'f.test = value'}
22
+ lambda {
23
+ Factory::Attribute.new('test=')
24
+ }.should raise_error(Factory::AttributeDefinitionError, error_message)
25
+ end
26
+
27
+ it "should convert names to symbols" do
28
+ Factory::Attribute.new('name').name.should == :name
29
+ end
30
+ end
@@ -0,0 +1,605 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe Factory do
4
+ describe "defining a factory" do
5
+ before do
6
+ @name = :user
7
+ @factory = "factory"
8
+ stub(@factory).factory_name { @name }
9
+ @options = { :class => 'magic' }
10
+ stub(Factory).new { @factory }
11
+ end
12
+
13
+ after { Factory.factories.clear }
14
+
15
+ it "should create a new factory using the specified name and options" do
16
+ mock(Factory).new(@name, @options) { @factory }
17
+ Factory.define(@name, @options) {|f| }
18
+ end
19
+
20
+ it "should pass the factory do the block" do
21
+ yielded = nil
22
+ Factory.define(@name) do |y|
23
+ yielded = y
24
+ end
25
+ yielded.should == @factory
26
+ end
27
+
28
+ it "should add the factory to the list of factories" do
29
+ Factory.define(@name) {|f| }
30
+ @factory.should == Factory.factories[@name]
31
+ end
32
+
33
+ it "should allow a factory to be found by name" do
34
+ Factory.define(@name) {|f| }
35
+ Factory.factory_by_name(@name).should == @factory
36
+ end
37
+
38
+ it "should not allow a duplicate factory definition" do
39
+ lambda {
40
+ 2.times { Factory.define(@name) {|f| } }
41
+ }.should raise_error(Factory::DuplicateDefinitionError)
42
+ end
43
+
44
+ end
45
+
46
+ describe "a factory" do
47
+ before do
48
+ @name = :user
49
+ @class = User
50
+ @factory = Factory.new(@name)
51
+ end
52
+
53
+ it "should have a factory name" do
54
+ @factory.factory_name.should == @name
55
+ end
56
+
57
+ it "should have a build class" do
58
+ @factory.build_class.should == @class
59
+ end
60
+
61
+ it "should have a default strategy" do
62
+ @factory.default_strategy.should == :create
63
+ end
64
+
65
+ it "should not allow the same attribute to be added twice" do
66
+ lambda {
67
+ 2.times { @factory.add_attribute :first_name }
68
+ }.should raise_error(Factory::AttributeDefinitionError)
69
+ end
70
+
71
+ it "should add a static attribute when an attribute is defined with a value" do
72
+ attribute = 'attribute'
73
+ stub(attribute).name { :name }
74
+ mock(Factory::Attribute::Static).new(:name, 'value') { attribute }
75
+ @factory.add_attribute(:name, 'value')
76
+ end
77
+
78
+ it "should add a dynamic attribute when an attribute is defined with a block" do
79
+ attribute = 'attribute'
80
+ stub(attribute).name { :name }
81
+ block = lambda {}
82
+ mock(Factory::Attribute::Dynamic).new(:name, block) { attribute }
83
+ @factory.add_attribute(:name, &block)
84
+ end
85
+
86
+ it "should raise for an attribute with a value and a block" do
87
+ lambda {
88
+ @factory.add_attribute(:name, 'value') {}
89
+ }.should raise_error(Factory::AttributeDefinitionError)
90
+ end
91
+
92
+ describe "adding an attribute using a in-line sequence" do
93
+ it "should create the sequence" do
94
+ mock(Factory::Sequence).new
95
+ @factory.sequence(:name) {}
96
+ end
97
+
98
+ it "should add a dynamic attribute" do
99
+ attribute = 'attribute'
100
+ stub(attribute).name { :name }
101
+ mock(Factory::Attribute::Dynamic).new(:name, is_a(Proc)) { attribute }
102
+ @factory.sequence(:name) {}
103
+ @factory.attributes.should include(attribute)
104
+ end
105
+ end
106
+
107
+ describe "adding contructor arguments" do
108
+ before do
109
+ @proxy = "proxy"
110
+ stub(@proxy).result { 'result' }
111
+ end
112
+
113
+ it "should execute the block when running the factory" do
114
+ @args = {:message => 'The price is wrong, Bob!'}
115
+ @factory.constructor_args { @args }
116
+ mock(Factory::Proxy::Build).new(@factory.build_class, [@args]) { @proxy }
117
+ @factory.run(Factory::Proxy::Build, {})
118
+ end
119
+
120
+ it "should pass the overrides to the block if the block arity is one" do
121
+ @factory.constructor_args {|overrides| {:message => overrides.delete(:message)} }
122
+ mock(Factory::Proxy::Build).new(@factory.build_class, [{:message => 'The price is wrong, Bob!'}]) { @proxy }
123
+ @factory.run(Factory::Proxy::Build, {:message => 'The price is wrong, Bob!'})
124
+ end
125
+
126
+ end
127
+
128
+ describe "adding a callback" do
129
+ it "should add a callback attribute when the after_build attribute is defined" do
130
+ mock(Factory::Attribute::Callback).new(:after_build, is_a(Proc)) { 'after_build callback' }
131
+ @factory.after_build {}
132
+ @factory.attributes.should include('after_build callback')
133
+ end
134
+
135
+ it "should add a callback attribute when the after_create attribute is defined" do
136
+ mock(Factory::Attribute::Callback).new(:after_create, is_a(Proc)) { 'after_create callback' }
137
+ @factory.after_create {}
138
+ @factory.attributes.should include('after_create callback')
139
+ end
140
+
141
+ it "should add a callback attribute when the after_stub attribute is defined" do
142
+ mock(Factory::Attribute::Callback).new(:after_stub, is_a(Proc)) { 'after_stub callback' }
143
+ @factory.after_stub {}
144
+ @factory.attributes.should include('after_stub callback')
145
+ end
146
+
147
+ it "should add a callback attribute when defining a callback" do
148
+ mock(Factory::Attribute::Callback).new(:after_create, is_a(Proc)) { 'after_create callback' }
149
+ @factory.callback(:after_create) {}
150
+ @factory.attributes.should include('after_create callback')
151
+ end
152
+
153
+ it "should raise an InvalidCallbackNameError when defining a callback with an invalid name" do
154
+ lambda{
155
+ @factory.callback(:invalid_callback_name) {}
156
+ }.should raise_error(Factory::InvalidCallbackNameError)
157
+ end
158
+ end
159
+
160
+ describe "after adding an attribute" do
161
+ before do
162
+ @attribute = "attribute"
163
+ @proxy = "proxy"
164
+
165
+ stub(@attribute).name { :name }
166
+ stub(@attribute).add_to
167
+ stub(@proxy).set
168
+ stub(@proxy).result { 'result' }
169
+ stub(Factory::Attribute::Static).new { @attribute }
170
+ stub(Factory::Proxy::Build).new { @proxy }
171
+
172
+ @factory.add_attribute(:name, 'value')
173
+ end
174
+
175
+ it "should create the right proxy using the build class when running" do
176
+ mock(Factory::Proxy::Build).new(@factory.build_class, []) { @proxy }
177
+ @factory.run(Factory::Proxy::Build, {})
178
+ end
179
+
180
+ it "should add the attribute to the proxy when running" do
181
+ mock(@attribute).add_to(@proxy)
182
+ @factory.run(Factory::Proxy::Build, {})
183
+ end
184
+
185
+ it "should return the result from the proxy when running" do
186
+ mock(@proxy).result() { 'result' }
187
+ @factory.run(Factory::Proxy::Build, {}).should == 'result'
188
+ end
189
+
190
+ end
191
+
192
+ it "should add an association without a factory name or overrides" do
193
+ factory = Factory.new(:post)
194
+ name = :user
195
+ attr = 'attribute'
196
+ mock(Factory::Attribute::Association).new(name, name, {}) { attr }
197
+ factory.association(name)
198
+ factory.attributes.should include(attr)
199
+ end
200
+
201
+ it "should return associations" do
202
+ factory = Factory.new(:post)
203
+ factory.association(:author)
204
+ factory.association(:editor)
205
+ factory.associations.each do |association|
206
+ association.should be_a(Factory::Attribute::Association)
207
+ end
208
+ factory.associations.size.should == 2
209
+ end
210
+
211
+ it "should add an association with overrides" do
212
+ factory = Factory.new(:post)
213
+ name = :user
214
+ attr = 'attribute'
215
+ overrides = { :first_name => 'Ben' }
216
+ mock(Factory::Attribute::Association).new(name, name, overrides) { attr }
217
+ factory.association(name, overrides)
218
+ factory.attributes.should include(attr)
219
+ end
220
+
221
+ it "should add an association with a factory name" do
222
+ factory = Factory.new(:post)
223
+ attr = 'attribute'
224
+ mock(Factory::Attribute::Association).new(:author, :user, {}) { attr }
225
+ factory.association(:author, :factory => :user)
226
+ factory.attributes.should include(attr)
227
+ end
228
+
229
+ it "should add an association with a factory name and overrides" do
230
+ factory = Factory.new(:post)
231
+ attr = 'attribute'
232
+ mock(Factory::Attribute::Association).new(:author, :user, :first_name => 'Ben') { attr }
233
+ factory.association(:author, :factory => :user, :first_name => 'Ben')
234
+ factory.attributes.should include(attr)
235
+ end
236
+
237
+ it "should raise for a self referencing association" do
238
+ factory = Factory.new(:post)
239
+ lambda {
240
+ factory.association(:parent, :factory => :post)
241
+ }.should raise_error(Factory::AssociationDefinitionError)
242
+ end
243
+
244
+ it "should add an attribute using the method name when passed an undefined method" do
245
+ attribute = 'attribute'
246
+ stub(attribute).name { :name }
247
+ block = lambda {}
248
+ mock(Factory::Attribute::Static).new(:name, 'value') { attribute }
249
+ @factory.send(:name, 'value')
250
+ @factory.attributes.should include(attribute)
251
+ end
252
+
253
+ it "should allow human_name as a static attribute name" do
254
+ attribute = 'attribute'
255
+ stub(attribute).name { :name }
256
+ mock(Factory::Attribute::Static).new(:human_name, 'value') { attribute}
257
+ @factory.human_name 'value'
258
+ end
259
+
260
+ it "should allow human_name as a dynamic attribute name" do
261
+ attribute = 'attribute'
262
+ stub(attribute).name { :name }
263
+ block = lambda {}
264
+ mock(Factory::Attribute::Dynamic).new(:human_name, block) { attribute }
265
+ @factory.human_name(&block)
266
+ end
267
+
268
+ describe "when overriding generated attributes with a hash" do
269
+ before do
270
+ @attr = :name
271
+ @value = 'The price is right!'
272
+ @hash = { @attr => @value }
273
+ end
274
+
275
+ it "should return the overridden value in the generated attributes" do
276
+ @factory.add_attribute(@attr, 'The price is wrong, Bob!')
277
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
278
+ result[@attr].should == @value
279
+ end
280
+
281
+ it "should not call a lazy attribute block for an overridden attribute" do
282
+ @factory.add_attribute(@attr) { flunk }
283
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
284
+ end
285
+
286
+ it "should override a symbol parameter with a string parameter" do
287
+ @factory.add_attribute(@attr, 'The price is wrong, Bob!')
288
+ @hash = { @attr.to_s => @value }
289
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
290
+ result[@attr].should == @value
291
+ end
292
+ end
293
+
294
+ describe "overriding an attribute with an alias" do
295
+ before do
296
+ @factory.add_attribute(:test, 'original')
297
+ Factory.alias(/(.*)_alias/, '\1')
298
+ @result = @factory.run(Factory::Proxy::AttributesFor,
299
+ :test_alias => 'new')
300
+ end
301
+
302
+ it "should use the passed in value for the alias" do
303
+ @result[:test_alias].should == 'new'
304
+ end
305
+
306
+ it "should discard the predefined value for the attribute" do
307
+ @result[:test].should be_nil
308
+ end
309
+ end
310
+
311
+ it "should guess the build class from the factory name" do
312
+ @factory.build_class.should == User
313
+ end
314
+
315
+ describe "when defined with a custom class" do
316
+ before do
317
+ @class = User
318
+ @factory = Factory.new(:author, :class => @class)
319
+ end
320
+
321
+ it "should use the specified class as the build class" do
322
+ @factory.build_class.should == @class
323
+ end
324
+ end
325
+
326
+ describe "when defined with a class instead of a name" do
327
+ before do
328
+ @class = ArgumentError
329
+ @name = :argument_error
330
+ @factory = Factory.new(@class)
331
+ end
332
+
333
+ it "should guess the name from the class" do
334
+ @factory.factory_name.should == @name
335
+ end
336
+
337
+ it "should use the class as the build class" do
338
+ @factory.build_class.should == @class
339
+ end
340
+ end
341
+
342
+ describe "when defined with a custom class name" do
343
+ before do
344
+ @class = ArgumentError
345
+ @factory = Factory.new(:author, :class => :argument_error)
346
+ end
347
+
348
+ it "should use the specified class as the build class" do
349
+ @factory.build_class.should == @class
350
+ end
351
+ end
352
+ end
353
+
354
+ describe "a factory with a name ending in s" do
355
+ before do
356
+ @name = :business
357
+ @class = Business
358
+ @factory = Factory.new(@name)
359
+ end
360
+
361
+ it "should have a factory name" do
362
+ @factory.factory_name.should == @name
363
+ end
364
+
365
+ it "should have a build class" do
366
+ @factory.build_class.should == @class
367
+ end
368
+ end
369
+
370
+ describe "a factory with a string for a name" do
371
+ before do
372
+ @name = :user
373
+ @factory = Factory.new(@name.to_s) {}
374
+ end
375
+
376
+ it "should convert the string to a symbol" do
377
+ @factory.factory_name.should == @name
378
+ end
379
+ end
380
+
381
+ describe "a factory defined with a string name" do
382
+ before do
383
+ Factory.factories = {}
384
+ @name = :user
385
+ @factory = Factory.define(@name.to_s) {}
386
+ end
387
+
388
+ it "should store the factory using a symbol" do
389
+ Factory.factories[@name].should == @factory
390
+ end
391
+ end
392
+
393
+ describe "after defining a factory" do
394
+ before do
395
+ @name = :user
396
+ @factory = "factory"
397
+
398
+ Factory.factories[@name] = @factory
399
+ end
400
+
401
+ after { Factory.factories.clear }
402
+
403
+ it "should use Proxy::AttributesFor for Factory.attributes_for" do
404
+ mock(@factory).run(Factory::Proxy::AttributesFor, :attr => 'value') { 'result' }
405
+ Factory.attributes_for(@name, :attr => 'value').should == 'result'
406
+ end
407
+
408
+ it "should use Proxy::Build for Factory.build" do
409
+ mock(@factory).run(Factory::Proxy::Build, :attr => 'value') { 'result' }
410
+ Factory.build(@name, :attr => 'value').should == 'result'
411
+ end
412
+
413
+ it "should use Proxy::Create for Factory.create" do
414
+ mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
415
+ Factory.create(@name, :attr => 'value').should == 'result'
416
+ end
417
+
418
+ it "should use Proxy::Stub for Factory.stub" do
419
+ mock(@factory).run(Factory::Proxy::Stub, :attr => 'value') { 'result' }
420
+ Factory.stub(@name, :attr => 'value').should == 'result'
421
+ end
422
+
423
+ it "should use default strategy option as Factory.default_strategy" do
424
+ stub(@factory).default_strategy { :create }
425
+ mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
426
+ Factory.default_strategy(@name, :attr => 'value').should == 'result'
427
+ end
428
+
429
+ it "should use the default strategy for the global Factory method" do
430
+ stub(@factory).default_strategy { :create }
431
+ mock(@factory).run(Factory::Proxy::Create, :attr => 'value') { 'result' }
432
+ Factory(@name, :attr => 'value').should == 'result'
433
+ end
434
+
435
+ [:build, :create, :attributes_for, :stub].each do |method|
436
+ it "should raise an ArgumentError on #{method} with a nonexistant factory" do
437
+ lambda { Factory.send(method, :bogus) }.should raise_error(ArgumentError)
438
+ end
439
+
440
+ it "should recognize either 'name' or :name for Factory.#{method}" do
441
+ stub(@factory).run
442
+ lambda { Factory.send(method, @name.to_s) }.should_not raise_error
443
+ lambda { Factory.send(method, @name.to_sym) }.should_not raise_error
444
+ end
445
+ end
446
+ end
447
+
448
+ describe 'defining a factory with a parent parameter' do
449
+ before do
450
+ @parent = Factory.define :object do |f|
451
+ f.name 'Name'
452
+ end
453
+ end
454
+
455
+ after { Factory.factories.clear }
456
+
457
+ it "should raise an ArgumentError when trying to use a non-existent factory as parent" do
458
+ lambda {
459
+ Factory.define(:child, :parent => :nonexsitent) {}
460
+ }.should raise_error(ArgumentError)
461
+ end
462
+
463
+ it "should create a new factory using the class of the parent" do
464
+ child = Factory.define(:child, :parent => :object) {}
465
+ child.build_class.should == @parent.build_class
466
+ end
467
+
468
+ it "should create a new factory while overriding the parent class" do
469
+ class Other; end
470
+
471
+ child = Factory.define(:child, :parent => :object, :class => Other) {}
472
+ child.build_class.should == Other
473
+ end
474
+
475
+ it "should create a new factory with attributes of the parent" do
476
+ child = Factory.define(:child, :parent => :object) {}
477
+ child.attributes.size.should == 1
478
+ child.attributes.first.name.should == :name
479
+ end
480
+
481
+ it "should allow to define additional attributes" do
482
+ child = Factory.define(:child, :parent => :object) do |f|
483
+ f.email 'person@somebody.com'
484
+ end
485
+ child.attributes.size.should == 2
486
+ end
487
+
488
+ it "should allow to override parent attributes" do
489
+ child = Factory.define(:child, :parent => :object) do |f|
490
+ f.name { 'Child Name' }
491
+ end
492
+ child.attributes.size.should == 1
493
+ child.attributes.first.should be_kind_of(Factory::Attribute::Dynamic)
494
+ end
495
+
496
+ it "inherit all callbacks" do
497
+ Factory.define(:child, :parent => :object) do |f|
498
+ f.after_stub {|o| o.name = 'Stubby' }
499
+ end
500
+
501
+ grandchild = Factory.define(:grandchild, :parent => :child) do |f|
502
+ f.after_stub {|o| o.name = "#{o.name} McStubby" }
503
+ end
504
+
505
+ grandchild.attributes.size.should == 3
506
+ grandchild.attributes.first.should be_kind_of(Factory::Attribute::Callback)
507
+ grandchild.attributes[1].should be_kind_of(Factory::Attribute::Callback)
508
+ end
509
+ end
510
+
511
+ describe 'defining a factory with a default strategy parameter' do
512
+ it "should raise an ArgumentError when trying to use a non-existent factory" do
513
+ lambda {
514
+ Factory.define(:object, :default_strategy => :nonexistent) {}
515
+ }.should raise_error(ArgumentError)
516
+ end
517
+
518
+ it "should create a new factory with a specified default strategy" do
519
+ factory = Factory.define(:object, :default_strategy => :stub) {}
520
+ factory.default_strategy.should == :stub
521
+ end
522
+ end
523
+
524
+ def self.in_directory_with_files(*files)
525
+ before do
526
+ @pwd = Dir.pwd
527
+ @tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
528
+ FileUtils.mkdir_p @tmp_dir
529
+ Dir.chdir(@tmp_dir)
530
+
531
+ files.each do |file|
532
+ FileUtils.mkdir_p File.dirname(file)
533
+ FileUtils.touch file
534
+ stub(Factory).require(file)
535
+ end
536
+ end
537
+
538
+ after do
539
+ Dir.chdir(@pwd)
540
+ FileUtils.rm_rf(@tmp_dir)
541
+ end
542
+ end
543
+
544
+ def require_definitions_from(file)
545
+ simple_matcher do |given, matcher|
546
+ has_received = have_received.require(file)
547
+ result = has_received.matches?(given)
548
+ matcher.description = "require definitions from #{file}"
549
+ matcher.failure_message = has_received.failure_message
550
+ result
551
+ end
552
+ end
553
+
554
+ share_examples_for "finds definitions" do
555
+ before do
556
+ stub(Factory).require
557
+ Factory.find_definitions
558
+ end
559
+ subject { Factory }
560
+ end
561
+
562
+ describe "with factories.rb" do
563
+ in_directory_with_files 'factories.rb'
564
+ it_should_behave_like "finds definitions"
565
+ it { should require_definitions_from('factories.rb') }
566
+ end
567
+
568
+ %w(spec test).each do |dir|
569
+ describe "with a factories file under #{dir}" do
570
+ in_directory_with_files File.join(dir, 'factories.rb')
571
+ it_should_behave_like "finds definitions"
572
+ it { should require_definitions_from("#{dir}/factories.rb") }
573
+ end
574
+
575
+ describe "with a factories file under #{dir}/factories" do
576
+ in_directory_with_files File.join(dir, 'factories', 'post_factory.rb')
577
+ it_should_behave_like "finds definitions"
578
+ it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
579
+ end
580
+
581
+ describe "with several factories files under #{dir}/factories" do
582
+ in_directory_with_files File.join(dir, 'factories', 'post_factory.rb'),
583
+ File.join(dir, 'factories', 'person_factory.rb')
584
+ it_should_behave_like "finds definitions"
585
+ it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
586
+ it { should require_definitions_from("#{dir}/factories/person_factory.rb") }
587
+ end
588
+
589
+ describe "with nested and unnested factories files under #{dir}" do
590
+ in_directory_with_files File.join(dir, 'factories.rb'),
591
+ File.join(dir, 'factories', 'post_factory.rb'),
592
+ File.join(dir, 'factories', 'person_factory.rb')
593
+ it_should_behave_like "finds definitions"
594
+ it { should require_definitions_from("#{dir}/factories.rb") }
595
+ it { should require_definitions_from("#{dir}/factories/post_factory.rb") }
596
+ it { should require_definitions_from("#{dir}/factories/person_factory.rb") }
597
+ end
598
+ end
599
+
600
+ it "should return the factory name without underscores for the human name" do
601
+ factory = Factory.new(:name_with_underscores)
602
+ factory.human_name.should == 'name with underscores'
603
+ end
604
+
605
+ end