snowblink-factory_girl 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ class Factory
2
+
3
+ class Sequence
4
+
5
+ def initialize (&proc) #:nodoc:
6
+ @proc = proc
7
+ @value = 0
8
+ end
9
+
10
+ # Returns the next value for this sequence
11
+ def next
12
+ @value += 1
13
+ @proc.call(@value)
14
+ end
15
+
16
+ end
17
+
18
+ class << self
19
+ attr_accessor :sequences #:nodoc:
20
+ end
21
+ self.sequences = {}
22
+
23
+ # Defines a new sequence that can be used to generate unique values in a specific format.
24
+ #
25
+ # Arguments:
26
+ # name: (Symbol)
27
+ # A unique name for this sequence. This name will be referenced when
28
+ # calling next to generate new values from this sequence.
29
+ # block: (Proc)
30
+ # The code to generate each value in the sequence. This block will be
31
+ # called with a unique number each time a value in the sequence is to be
32
+ # generated. The block should return the generated value for the
33
+ # sequence.
34
+ #
35
+ # Example:
36
+ #
37
+ # Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }
38
+ def self.sequence (name, &block)
39
+ self.sequences[name] = Sequence.new(&block)
40
+ end
41
+
42
+ # Generates and returns the next value in a sequence.
43
+ #
44
+ # Arguments:
45
+ # name: (Symbol)
46
+ # The name of the sequence that a value should be generated for.
47
+ #
48
+ # Returns:
49
+ # The next value in the sequence. (Object)
50
+ def self.next (sequence)
51
+ unless self.sequences.key?(sequence)
52
+ raise "No such sequence: #{sequence}"
53
+ end
54
+
55
+ self.sequences[sequence].next
56
+ end
57
+
58
+ end
@@ -0,0 +1,29 @@
1
+ require(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class AliasesTest < Test::Unit::TestCase
4
+
5
+ should "include an attribute as an alias for itself by default" do
6
+ assert Factory.aliases_for(:test).include?(:test)
7
+ end
8
+
9
+ should "include the root of a foreign key as an alias by default" do
10
+ assert Factory.aliases_for(:test_id).include?(:test)
11
+ end
12
+
13
+ should "include an attribute's foreign key as an alias by default" do
14
+ assert Factory.aliases_for(:test).include?(:test_id)
15
+ end
16
+
17
+ context "after adding an alias" do
18
+
19
+ setup do
20
+ Factory.alias(/(.*)_suffix/, '\1')
21
+ end
22
+
23
+ should "return the alias in the aliases list" do
24
+ assert Factory.aliases_for(:test_suffix).include?(:test)
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,32 @@
1
+ require(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class AttributeTest < Test::Unit::TestCase
4
+
5
+ context "an attribute" do
6
+ setup do
7
+ @name = :user
8
+ @attr = Factory::Attribute.new(@name)
9
+ end
10
+
11
+ should "have a name" do
12
+ assert_equal @name, @attr.name
13
+ end
14
+
15
+ should "do nothing when being added to a proxy" do
16
+ @proxy = mock('proxy')
17
+ @proxy.expects(:set).never
18
+ @attr.add_to(@proxy)
19
+ end
20
+ end
21
+
22
+ should "raise an error when defining an attribute writer" do
23
+ assert_raise Factory::AttributeDefinitionError do
24
+ Factory::Attribute.new('test=')
25
+ end
26
+ end
27
+
28
+ should "convert names to symbols" do
29
+ assert_equal :name, Factory::Attribute.new('name').name
30
+ end
31
+
32
+ end
@@ -0,0 +1,410 @@
1
+ require(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class FactoryTest < Test::Unit::TestCase
4
+
5
+ context "defining a factory" do
6
+ setup do
7
+ @name = :user
8
+ @factory = mock('factory')
9
+ @factory.stubs(:factory_name).returns(@name)
10
+ @options = { :class => 'magic' }
11
+ Factory.stubs(:new).returns(@factory)
12
+ end
13
+
14
+ should "create a new factory using the specified name and options" do
15
+ Factory.expects(:new).with(@name, @options).returns(@factory)
16
+ Factory.define(@name, @options) {|f| }
17
+ end
18
+
19
+ should "pass the factory do the block" do
20
+ yielded = nil
21
+ Factory.define(@name) do |y|
22
+ yielded = y
23
+ end
24
+ assert_equal @factory, yielded
25
+ end
26
+
27
+ should "add the factory to the list of factories" do
28
+ Factory.define(@name) {|f| }
29
+ assert_equal Factory.factories[@name],
30
+ @factory,
31
+ "Factories: #{Factory.factories.inspect}"
32
+ end
33
+ end
34
+
35
+ context "a factory" do
36
+ setup do
37
+ @name = :user
38
+ @class = User
39
+ @factory = Factory.new(@name)
40
+ end
41
+
42
+ should "have a factory name" do
43
+ assert_equal @name, @factory.factory_name
44
+ end
45
+
46
+ should "have a build class" do
47
+ assert_equal @class, @factory.build_class
48
+ end
49
+
50
+ should "not allow the same attribute to be added twice" do
51
+ assert_raise(Factory::AttributeDefinitionError) do
52
+ 2.times { @factory.add_attribute :first_name }
53
+ end
54
+ end
55
+
56
+ should "add a static attribute when an attribute is defined with a value" do
57
+ attribute = mock('attribute', :name => :name)
58
+ Factory::Attribute::Static.
59
+ expects(:new).
60
+ with(:name, 'value').
61
+ returns(attribute)
62
+ @factory.add_attribute(:name, 'value')
63
+ end
64
+
65
+ should "add a dynamic attribute when an attribute is defined with a block" do
66
+ attribute = mock('attribute', :name => :name)
67
+ block = lambda {}
68
+ Factory::Attribute::Dynamic.
69
+ expects(:new).
70
+ with(:name, block).
71
+ returns(attribute)
72
+ @factory.add_attribute(:name, &block)
73
+ end
74
+
75
+ should "raise for an attribute with a value and a block" do
76
+ assert_raise(Factory::AttributeDefinitionError) do
77
+ @factory.add_attribute(:name, 'value') {}
78
+ end
79
+ end
80
+
81
+ context "after adding an attribute" do
82
+ setup do
83
+ @attribute = mock('attribute')
84
+ @proxy = mock('proxy')
85
+
86
+ @attribute. stubs(:name). returns(:name)
87
+ @attribute. stubs(:add_to)
88
+ @proxy. stubs(:set)
89
+ @proxy. stubs(:result).returns('result')
90
+ Factory::Attribute::Static.stubs(:new). returns(@attribute)
91
+ Factory::Proxy::Build. stubs(:new). returns(@proxy)
92
+
93
+ @factory.add_attribute(:name, 'value')
94
+ end
95
+
96
+ should "create the right proxy using the build class when running" do
97
+ Factory::Proxy::Build.
98
+ expects(:new).
99
+ with(@factory.build_class).
100
+ returns(@proxy)
101
+ @factory.run(Factory::Proxy::Build, {})
102
+ end
103
+
104
+ should "add the attribute to the proxy when running" do
105
+ @attribute.expects(:add_to).with(@proxy)
106
+ @factory.run(Factory::Proxy::Build, {})
107
+ end
108
+
109
+ should "return the result from the proxy when running" do
110
+ @proxy.expects(:result).with().returns('result')
111
+ assert_equal 'result',
112
+ @factory.run(Factory::Proxy::Build, {})
113
+ end
114
+ end
115
+
116
+ should "add an association without a factory name or overrides" do
117
+ factory = Factory.new(:post)
118
+ name = :user
119
+ attr = 'attribute'
120
+ Factory::Attribute::Association.
121
+ expects(:new).
122
+ with(name, name, {}).
123
+ returns(attr)
124
+ factory.association(name)
125
+ assert factory.attributes.include?(attr)
126
+ end
127
+
128
+ should "add an association with overrides" do
129
+ factory = Factory.new(:post)
130
+ name = :user
131
+ attr = 'attribute'
132
+ overrides = { :first_name => 'Ben' }
133
+ Factory::Attribute::Association.
134
+ expects(:new).
135
+ with(name, name, overrides).
136
+ returns(attr)
137
+ factory.association(name, overrides)
138
+ assert factory.attributes.include?(attr)
139
+ end
140
+
141
+ should "add an association with a factory name" do
142
+ factory = Factory.new(:post)
143
+ attr = 'attribute'
144
+ Factory::Attribute::Association.
145
+ expects(:new).
146
+ with(:author, :user, {}).
147
+ returns(attr)
148
+ factory.association(:author, :factory => :user)
149
+ assert factory.attributes.include?(attr)
150
+ end
151
+
152
+ should "add an association with a factory name and overrides" do
153
+ factory = Factory.new(:post)
154
+ attr = 'attribute'
155
+ Factory::Attribute::Association.
156
+ expects(:new).
157
+ with(:author, :user, :first_name => 'Ben').
158
+ returns(attr)
159
+ factory.association(:author, :factory => :user, :first_name => 'Ben')
160
+ assert factory.attributes.include?(attr)
161
+ end
162
+
163
+ should "add an attribute using the method name when passed an undefined method" do
164
+ attr = mock('attribute', :name => :name)
165
+ block = lambda {}
166
+ Factory::Attribute::Static.
167
+ expects(:new).
168
+ with(:name, 'value').
169
+ returns(attr)
170
+ @factory.send(:name, 'value')
171
+ assert @factory.attributes.include?(attr)
172
+ end
173
+
174
+ context "when overriding generated attributes with a hash" do
175
+ setup do
176
+ @attr = :name
177
+ @value = 'The price is right!'
178
+ @hash = { @attr => @value }
179
+ end
180
+
181
+ should "return the overridden value in the generated attributes" do
182
+ @factory.add_attribute(@attr, 'The price is wrong, Bob!')
183
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
184
+ assert_equal @value, result[@attr]
185
+ end
186
+
187
+ should "not call a lazy attribute block for an overridden attribute" do
188
+ @factory.add_attribute(@attr) { flunk }
189
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
190
+ end
191
+
192
+ should "override a symbol parameter with a string parameter" do
193
+ @factory.add_attribute(@attr, 'The price is wrong, Bob!')
194
+ @hash = { @attr.to_s => @value }
195
+ result = @factory.run(Factory::Proxy::AttributesFor, @hash)
196
+ assert_equal @value, result[@attr]
197
+ end
198
+ end
199
+
200
+ context "overriding an attribute with an alias" do
201
+ setup do
202
+ @factory.add_attribute(:test, 'original')
203
+ Factory.alias(/(.*)_alias/, '\1')
204
+ @result = @factory.run(Factory::Proxy::AttributesFor,
205
+ :test_alias => 'new')
206
+ end
207
+
208
+ should "use the passed in value for the alias" do
209
+ assert_equal 'new', @result[:test_alias]
210
+ end
211
+
212
+ should "discard the predefined value for the attribute" do
213
+ assert_nil @result[:test]
214
+ end
215
+ end
216
+
217
+ should "guess the build class from the factory name" do
218
+ assert_equal User, @factory.build_class
219
+ end
220
+
221
+ context "when defined with a custom class" do
222
+ setup do
223
+ @class = User
224
+ @factory = Factory.new(:author, :class => @class)
225
+ end
226
+
227
+ should "use the specified class as the build class" do
228
+ assert_equal @class, @factory.build_class
229
+ end
230
+ end
231
+
232
+ context "when defined with a class instead of a name" do
233
+ setup do
234
+ @class = ArgumentError
235
+ @name = :argument_error
236
+ @factory = Factory.new(@class)
237
+ end
238
+
239
+ should "guess the name from the class" do
240
+ assert_equal @name, @factory.factory_name
241
+ end
242
+
243
+ should "use the class as the build class" do
244
+ assert_equal @class, @factory.build_class
245
+ end
246
+ end
247
+
248
+ context "when defined with a custom class name" do
249
+ setup do
250
+ @class = ArgumentError
251
+ @factory = Factory.new(:author, :class => :argument_error)
252
+ end
253
+
254
+ should "use the specified class as the build class" do
255
+ assert_equal @class, @factory.build_class
256
+ end
257
+ end
258
+ end
259
+
260
+ context "a factory with a name ending in s" do
261
+ setup do
262
+ @name = :business
263
+ @class = Business
264
+ @factory = Factory.new(@name)
265
+ end
266
+
267
+ should "have a factory name" do
268
+ assert_equal @name, @factory.factory_name
269
+ end
270
+
271
+ should "have a build class" do
272
+ assert_equal @class, @factory.build_class
273
+ end
274
+ end
275
+
276
+ context "a factory with a string for a name" do
277
+ setup do
278
+ @name = :user
279
+ @factory = Factory.new(@name.to_s) {}
280
+ end
281
+
282
+ should "convert the string to a symbol" do
283
+ assert_equal @name, @factory.factory_name
284
+ end
285
+ end
286
+
287
+ context "a factory defined with a string name" do
288
+ setup do
289
+ Factory.factories = {}
290
+ @name = :user
291
+ @factory = Factory.define(@name.to_s) {}
292
+ end
293
+
294
+ should "store the factory using a symbol" do
295
+ assert_equal @factory, Factory.factories[@name]
296
+ end
297
+ end
298
+
299
+ context "after defining a factory" do
300
+ setup do
301
+ @name = :user
302
+ @factory = mock('factory')
303
+
304
+ Factory.factories[@name] = @factory
305
+ end
306
+
307
+ teardown { Factory.factories.clear }
308
+
309
+ should "use Proxy::AttributesFor for Factory.attributes_for" do
310
+ @factory.
311
+ expects(:run).
312
+ with(Factory::Proxy::AttributesFor, :attr => 'value').
313
+ returns('result')
314
+ assert_equal 'result', Factory.attributes_for(@name, :attr => 'value')
315
+ end
316
+
317
+ should "use Proxy::Build for Factory.build" do
318
+ @factory.
319
+ expects(:run).
320
+ with(Factory::Proxy::Build, :attr => 'value').
321
+ returns('result')
322
+ assert_equal 'result', Factory.build(@name, :attr => 'value')
323
+ end
324
+
325
+ should "use Proxy::Create for Factory.create" do
326
+ @factory.
327
+ expects(:run).
328
+ with(Factory::Proxy::Create, :attr => 'value').
329
+ returns('result')
330
+ assert_equal 'result', Factory.create(@name, :attr => 'value')
331
+ end
332
+
333
+ should "use Proxy::Create for the global Factory method" do
334
+ @factory.
335
+ expects(:run).
336
+ with(Factory::Proxy::Create, :attr => 'value').
337
+ returns('result')
338
+ assert_equal 'result', Factory(@name, :attr => 'value')
339
+ end
340
+
341
+ [:build, :create, :attributes_for].each do |method|
342
+ should "raise an ArgumentError on #{method} with a nonexistant factory" do
343
+ assert_raise(ArgumentError) { Factory.send(method, :bogus) }
344
+ end
345
+
346
+ should "recognize either 'name' or :name for Factory.#{method}" do
347
+ @factory.stubs(:run)
348
+ assert_nothing_raised { Factory.send(method, @name.to_s) }
349
+ assert_nothing_raised { Factory.send(method, @name.to_sym) }
350
+ end
351
+ end
352
+ end
353
+
354
+ def self.context_in_directory_with_files(*files)
355
+ context "in a directory with #{files.to_sentence}" do
356
+ setup do
357
+ @pwd = Dir.pwd
358
+ @tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
359
+ FileUtils.mkdir_p @tmp_dir
360
+ Dir.chdir(@tmp_dir)
361
+
362
+ files.each do |file|
363
+ FileUtils.mkdir_p File.dirname(file)
364
+ FileUtils.touch file
365
+ Factory.stubs(:require).with(file)
366
+ end
367
+ end
368
+
369
+ teardown do
370
+ Dir.chdir(@pwd)
371
+ FileUtils.rm_rf(@tmp_dir)
372
+ end
373
+
374
+ yield
375
+ end
376
+ end
377
+
378
+ def self.should_require_definitions_from(file)
379
+ should "load definitions from #{file}" do
380
+ Factory.expects(:require).with(file)
381
+ Factory.find_definitions
382
+ end
383
+ end
384
+
385
+ context_in_directory_with_files 'factories.rb' do
386
+ should_require_definitions_from 'factories.rb'
387
+ end
388
+
389
+ %w(spec test).each do |dir|
390
+ context_in_directory_with_files File.join(dir, 'factories.rb') do
391
+ should_require_definitions_from "#{dir}/factories.rb"
392
+ end
393
+
394
+ context_in_directory_with_files File.join(dir, 'factories', 'post_factory.rb') do
395
+ should_require_definitions_from "#{dir}/factories/post_factory.rb"
396
+ end
397
+
398
+ context_in_directory_with_files File.join(dir, 'factories', 'post_factory.rb'), File.join(dir, 'factories', 'person_factory.rb') do
399
+ should_require_definitions_from "#{dir}/factories/post_factory.rb"
400
+ should_require_definitions_from "#{dir}/factories/person_factory.rb"
401
+ end
402
+
403
+ context_in_directory_with_files File.join(dir, 'factories.rb'), File.join(dir, 'factories', 'post_factory.rb'), File.join(dir, 'factories', 'person_factory.rb') do
404
+ should_require_definitions_from "#{dir}/factories.rb"
405
+ should_require_definitions_from "#{dir}/factories/post_factory.rb"
406
+ should_require_definitions_from "#{dir}/factories/person_factory.rb"
407
+ end
408
+ end
409
+
410
+ end