masa-iwasaki-factory_girl 1.2.1.1 → 1.2.3.1

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