active_factory 0.1.0

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.
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Copy ActiveFactory files to your application.
@@ -0,0 +1,15 @@
1
+ module ActiveFactory
2
+ module Generators #:nodoc:
3
+ class InstallGenerator < Rails::Generators::Base #:nodoc:
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def define_factories_file
7
+ copy_file "define_factories.rb", "spec/define_factories.rb"
8
+ end
9
+
10
+ def active_factory_file
11
+ copy_file "active_factory.rb", "spec/support/active_factory.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_factory'
2
+
3
+ RSpec::configure do |config|
4
+ config.include ActiveFactory::API, :type => :controller
5
+ config.include ActiveFactory::API, :type => :model
6
+ config.include ActiveFactory::API, :type => :request
7
+ end
8
+
9
+ require File.expand_path "../../define_factories", __FILE__
@@ -0,0 +1,7 @@
1
+ class ActiveFactory::Define
2
+ # define your factories here, e.g.
3
+ #
4
+ # factory :post, :class => Post do
5
+ # title { "example title #{index}" }
6
+ # end
7
+ end
@@ -0,0 +1,16 @@
1
+ class HashStruct < Hash
2
+ def initialize hash
3
+ merge! hash
4
+ keys.each { |key|
5
+ eval %{ def self.#{key}; self[:#{key}] end }
6
+ }
7
+ end
8
+
9
+ def self.[] hash
10
+ new Hash[hash]
11
+ end
12
+
13
+ def merge *args
14
+ HashStruct.new(super(*args))
15
+ end
16
+ end
@@ -0,0 +1,95 @@
1
+ require 'support/active_record_environment'
2
+ require 'active_factory'
3
+ require "#{File.dirname(__FILE__)}/spec_helper"
4
+ require "#{File.dirname(__FILE__)}/define_lib_factories"
5
+
6
+ describe ActiveFactory::Define do
7
+ include ActiveFactory::API
8
+ include Test::Unit::Assertions
9
+ include ActiveRecordEnvironment
10
+
11
+ before(:each) do
12
+ empty_database!
13
+ end
14
+
15
+ describe "Processes factory definitions:" do
16
+
17
+ def get_factory name
18
+ ActiveFactory::Define.factories_hash[name]
19
+ end
20
+
21
+ it "with explicit class and explicit values for attributes" do
22
+ factory = get_factory :simple_user
23
+ factory.model_class.should == User
24
+ factory.after_build.should == nil
25
+ factory.prefer_associations.should == nil
26
+ factory.attributes_for(0).should ==
27
+ {:email => 'simple_user@gmail.com',
28
+ :password => 'simple_password'}
29
+ end
30
+
31
+ it "with implicit class and blocks for attributes" do
32
+ factory = get_factory :user
33
+ factory.model_class.should == User
34
+ factory.after_build.should == nil
35
+ factory.prefer_associations.should == nil
36
+ factory.attributes_for(0).should ==
37
+ {:email => 'user0@tut.by',
38
+ :password => 'password00'}
39
+ factory.attributes_for(1).should ==
40
+ {:email => 'user1@tut.by',
41
+ :password => 'password11'}
42
+ end
43
+
44
+ it "with explicit class and blocks for attributes" do
45
+ factory = get_factory :post
46
+ factory.model_class.should == Post
47
+ factory.after_build.should == nil
48
+ factory.prefer_associations.should == nil
49
+ factory.attributes_for(0).should ==
50
+ {:text => "Content 0"}
51
+ end
52
+
53
+ it "with after_build block" do
54
+ factory = get_factory :post_with_after_build
55
+ factory.model_class.should == Post
56
+ factory.after_build.should be_an_instance_of Proc
57
+ factory.prefer_associations.should == nil
58
+ factory.attributes_for(0).should ==
59
+ {:text => "Post with after_build"}
60
+
61
+ post = mock "Post"
62
+ post.should_receive(:text=).with("After Build 0").and_return(nil)
63
+ factory.apply_after_build 0, nil, post
64
+ end
65
+
66
+ it "with before_save block" do
67
+ factory = get_factory :post_with_before_save
68
+ factory.model_class.should == Post
69
+ factory.before_save.should be_an_instance_of Proc
70
+ factory.prefer_associations.should == nil
71
+ factory.attributes_for(0).should ==
72
+ {:text => "Post with before_save"}
73
+
74
+ post = mock "Post"
75
+ post.should_receive(:text=).with("Before Save 0").and_return(nil)
76
+ factory.apply_before_save 0, nil, post
77
+ end
78
+
79
+ it "with preferred associations" do
80
+ factory = get_factory :follower
81
+ factory.prefer_associations.should == [:following]
82
+ end
83
+
84
+ it "with parent" do
85
+ factory = get_factory :user_with_parent
86
+ factory.name.should == :user_with_parent
87
+ factory.parent.name.should == :user
88
+ factory.model_class.should == User
89
+ factory.attributes_for(0).should == {
90
+ :email => "user0@tut.by",
91
+ :password => "overriden"
92
+ }
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,324 @@
1
+ require 'support/active_record_environment'
2
+ require 'active_factory'
3
+ require "#{File.dirname(__FILE__)}/spec_helper"
4
+ require "#{File.dirname(__FILE__)}/define_lib_factories"
5
+
6
+ describe "ActiveFactory" do
7
+ include ActiveFactory::API
8
+ include Test::Unit::Assertions
9
+ include ActiveRecordEnvironment
10
+
11
+ before(:each) do
12
+ empty_database!
13
+ end
14
+
15
+ # INTRODUCING METHODS
16
+
17
+ it "defines methods in models{} section to declare a singleton object and hash, collection of objects and hashes" do
18
+ models {
19
+ respond_to?(:user).should == true
20
+ respond_to?(:user_).should == true
21
+ respond_to?(:users).should == true
22
+ respond_to?(:users_).should == true
23
+
24
+ respond_to?(:simple_user).should == true
25
+ respond_to?(:follower).should == true
26
+ respond_to?(:post).should == true
27
+ }
28
+ end
29
+
30
+ it "defines methods in the current spec context to access a singleton object, a singleton hash, a collection and a collection of hashes" do
31
+ models { user }
32
+
33
+ respond_to?(:user).should == true
34
+ respond_to?(:user_).should == true
35
+ respond_to?(:users).should == true
36
+ respond_to?(:users_).should == true
37
+
38
+ respond_to?(:post).should == false
39
+ respond_to?(:post_).should == false
40
+ respond_to?(:posts).should == false
41
+ respond_to?(:posts_).should == false
42
+ end
43
+
44
+ it "vice versa" do
45
+ models { post }
46
+
47
+ respond_to?(:post).should == true
48
+ respond_to?(:user).should == false
49
+ end
50
+
51
+ # CREATING IN MODELS SECTION
52
+
53
+ it "creates singleton model without blocks and with explicit class" do
54
+ models { simple_user }
55
+
56
+ simple_user.email.should == "simple_user@gmail.com"
57
+ simple_user.password.should == "simple_password"
58
+ simple_user.should be_an_instance_of User
59
+ simple_user.should_not be_new_record
60
+
61
+ User.all.should == [simple_user]
62
+ end
63
+
64
+ it "creates singleton model 'user' with index and implicit class" do
65
+ models { user }
66
+
67
+ user.email.should == "user0@tut.by"
68
+ user.password.should == "password00"
69
+
70
+ user.should be_an_instance_of User
71
+ user.should_not be_new_record
72
+
73
+ User.all.should == [user]
74
+ end
75
+
76
+ it "creates a collection" do
77
+ models { users(2) }
78
+
79
+ users[0].email.should == "user0@tut.by"
80
+ users[1].email.should == "user1@tut.by"
81
+ users[1].password.should == "password11"
82
+
83
+ users.size.should == 2
84
+ User.all.should == users
85
+ end
86
+
87
+ it "collection(i) adds specified number of new instances to a collection" do
88
+ models { users(1); users(2) }
89
+
90
+ users[0].email.should == "user0@tut.by"
91
+ users[1].email.should == "user1@tut.by"
92
+ users[2].email.should == "user2@tut.by"
93
+
94
+ users.size.should == 3
95
+ User.all.should == users
96
+ end
97
+
98
+ it "collection() syntax allows to refer to all entities already created by a factory" do
99
+ models { users }
100
+
101
+ users.size.should == 0
102
+ end
103
+
104
+ it "collection(1) syntax creates additional instance" do
105
+ models { user; users(1) }
106
+
107
+ users[0].email.should == "user0@tut.by"
108
+ users[1].email.should == "user1@tut.by"
109
+
110
+ users.size.should == 2
111
+ end
112
+
113
+ it "singleton syntax does not create additional instances, if it already exist" do
114
+ models { users(1); user }
115
+
116
+ users.size.should == 1
117
+
118
+ User.all.should == users
119
+ end
120
+
121
+ it "cannot use singleton syntax when many instances are created" do
122
+ assert_raise RuntimeError do
123
+ models { users(2); user }
124
+ end
125
+ end
126
+
127
+ # HASHES IN PRODUCE SECTION
128
+
129
+ it "singleton syntax defines 'user_' method to access a hash" do
130
+ models { user } #.define_all
131
+
132
+ user_.should == {:email => "user0@tut.by", :password => "password00" }
133
+ user.should be_an_instance_of User
134
+ end
135
+
136
+ it "declares hash without creating an object" do
137
+ models { user_ }
138
+
139
+ user_.should == {:email => "user0@tut.by", :password => "password00" }
140
+ user.should == nil
141
+
142
+ User.all.should == []
143
+ end
144
+
145
+ it "defines symbols 'users' and 'users_' for a collection" do
146
+ models { users(1) } #.define_all
147
+
148
+ users[0].email.should == "user0@tut.by"
149
+ users_[0].email.should == "user0@tut.by"
150
+ users[0].should_not be_new_record
151
+
152
+ users.size.should == 1
153
+ User.all.should == users
154
+ end
155
+
156
+ it "declares many hashes without creating" do
157
+ models { posts_(2) }
158
+
159
+ posts_[0].text.should == "Content 0"
160
+ posts_[1].text.should == "Content 1"
161
+
162
+ Post.all.should == []
163
+ end
164
+
165
+ it "" do
166
+ models { users(1) ; users_(1); users(1) }
167
+
168
+ users[0].should be_an_instance_of User
169
+ users[1].should be_an_instance_of NilClass
170
+ users[2].should be_an_instance_of User
171
+ end
172
+
173
+ # LINKING
174
+
175
+ it "associates through belongs_to" do
176
+ models { post - user }
177
+
178
+ post.user.should == user
179
+ user.posts.should == [post]
180
+
181
+ Post.all.should == [post]
182
+ Post.all.map(&:user).should == [user]
183
+ end
184
+
185
+ it "associates through has_many" do
186
+ models { user - post }
187
+
188
+ post.user.should == user
189
+ user.posts.should == [post]
190
+
191
+ User.all.should == [user]
192
+ User.all.map(&:posts).should == [[post]]
193
+ end
194
+
195
+ it "associates singleton and collection" do
196
+ models { user - posts(2) }
197
+
198
+ user.posts.should == posts
199
+ posts.map(&:user).should == [user, user]
200
+
201
+ User.all.should == [user]
202
+ User.all.map(&:posts).should =~ [posts]
203
+ end
204
+
205
+ it "associates collections" do
206
+ models { posts(3) - users(1) }
207
+
208
+ _posts = 3.times.map { |n| Post.find_by_text("Content #{n}") }
209
+
210
+ user.posts.all.should == _posts
211
+ end
212
+
213
+ it "zips links" do
214
+ models { users(2) - posts(2) }
215
+
216
+ 2.times { |i|
217
+ posts[i].user_id.should == users[i].id
218
+ }
219
+
220
+ Post.all.should =~ posts
221
+ Post.all.map(&:user).should =~ users
222
+ end
223
+
224
+ it "it associates only specified number of posts, not all" do
225
+ models { posts(1); posts(1) - user }
226
+
227
+ posts[0].user.should == nil
228
+ posts[1].user.should == user
229
+
230
+ Post.all.map(&:user).should =~ [nil, user]
231
+ end
232
+
233
+ # ADVANCED FACTORY OPTIONS
234
+
235
+ it "uses prefer_associations option to disambiguate associations (followers & following)" do
236
+ models { follower - user }
237
+
238
+ follower.following.should == [user]
239
+ follower.followers.should == []
240
+
241
+ User.all.should =~ [follower, user]
242
+ end
243
+
244
+ it "allows to redefine prefer_associations" do
245
+ models { follower - :followers - user }
246
+
247
+ follower.followers.should == [user]
248
+ follower.following.should == []
249
+
250
+ User.all.should =~ [follower, user]
251
+ end
252
+
253
+ it "invokes after_build" do
254
+ models { post_with_after_build }
255
+
256
+ post_with_after_build.text.should == "After Build 0"
257
+ end
258
+
259
+ it "provides methods for hash keys" do
260
+ models { post_with_after_builds(1) }
261
+
262
+ post_with_after_builds_[0].text.should == "Post with after_build"
263
+ end
264
+
265
+ it "syntax sugar to merge" do
266
+ models { user_ }
267
+
268
+ user_(:text => "new@email.com").should == user_.merge(:text => "new@email.com")
269
+ end
270
+
271
+ it "syntax sugar for update_attribute" do
272
+ models { simple_user(:email => "modified@email.com") }
273
+
274
+ simple_user.email.should == "modified@email.com"
275
+ end
276
+
277
+ it "syntax sugar for update_attribute for multiple instances" do
278
+ models { simple_users({:email => "1st@email.com"}, {:email => "2nd@email.com"})}
279
+
280
+ simple_users.size.should == 2
281
+ simple_users[0].email.should == "1st@email.com"
282
+ simple_users[1].email.should == "2nd@email.com"
283
+ end
284
+
285
+ # MORE
286
+
287
+ it "leaves no coincidental methods in following specs" do
288
+ models { post_overrides_method }
289
+
290
+ assert_raise(NameError) { simple_user }
291
+ assert_raise(NameError) { simple_user_ }
292
+ assert_raise(NameError) { simple_users }
293
+ assert_raise(NameError) { simple_users_ }
294
+ assert_raise(NameError) { post }
295
+ end
296
+
297
+ def post_overrides_method_; "invoke function" end
298
+
299
+ it "preserves old methods" do
300
+ post_overrides_method_.should == "invoke function"
301
+ end
302
+
303
+ def some_method
304
+ :some_outer_method_result
305
+ end
306
+
307
+ it "outer methods are accessible in models {} section" do
308
+ should_receive(:some_method).with(:some_arg, 1).and_return(:some_result)
309
+
310
+ models { some_method(:some_arg, 1).should == :some_result }
311
+ end
312
+
313
+ it "#factory_attributes returns attributes" do
314
+
315
+ assert_equal({:text => "Content 1"}, self.class.class_eval { factory_attributes(:post, 1) })
316
+ end
317
+
318
+ it "::Define.models[:user] is model" do
319
+ factory = ActiveFactory::Define.factories_hash[:user]
320
+
321
+ assert factory
322
+ factory.model_class.should == User
323
+ end
324
+ end