machinist 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,194 @@
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) { title 'Dummy Post' }
64
+ Comment.blueprint { post(:dummy) }
65
+ Comment.make.post.title.should == 'Dummy Post'
66
+ end
67
+
68
+ it "should allow creating an object through a has_many association" do
69
+ Post.blueprint do
70
+ comments { [Comment.make] }
71
+ end
72
+ Comment.blueprint { }
73
+ Post.make.comments.should have(1).instance_of(Comment)
74
+ end
75
+
76
+ it "should allow setting a protected attribute in the blueprint" do
77
+ Person.blueprint do
78
+ password "Test"
79
+ end
80
+ Person.make.password.should == "Test"
81
+ end
82
+
83
+ it "should allow overriding a protected attribute" do
84
+ Person.blueprint do
85
+ password "Test"
86
+ end
87
+ Person.make(:password => "New").password.should == "New"
88
+ end
89
+
90
+ it "should allow setting the id attribute in a blueprint" do
91
+ Person.blueprint { id 12345 }
92
+ Person.make.id.should == 12345
93
+ end
94
+
95
+ it "should allow setting the type attribute in a blueprint" do
96
+ Person.blueprint { type "Person" }
97
+ Person.make.type.should == "Person"
98
+ end
99
+
100
+ describe "on a has_many association" do
101
+ before do
102
+ Post.blueprint { }
103
+ Comment.blueprint { post }
104
+ @post = Post.make
105
+ @comment = @post.comments.make
106
+ end
107
+
108
+ it "should save the created object" do
109
+ @comment.should_not be_new_record
110
+ end
111
+
112
+ it "should set the parent association on the created object" do
113
+ @comment.post.should == @post
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "plan method" do
119
+ it "should not save the constructed object" do
120
+ person_count = Person.count
121
+ Person.blueprint { }
122
+ person = Person.plan
123
+ Person.count.should == person_count
124
+ end
125
+
126
+ it "should create an object through a belongs_to association, and return its id" do
127
+ Post.blueprint { }
128
+ Comment.blueprint { post }
129
+ post_count = Post.count
130
+ comment = Comment.plan
131
+ Post.count.should == post_count + 1
132
+ comment[:post].should be_nil
133
+ comment[:post_id].should_not be_nil
134
+ end
135
+
136
+ describe "on a belongs_to association" do
137
+ it "should allow explicitly setting the association to nil" do
138
+ Comment.blueprint { post }
139
+ Comment.blueprint(:no_post) { post { nil } }
140
+ lambda {
141
+ @comment = Comment.plan(:no_post)
142
+ }.should_not raise_error
143
+ end
144
+ end
145
+
146
+ describe "on a has_many association" do
147
+ before do
148
+ Post.blueprint { }
149
+ Comment.blueprint do
150
+ post
151
+ body { "Test" }
152
+ end
153
+ @post = Post.make
154
+ @post_count = Post.count
155
+ @comment = @post.comments.plan
156
+ end
157
+
158
+ it "should not include the parent in the returned hash" do
159
+ @comment[:post].should be_nil
160
+ @comment[:post_id].should be_nil
161
+ end
162
+
163
+ it "should not create an extra parent object" do
164
+ Post.count.should == @post_count
165
+ end
166
+ end
167
+ end
168
+
169
+ describe "make_unsaved method" do
170
+ it "should not save the constructed object" do
171
+ Person.blueprint { }
172
+ person = Person.make_unsaved
173
+ person.should be_new_record
174
+ end
175
+
176
+ it "should not save associated objects" do
177
+ Post.blueprint { }
178
+ Comment.blueprint { post }
179
+ comment = Comment.make_unsaved
180
+ comment.post.should be_new_record
181
+ end
182
+
183
+ it "should save objects made within a passed-in block" do
184
+ Post.blueprint { }
185
+ Comment.blueprint { }
186
+ comment = nil
187
+ post = Post.make_unsaved { comment = Comment.make }
188
+ post.should be_new_record
189
+ comment.should_not be_new_record
190
+ end
191
+ end
192
+
193
+ end
194
+ end
@@ -0,0 +1,134 @@
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 { title "Test" }
93
+ post = Post.plan
94
+ post[:title].should == "Test"
95
+ end
96
+
97
+ it "should create an object through a belongs_to association, and return its id" do
98
+ Post.blueprint { }
99
+ Comment.blueprint { post }
100
+ post_count = Post.all.length
101
+ comment = Comment.plan
102
+ Post.all.length.should == post_count + 1
103
+ comment[:post].should be_nil
104
+ comment[:post_id].should_not be_nil
105
+ end
106
+ end
107
+
108
+ describe "make_unsaved method" do
109
+ it "should not save the constructed object" do
110
+ Person.blueprint { }
111
+ person = Person.make_unsaved
112
+ person.should be_new
113
+ end
114
+
115
+ it "should not save associated objects" do
116
+ Post.blueprint { }
117
+ Comment.blueprint { post }
118
+ comment = Comment.make_unsaved
119
+ comment.post.should be_new
120
+ end
121
+
122
+ it "should save objects made within a passed-in block" do
123
+ Post.blueprint { }
124
+ Comment.blueprint { }
125
+ comment = nil
126
+ post = Post.make_unsaved { comment = Comment.make }
127
+ post.should be_new
128
+ comment.should_not be_new
129
+ end
130
+ end
131
+
132
+ end
133
+ end
134
+
@@ -0,0 +1 @@
1
+ *.sqlite3
@@ -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,190 @@
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)
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 override an attribute from the blueprint with a passed-in attribute" do
64
+ Person.blueprint do
65
+ name "Fred"
66
+ end
67
+ Person.make(:name => "Bill").name.should == "Bill"
68
+ end
69
+
70
+ it "should allow overridden attribute names to be strings" do
71
+ Person.blueprint do
72
+ name "Fred"
73
+ end
74
+ Person.make("name" => "Bill").name.should == "Bill"
75
+ end
76
+
77
+ it "should not call a block in the blueprint if that attribute is passed in" do
78
+ block_called = false
79
+ Person.blueprint do
80
+ name { block_called = true; "Fred" }
81
+ end
82
+ Person.make(:name => "Bill").name.should == "Bill"
83
+ block_called.should be_false
84
+ end
85
+
86
+ it "should call a passed-in block with the object being constructed" do
87
+ Person.blueprint { }
88
+ block_called = false
89
+ Person.make do |person|
90
+ block_called = true
91
+ person.class.should == Person
92
+ end
93
+ block_called.should be_true
94
+ end
95
+
96
+ it "should provide access to the object being constructed from within the blueprint" do
97
+ person = nil
98
+ Person.blueprint { person = object }
99
+ Person.make
100
+ person.class.should == Person
101
+ end
102
+
103
+ it "should allow reading of a previously assigned attribute from within the blueprint" do
104
+ Post.blueprint do
105
+ title "Test"
106
+ body { title }
107
+ end
108
+ Post.make.body.should == "Test"
109
+ end
110
+
111
+ describe "named blueprints" do
112
+ before do
113
+ @block_called = false
114
+ Person.blueprint do
115
+ name { "Fred" }
116
+ admin { @block_called = true; false }
117
+ end
118
+ Person.blueprint(:admin) do
119
+ admin { true }
120
+ end
121
+ @person = Person.make(:admin)
122
+ end
123
+
124
+ it "should override an attribute from the parent blueprint in the child blueprint" do
125
+ @person.admin.should == true
126
+ end
127
+
128
+ it "should not call the block for an attribute from the parent blueprint if that attribute is overridden in the child" do
129
+ @block_called.should be_false
130
+ end
131
+
132
+ it "should set an attribute defined in the parent blueprint" do
133
+ @person.name.should == "Fred"
134
+ end
135
+
136
+ it "should return the correct list of named blueprints" do
137
+ Person.blueprint(:foo) { }
138
+ Person.blueprint(:bar) { }
139
+ Person.named_blueprints.to_set.should == [:admin, :foo, :bar].to_set
140
+ end
141
+ end
142
+
143
+ describe "blueprint inheritance" do
144
+ it "should inherit blueprinted attributes from the parent class" do
145
+ Dad.blueprint { name "Fred" }
146
+ Son.blueprint { }
147
+ Son.make.name.should == "Fred"
148
+ end
149
+
150
+ it "should override blueprinted attributes in the child class" do
151
+ Dad.blueprint { name "Fred" }
152
+ Son.blueprint { name "George" }
153
+ Dad.make.name.should == "Fred"
154
+ Son.make.name.should == "George"
155
+ end
156
+
157
+ it "should inherit from blueprinted attributes in ancestor class" do
158
+ Grandpa.blueprint { name "Fred" }
159
+ Son.blueprint { }
160
+ Grandpa.make.name.should == "Fred"
161
+ lambda { Dad.make }.should raise_error(RuntimeError)
162
+ Son.make.name.should == "Fred"
163
+ end
164
+
165
+ it "should follow inheritance for named blueprints correctly" do
166
+ Dad.blueprint { name "John" }
167
+ Dad.blueprint(:special) { name "Paul" }
168
+ Son.blueprint { }
169
+ Son.blueprint(:special) { }
170
+ Son.make(:special).name.should == "John"
171
+ end
172
+ end
173
+
174
+ describe "clear_blueprints! method" do
175
+ it "should clear the list of blueprints" do
176
+ Person.blueprint(:foo){}
177
+ Person.clear_blueprints!
178
+ Person.named_blueprints.should == []
179
+ end
180
+
181
+ it "should clear master blueprint too" do
182
+ Person.blueprint(:foo) {}
183
+ Person.blueprint {} # master
184
+ Person.clear_blueprints!
185
+ lambda { Person.make }.should raise_error(RuntimeError)
186
+ end
187
+ end
188
+
189
+ end
190
+ end