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.
- data/MIT-LICENSE +20 -0
- data/Manifest +17 -0
- data/README.rdoc +113 -0
- data/Rakefile +41 -0
- data/active_factory.gemspec +30 -0
- data/init.rb +1 -0
- data/lib/active_factory.rb +480 -0
- data/lib/generators/active_factory/install/USAGE +2 -0
- data/lib/generators/active_factory/install/install_generator.rb +15 -0
- data/lib/generators/active_factory/install/templates/active_factory.rb +9 -0
- data/lib/generators/active_factory/install/templates/define_factories.rb +7 -0
- data/lib/hash_struct.rb +16 -0
- data/spec/active_factory_define_spec.rb +95 -0
- data/spec/active_factory_spec.rb +324 -0
- data/spec/active_record_environment_spec.rb +14 -0
- data/spec/define_lib_factories.rb +39 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/active_record_environment.rb +46 -0
- metadata +75 -0
@@ -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__
|
data/lib/hash_struct.rb
ADDED
@@ -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
|