JamieFlournoy-machinist 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,200 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'machinist/active_record'
3
+ require 'active_support/whiny_nil'
4
+
5
+ module MachinistActiveRecordSpecs
6
+
7
+ class Person < ActiveRecord::Base
8
+ attr_protected :password
9
+ end
10
+
11
+ class Admin < Person
12
+ end
13
+
14
+ class Post < ActiveRecord::Base
15
+ has_many :comments
16
+ end
17
+
18
+ class Comment < ActiveRecord::Base
19
+ belongs_to :post
20
+ belongs_to :author, :class_name => "Person"
21
+ end
22
+
23
+ describe Machinist, "ActiveRecord adapter" do
24
+ before(:suite) do
25
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/log/test.log")
26
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
27
+ load(File.dirname(__FILE__) + "/db/schema.rb")
28
+ end
29
+
30
+ before(:each) do
31
+ [Person, Admin, Post, Comment].each(&:clear_blueprints!)
32
+ end
33
+
34
+ describe "make method" do
35
+ it "should support single-table inheritance" do
36
+ Person.blueprint { }
37
+ Admin.blueprint { }
38
+ admin = Admin.make
39
+ admin.should_not be_new_record
40
+ admin.type.should == "Admin"
41
+ end
42
+
43
+ it "should save the constructed object" do
44
+ Person.blueprint { }
45
+ person = Person.make
46
+ person.should_not be_new_record
47
+ end
48
+
49
+ it "should create an object through belongs_to association" do
50
+ Post.blueprint { }
51
+ Comment.blueprint { post }
52
+ Comment.make.post.class.should == Post
53
+ end
54
+
55
+ it "should create an object through belongs_to association with a class_name attribute" do
56
+ Person.blueprint { }
57
+ Comment.blueprint { author }
58
+ Comment.make.author.class.should == Person
59
+ end
60
+
61
+ it "should create an object through belongs_to association using a named blueprint" do
62
+ Post.blueprint { }
63
+ Post.blueprint(:dummy) do
64
+ title { 'Dummy Post' }
65
+ end
66
+ Comment.blueprint { post(:dummy) }
67
+ Comment.make.post.title.should == 'Dummy Post'
68
+ end
69
+
70
+ it "should allow creating an object through a has_many association" do
71
+ Post.blueprint do
72
+ comments { [Comment.make] }
73
+ end
74
+ Comment.blueprint { }
75
+ Post.make.comments.should have(1).instance_of(Comment)
76
+ end
77
+
78
+ it "should allow setting a protected attribute in the blueprint" do
79
+ Person.blueprint do
80
+ password { "Test" }
81
+ end
82
+ Person.make.password.should == "Test"
83
+ end
84
+
85
+ it "should allow overriding a protected attribute" do
86
+ Person.blueprint do
87
+ password { "Test" }
88
+ end
89
+ Person.make(:password => "New").password.should == "New"
90
+ end
91
+
92
+ it "should allow setting the id attribute in a blueprint" do
93
+ Person.blueprint do
94
+ id { 12345 }
95
+ end
96
+ Person.make.id.should == 12345
97
+ end
98
+
99
+ it "should allow setting the type attribute in a blueprint" do
100
+ Person.blueprint do
101
+ type { "Person" }
102
+ end
103
+ Person.make.type.should == "Person"
104
+ end
105
+
106
+ describe "on a has_many association" do
107
+ before do
108
+ Post.blueprint { }
109
+ Comment.blueprint { post }
110
+ @post = Post.make
111
+ @comment = @post.comments.make
112
+ end
113
+
114
+ it "should save the created object" do
115
+ @comment.should_not be_new_record
116
+ end
117
+
118
+ it "should set the parent association on the created object" do
119
+ @comment.post.should == @post
120
+ end
121
+ end
122
+ end
123
+
124
+ describe "plan method" do
125
+ it "should not save the constructed object" do
126
+ person_count = Person.count
127
+ Person.blueprint { }
128
+ person = Person.plan
129
+ Person.count.should == person_count
130
+ end
131
+
132
+ it "should create an object through a belongs_to association, and return its id" do
133
+ Post.blueprint { }
134
+ Comment.blueprint { post }
135
+ post_count = Post.count
136
+ comment = Comment.plan
137
+ Post.count.should == post_count + 1
138
+ comment[:post].should be_nil
139
+ comment[:post_id].should_not be_nil
140
+ end
141
+
142
+ describe "on a belongs_to association" do
143
+ it "should allow explicitly setting the association to nil" do
144
+ Comment.blueprint { post }
145
+ Comment.blueprint(:no_post) { post { nil } }
146
+ lambda {
147
+ @comment = Comment.plan(:no_post)
148
+ }.should_not raise_error
149
+ end
150
+ end
151
+
152
+ describe "on a has_many association" do
153
+ before do
154
+ Post.blueprint { }
155
+ Comment.blueprint do
156
+ post
157
+ body { "Test" }
158
+ end
159
+ @post = Post.make
160
+ @post_count = Post.count
161
+ @comment = @post.comments.plan
162
+ end
163
+
164
+ it "should not include the parent in the returned hash" do
165
+ @comment[:post].should be_nil
166
+ @comment[:post_id].should be_nil
167
+ end
168
+
169
+ it "should not create an extra parent object" do
170
+ Post.count.should == @post_count
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "make_unsaved method" do
176
+ it "should not save the constructed object" do
177
+ Person.blueprint { }
178
+ person = Person.make_unsaved
179
+ person.should be_new_record
180
+ end
181
+
182
+ it "should not save associated objects" do
183
+ Post.blueprint { }
184
+ Comment.blueprint { post }
185
+ comment = Comment.make_unsaved
186
+ comment.post.should be_new_record
187
+ end
188
+
189
+ it "should save objects made within a passed-in block" do
190
+ Post.blueprint { }
191
+ Comment.blueprint { }
192
+ comment = nil
193
+ post = Post.make_unsaved { comment = Comment.make }
194
+ post.should be_new_record
195
+ comment.should_not be_new_record
196
+ end
197
+ end
198
+
199
+ end
200
+ end
@@ -0,0 +1,136 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'machinist/data_mapper'
3
+ require 'dm-validations'
4
+
5
+ module MachinistDataMapperSpecs
6
+
7
+ class Person
8
+ include DataMapper::Resource
9
+ property :id, Serial
10
+ property :name, String, :length => (0..10)
11
+ property :type, Discriminator
12
+ property :password, String
13
+ property :admin, Boolean, :default => false
14
+ end
15
+
16
+ class Admin < Person
17
+ end
18
+
19
+ class Post
20
+ include DataMapper::Resource
21
+ property :id, Serial
22
+ property :title, String
23
+ property :body, Text
24
+ property :published, Boolean, :default => true
25
+ has n, :comments
26
+ end
27
+
28
+ class Comment
29
+ include DataMapper::Resource
30
+ property :id, Serial
31
+ property :post_id, Integer
32
+ property :author_id, Integer
33
+ belongs_to :post
34
+ belongs_to :author, :model => "Person", :child_key => [:author_id]
35
+ end
36
+
37
+ describe Machinist, "DataMapper adapter" do
38
+ before(:suite) do
39
+ DataMapper::Logger.new(File.dirname(__FILE__) + "/log/test.log", :debug)
40
+ DataMapper.setup(:default, "sqlite3::memory:")
41
+ DataMapper.auto_migrate!
42
+ end
43
+
44
+ before(:each) do
45
+ [Person, Admin, Post, Comment].each(&:clear_blueprints!)
46
+ end
47
+
48
+ describe "make method" do
49
+ it "should support inheritance" do
50
+ Person.blueprint {}
51
+ Admin.blueprint {}
52
+
53
+ admin = Admin.make
54
+ admin.should_not be_new
55
+ admin.type.should_not be_nil
56
+ end
57
+
58
+ it "should save the constructed object" do
59
+ Person.blueprint { }
60
+ person = Person.make
61
+ person.should_not be_new
62
+ end
63
+
64
+ it "should create an object through a belongs_to association" do
65
+ Post.blueprint { }
66
+ Comment.blueprint { post }
67
+ Comment.make.post.class.should == Post
68
+ end
69
+
70
+
71
+ it "should create an object through a belongs_to association with a class_name attribute" do
72
+ Person.blueprint { }
73
+ Comment.blueprint { author }
74
+ Comment.make.author.class.should == Person
75
+ end
76
+
77
+ it "should raise an exception if the object can't be saved" do
78
+ Person.blueprint { }
79
+ lambda { Person.make(:name => "More than ten characters") }.should raise_error(RuntimeError)
80
+ end
81
+ end
82
+
83
+ describe "plan method" do
84
+ it "should not save the constructed object" do
85
+ person_count = Person.all.length
86
+ Person.blueprint { }
87
+ person = Person.plan
88
+ Person.all.length.should == person_count
89
+ end
90
+
91
+ it "should return a regular attribute in the hash" do
92
+ Post.blueprint do
93
+ title { "Test" }
94
+ end
95
+ post = Post.plan
96
+ post[:title].should == "Test"
97
+ end
98
+
99
+ it "should create an object through a belongs_to association, and return its id" do
100
+ Post.blueprint { }
101
+ Comment.blueprint { post }
102
+ post_count = Post.all.length
103
+ comment = Comment.plan
104
+ Post.all.length.should == post_count + 1
105
+ comment[:post].should be_nil
106
+ comment[:post_id].should_not be_nil
107
+ end
108
+ end
109
+
110
+ describe "make_unsaved method" do
111
+ it "should not save the constructed object" do
112
+ Person.blueprint { }
113
+ person = Person.make_unsaved
114
+ person.should be_new
115
+ end
116
+
117
+ it "should not save associated objects" do
118
+ Post.blueprint { }
119
+ Comment.blueprint { post }
120
+ comment = Comment.make_unsaved
121
+ comment.post.should be_new
122
+ end
123
+
124
+ it "should save objects made within a passed-in block" do
125
+ Post.blueprint { }
126
+ Comment.blueprint { }
127
+ comment = nil
128
+ post = Post.make_unsaved { comment = Comment.make }
129
+ post.should be_new
130
+ comment.should_not be_new
131
+ end
132
+ end
133
+
134
+ end
135
+ end
136
+
@@ -0,0 +1 @@
1
+ *.sqlite3
data/spec/db/schema.rb ADDED
@@ -0,0 +1,20 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :people, :force => true do |t|
3
+ t.column :name, :string
4
+ t.column :type, :string
5
+ t.column :password, :string
6
+ t.column :admin, :boolean, :default => false
7
+ end
8
+
9
+ create_table :posts, :force => true do |t|
10
+ t.column :title, :string
11
+ t.column :body, :text
12
+ t.column :published, :boolean, :default => true
13
+ end
14
+
15
+ create_table :comments, :force => true do |t|
16
+ t.column :post_id, :integer
17
+ t.column :author_id, :integer
18
+ t.column :body, :text
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,208 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'machinist/object'
3
+
4
+ module MachinistSpecs
5
+
6
+ class Person
7
+ attr_accessor :name, :admin
8
+ end
9
+
10
+ class Post
11
+ attr_accessor :title, :body, :published
12
+ end
13
+
14
+ class Grandpa
15
+ attr_accessor :name
16
+ end
17
+
18
+ class Dad < Grandpa
19
+ attr_accessor :name
20
+ end
21
+
22
+ class Son < Dad
23
+ attr_accessor :name
24
+ end
25
+
26
+ describe Machinist do
27
+ before(:each) do
28
+ [Person, Post, Grandpa, Dad, Son].each(&:clear_blueprints!)
29
+ end
30
+
31
+ it "should raise for make on a class with no blueprint" do
32
+ lambda { Person.make }.should raise_error(RuntimeError, "No blueprint for class MachinistSpecs::Person")
33
+ end
34
+
35
+ it "should set an attribute on the constructed object from a constant in the blueprint" do
36
+ Person.blueprint do
37
+ name "Fred"
38
+ end
39
+ Person.make.name.should == "Fred"
40
+ end
41
+
42
+ it "should set an attribute on the constructed object from a block in the blueprint" do
43
+ Person.blueprint do
44
+ name { "Fred" }
45
+ end
46
+ Person.make.name.should == "Fred"
47
+ end
48
+
49
+ it "should default to calling Sham for an attribute in the blueprint" do
50
+ Sham.clear
51
+ Sham.name { "Fred" }
52
+ Person.blueprint { name }
53
+ Person.make.name.should == "Fred"
54
+ end
55
+
56
+ it "should let the blueprint override an attribute with a default value" do
57
+ Post.blueprint do
58
+ published { false }
59
+ end
60
+ Post.make.published.should be_false
61
+ end
62
+
63
+ it "should allow overridden attribute names to be strings" do
64
+ Person.blueprint do
65
+ name { "Fred" }
66
+ end
67
+ Person.make("name" => "Bill").name.should == "Bill"
68
+ end
69
+
70
+ it "should override an attribute from the blueprint with a passed-in attribute" do
71
+ block_called = false
72
+ Person.blueprint do
73
+ name { block_called = true; "Fred" }
74
+ end
75
+ Person.make(:name => "Bill").name.should == "Bill"
76
+ block_called.should be_false
77
+ end
78
+
79
+ it "should call a passed-in block with the object being constructed" do
80
+ Person.blueprint { }
81
+ block_called = false
82
+ Person.make do |person|
83
+ block_called = true
84
+ person.class.should == Person
85
+ end
86
+ block_called.should be_true
87
+ end
88
+
89
+ it "should provide access to the object being constructed from within the blueprint" do
90
+ person = nil
91
+ Person.blueprint { person = object }
92
+ Person.make
93
+ person.class.should == Person
94
+ end
95
+
96
+ it "should allow reading of a previously assigned attribute from within the blueprint" do
97
+ Post.blueprint do
98
+ title { "Test" }
99
+ body { title }
100
+ end
101
+ Post.make.body.should == "Test"
102
+ end
103
+
104
+ describe "named blueprints" do
105
+ before do
106
+ @block_called = false
107
+ Person.blueprint do
108
+ name { "Fred" }
109
+ admin { @block_called = true; false }
110
+ end
111
+ Person.blueprint(:admin) do
112
+ admin { true }
113
+ end
114
+ @person = Person.make(:admin)
115
+ end
116
+
117
+ it "should override an attribute from the parent blueprint in the child blueprint" do
118
+ @person.admin.should == true
119
+ end
120
+
121
+ it "should not call the block for an attribute from the parent blueprint if that attribute is overridden in the child" do
122
+ @block_called.should be_false
123
+ end
124
+
125
+ it "should set an attribute defined in the parent blueprint" do
126
+ @person.name.should == "Fred"
127
+ end
128
+
129
+ it "should return the correct list of named blueprints" do
130
+ Person.blueprint(:foo) { }
131
+ Person.blueprint(:bar) { }
132
+ Person.named_blueprints.to_set.should == [:admin, :foo, :bar].to_set
133
+ end
134
+
135
+ it "should raise exception for make if named blueprint is not defined" do
136
+ lambda { Person.make(:bogus) }.should raise_error(
137
+ RuntimeError, "No blueprint named 'bogus' defined for class MachinistSpecs::Person"
138
+ )
139
+ end
140
+
141
+ it "should raise a sensible error when calling a named blueprint with no master" do
142
+ Post.blueprint(:foo) { }
143
+ lambda { Post.make(:foo) }.should raise_error(
144
+ RuntimeError, "Can't construct an object from a named blueprint without a default blueprint for class MachinistSpecs::Post"
145
+ )
146
+ end
147
+ end
148
+
149
+ describe "blueprint inheritance" do
150
+ it "should inherit blueprinted attributes from the parent class" do
151
+ Dad.blueprint do
152
+ name { "Fred" }
153
+ end
154
+ Son.blueprint { }
155
+ Son.make.name.should == "Fred"
156
+ end
157
+
158
+ it "should override blueprinted attributes in the child class" do
159
+ Dad.blueprint do
160
+ name { "Fred" }
161
+ end
162
+ Son.blueprint do
163
+ name { "George" }
164
+ end
165
+ Dad.make.name.should == "Fred"
166
+ Son.make.name.should == "George"
167
+ end
168
+
169
+ it "should inherit from blueprinted attributes in ancestor class" do
170
+ Grandpa.blueprint do
171
+ name { "Fred" }
172
+ end
173
+ Son.blueprint { }
174
+ Grandpa.make.name.should == "Fred"
175
+ lambda { Dad.make }.should raise_error(RuntimeError)
176
+ Son.make.name.should == "Fred"
177
+ end
178
+
179
+ it "should follow inheritance for named blueprints correctly" do
180
+ Dad.blueprint do
181
+ name { "John" }
182
+ end
183
+ Dad.blueprint(:special) do
184
+ name { "Paul" }
185
+ end
186
+ Son.blueprint { }
187
+ Son.blueprint(:special) { }
188
+ Son.make(:special).name.should == "John"
189
+ end
190
+ end
191
+
192
+ describe "clear_blueprints! method" do
193
+ it "should clear the list of blueprints" do
194
+ Person.blueprint(:foo){}
195
+ Person.clear_blueprints!
196
+ Person.named_blueprints.should == []
197
+ end
198
+
199
+ it "should clear master blueprint too" do
200
+ Person.blueprint(:foo) {}
201
+ Person.blueprint {} # master
202
+ Person.clear_blueprints!
203
+ lambda { Person.make }.should raise_error(RuntimeError)
204
+ end
205
+ end
206
+
207
+ end
208
+ end