virtualbox 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +3 -3
  2. data/Gemfile +8 -8
  3. data/Rakefile +2 -0
  4. data/Readme.md +11 -2
  5. data/VERSION +1 -1
  6. data/docs/WhatsNew.md +40 -24
  7. data/lib/virtualbox.rb +9 -0
  8. data/lib/virtualbox/abstract_model.rb +80 -10
  9. data/lib/virtualbox/abstract_model/attributable.rb +61 -1
  10. data/lib/virtualbox/abstract_model/relatable.rb +88 -6
  11. data/lib/virtualbox/attached_device.rb +18 -10
  12. data/lib/virtualbox/command.rb +13 -0
  13. data/lib/virtualbox/dvd.rb +35 -0
  14. data/lib/virtualbox/exceptions.rb +1 -0
  15. data/lib/virtualbox/extra_data.rb +10 -21
  16. data/lib/virtualbox/global.rb +126 -0
  17. data/lib/virtualbox/hard_drive.rb +33 -9
  18. data/lib/virtualbox/image.rb +2 -3
  19. data/lib/virtualbox/media.rb +19 -0
  20. data/lib/virtualbox/nic.rb +28 -67
  21. data/lib/virtualbox/shared_folder.rb +7 -12
  22. data/lib/virtualbox/storage_controller.rb +8 -36
  23. data/lib/virtualbox/system_property.rb +55 -0
  24. data/lib/virtualbox/usb.rb +72 -0
  25. data/lib/virtualbox/vm.rb +126 -25
  26. data/test/test_helper.rb +118 -12
  27. data/test/virtualbox/abstract_model/attributable_test.rb +55 -5
  28. data/test/virtualbox/abstract_model/relatable_test.rb +66 -4
  29. data/test/virtualbox/abstract_model_test.rb +140 -8
  30. data/test/virtualbox/attached_device_test.rb +10 -7
  31. data/test/virtualbox/command_test.rb +13 -0
  32. data/test/virtualbox/dvd_test.rb +50 -28
  33. data/test/virtualbox/extra_data_test.rb +11 -51
  34. data/test/virtualbox/global_test.rb +78 -0
  35. data/test/virtualbox/hard_drive_test.rb +34 -57
  36. data/test/virtualbox/image_test.rb +0 -5
  37. data/test/virtualbox/nic_test.rb +11 -64
  38. data/test/virtualbox/shared_folder_test.rb +5 -5
  39. data/test/virtualbox/storage_controller_test.rb +15 -30
  40. data/test/virtualbox/system_property_test.rb +71 -0
  41. data/test/virtualbox/usb_test.rb +35 -0
  42. data/test/virtualbox/vm_test.rb +62 -121
  43. data/virtualbox.gemspec +15 -2
  44. metadata +23 -4
data/test/test_helper.rb CHANGED
@@ -1,16 +1,10 @@
1
1
  begin
2
- require File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'environment')
2
+ require File.expand_path('../.bundle/environment', __FILE__)
3
3
  rescue LoadError
4
- puts <<-ENVERR
5
- ==================================================
6
- ERROR: Gem environment file not found!
7
-
8
- This gem uses bundler to handle gem dependencies. To setup the
9
- test environment, please run `gem bundle test` If you don't
10
- have bundler, you can install that with `gem install bundler`
11
- ==================================================
12
- ENVERR
13
- exit
4
+ # Fallback on doing the resolve at runtime.
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup
14
8
  end
15
9
 
16
10
  # ruby-debug, not necessary, but useful if we have it
@@ -22,4 +16,116 @@ require 'contest'
22
16
  require 'mocha'
23
17
 
24
18
  # The actual library
25
- require File.join(File.dirname(__FILE__), '..', 'lib', 'virtualbox')
19
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'virtualbox')
20
+
21
+ # Data
22
+ class Test::Unit::TestCase
23
+ def mock_xml_doc
24
+ Nokogiri::XML(mock_xml)
25
+ end
26
+
27
+ def mock_xml
28
+ <<-xml
29
+ <?xml version="1.0"?>
30
+ <VirtualBox xmlns="http://www.innotek.de/VirtualBox-settings" version="1.9-macosx">
31
+ <Machine uuid="{8710d3db-d96a-46ed-9004-59fa891fda90}" name="foo" OSType="Ubuntu" currentSnapshot="{f1e6edb3-6e12-4615-9642-a80a3a1ad115}" lastStateChange="2010-02-07T20:01:20Z">
32
+ <Description>This is a description</Description>
33
+ <ExtraData>
34
+ <ExtraDataItem name="GUI/AutoresizeGuest" value="on"/>
35
+ <ExtraDataItem name="GUI/Fullscreen" value="off"/>
36
+ <ExtraDataItem name="GUI/LastWindowPostion" value="1040,171,720,422"/>
37
+ <ExtraDataItem name="GUI/MiniToolBarAlignment" value="bottom"/>
38
+ <ExtraDataItem name="GUI/MiniToolBarAutoHide" value="on"/>
39
+ <ExtraDataItem name="GUI/SaveMountedAtRuntime" value="yes"/>
40
+ <ExtraDataItem name="GUI/Seamless" value="off"/>
41
+ <ExtraDataItem name="GUI/ShowMiniToolBar" value="yes"/>
42
+ <ExtraDataItem name="VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" value="23"/>
43
+ <ExtraDataItem name="VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" value="2222"/>
44
+ <ExtraDataItem name="VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/Protocol" value="TCP"/>
45
+ </ExtraData>
46
+ <Hardware version="2">
47
+ <CPU count="1">
48
+ <HardwareVirtEx enabled="true" exclusive="false"/>
49
+ <HardwareVirtExNestedPaging enabled="false"/>
50
+ <HardwareVirtExVPID enabled="false"/>
51
+ <PAE enabled="true"/>
52
+ </CPU>
53
+ <Memory RAMSize="360"/>
54
+ <Boot>
55
+ <Order position="1" device="Floppy"/>
56
+ <Order position="2" device="DVD"/>
57
+ <Order position="3" device="HardDisk"/>
58
+ <Order position="4" device="None"/>
59
+ </Boot>
60
+ <Display VRAMSize="12" monitorCount="1" accelerate3D="false" accelerate2DVideo="false"/>
61
+ <RemoteDisplay enabled="false" port="3389" authType="Null" authTimeout="5000"/>
62
+ <BIOS>
63
+ <ACPI enabled="true"/>
64
+ <IOAPIC enabled="false"/>
65
+ <Logo fadeIn="true" fadeOut="true" displayTime="0"/>
66
+ <BootMenu mode="MessageAndMenu"/>
67
+ <TimeOffset value="0"/>
68
+ <PXEDebug enabled="false"/>
69
+ </BIOS>
70
+ <USBController enabled="true" enabledEhci="true">
71
+ <DeviceFilter name="Apple, Inc Apple Keyboard [0069]" active="true" vendorId="05ac" productId="0220" revision="0069" manufacturer="Apple, Inc" product="Apple Keyboard" remote="no"/>
72
+ <DeviceFilter name="Micron Built-in iSight [0189]" active="false" vendorId="05ac" productId="8501" revision="0189" manufacturer="Micron" product="Built-in iSight" remote="no"/>
73
+ </USBController>
74
+ <Network>
75
+ <Adapter slot="0" enabled="true" MACAddress="0800279C2E41" cable="true" speed="0" type="Am79C973">
76
+ <NAT/>
77
+ </Adapter>
78
+ <Adapter slot="1" enabled="false" MACAddress="0800277D1707" cable="true" speed="0" type="Am79C973"/>
79
+ <Adapter slot="2" enabled="false" MACAddress="080027FB5229" cable="true" speed="0" type="Am79C973"/>
80
+ <Adapter slot="3" enabled="false" MACAddress="080027DE7343" cable="true" speed="0" type="Am79C973"/>
81
+ <Adapter slot="4" enabled="false" MACAddress="0800277989CB" cable="true" speed="0" type="Am79C973"/>
82
+ <Adapter slot="5" enabled="false" MACAddress="08002768E43B" cable="true" speed="0" type="Am79C973"/>
83
+ <Adapter slot="6" enabled="false" MACAddress="080027903DF3" cable="true" speed="0" type="Am79C973"/>
84
+ <Adapter slot="7" enabled="false" MACAddress="0800276A0A7D" cable="true" speed="0" type="Am79C973"/>
85
+ </Network>
86
+ <UART>
87
+ <Port slot="0" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/>
88
+ <Port slot="1" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/>
89
+ </UART>
90
+ <LPT>
91
+ <Port slot="0" enabled="false" IOBase="0x378" IRQ="4"/>
92
+ <Port slot="1" enabled="false" IOBase="0x378" IRQ="4"/>
93
+ </LPT>
94
+ <AudioAdapter controller="AC97" driver="CoreAudio" enabled="false"/>
95
+ <SharedFolders>
96
+ <SharedFolder name="foo" hostPath="/foo" writable="true"/>
97
+ <SharedFolder name="bar" hostPath="/bar" writable="true"/>
98
+ </SharedFolders>
99
+ <Clipboard mode="Bidirectional"/>
100
+ <Guest memoryBalloonSize="0" statisticsUpdateInterval="0"/>
101
+ <GuestProperties>
102
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/Product" value="Linux" timestamp="1265440664974640000" flags=""/>
103
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/Release" value="2.6.24-26-virtual" timestamp="1265440664974987000" flags=""/>
104
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/Version" value="#1 SMP Tue Dec 1 20:00:30 UTC 2009" timestamp="1265440664975592000" flags=""/>
105
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/ServicePack" value="" timestamp="1265440664976342000" flags=""/>
106
+ <GuestProperty name="/VirtualBox/GuestAdd/Revision" value="3.1.2" timestamp="1265440664977228000" flags=""/>
107
+ <GuestProperty name="/VirtualBox/GuestAdd/Version" value="56127" timestamp="1265440664977917000" flags=""/>
108
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsers" value="1" timestamp="1265441395765168000" flags=""/>
109
+ <GuestProperty name="/VirtualBox/GuestInfo/Net/Count" value="1" timestamp="1265441395765770000" flags=""/>
110
+ <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/IP" value="10.0.2.15" timestamp="1265441395765987000" flags=""/>
111
+ <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Broadcast" value="10.0.2.255" timestamp="1265441395766412000" flags=""/>
112
+ <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Netmask" value="255.255.255.0" timestamp="1265441395766827000" flags=""/>
113
+ <GuestProperty name="/VirtualBox/GuestInfo/Net/0/Status" value="Up" timestamp="1265441395767109000" flags=""/>
114
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/NoLoggedInUsers" value="false" timestamp="1265440815142014000" flags=""/>
115
+ <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="en_US" timestamp="1265440628402728000" flags=""/>
116
+ <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsersList" value="hobo" timestamp="1265441395763755000" flags=""/>
117
+ </GuestProperties>
118
+ </Hardware>
119
+ <StorageControllers>
120
+ <StorageController name="foo" type="PIIX4" PortCount="2">
121
+ <AttachedDevice type="HardDisk" port="0" device="0">
122
+ <Image uuid="{2c16dd48-4cf1-497e-98fa-84ed55cfe71f}"/>
123
+ </AttachedDevice>
124
+ <AttachedDevice type="DVD" port="1" device="0"/>
125
+ </StorageController>
126
+ </StorageControllers>
127
+ </Machine>
128
+ </VirtualBox>
129
+ xml
130
+ end
131
+ end
@@ -11,11 +11,6 @@ class AttributableTest < Test::Unit::TestCase
11
11
 
12
12
  def initialize
13
13
  super
14
-
15
- populate_attributes({
16
- :foo => "foo",
17
- :bar => "bar"
18
- })
19
14
  end
20
15
  end
21
16
 
@@ -94,6 +89,46 @@ class AttributableTest < Test::Unit::TestCase
94
89
  assert_nil @model.bar
95
90
  end
96
91
  end
92
+
93
+ context "lazy loading" do
94
+ class LazyModel < EmptyAttributeModel
95
+ attribute :foo, :lazy => true
96
+ attribute :bar
97
+
98
+ def load_attribute(attribute)
99
+ write_attribute(attribute, "foo")
100
+ end
101
+ end
102
+
103
+ setup do
104
+ @model = LazyModel.new
105
+ end
106
+
107
+ should "return proper value for lazy_attribute?" do
108
+ assert @model.lazy_attribute?(:foo)
109
+ assert !@model.lazy_attribute?(:bar)
110
+ assert !@model.lazy_attribute?(:i_dont_exist)
111
+ end
112
+
113
+ should "load the lazy attribute on read" do
114
+ assert !@model.loaded_attribute?(:foo)
115
+ assert_equal "foo", @model.foo
116
+ assert @model.loaded_attribute?(:foo)
117
+ end
118
+
119
+ should "not be loaded initially, then should be loaded after being read" do
120
+ assert !@model.loaded_attribute?(:foo)
121
+ @model.foo
122
+ assert @model.loaded_attribute?(:foo)
123
+ end
124
+
125
+ should "mark as loaded if write_attribute is called on an attribute" do
126
+ assert !@model.loaded_attribute?(:foo)
127
+ @model.write_attribute(:foo, "bar")
128
+ assert @model.loaded_attribute?(:foo)
129
+ assert_equal "bar", @model.foo
130
+ end
131
+ end
97
132
  end
98
133
 
99
134
  context "populating attributes" do
@@ -112,11 +147,26 @@ class AttributableTest < Test::Unit::TestCase
112
147
  assert_equal v, @model.send(k)
113
148
  end
114
149
  end
150
+
151
+ should "not load nonexistent keys" do
152
+ new_attributes = {
153
+ :foo => "zxcv"
154
+ }
155
+
156
+ @model.populate_attributes(new_attributes)
157
+ assert @model.loaded_attribute?(:foo)
158
+ assert !@model.loaded_attribute?(:bar)
159
+ end
115
160
  end
116
161
 
117
162
  context "reading and writing attributes" do
118
163
  setup do
119
164
  @model = AttributeModel.new
165
+ @model.populate_attributes({
166
+ :foo => "foo",
167
+ :bar => "bar"
168
+ })
169
+
120
170
  @checkstring = "HEY"
121
171
  end
122
172
 
@@ -11,9 +11,11 @@ class RelatableTest < Test::Unit::TestCase
11
11
  end
12
12
  end
13
13
 
14
- class RelatableModel
14
+ class EmptyRelatableModel
15
15
  include VirtualBox::AbstractModel::Relatable
16
+ end
16
17
 
18
+ class RelatableModel < EmptyRelatableModel
17
19
  relationship :foos, Relatee
18
20
  relationship :bars, BarRelatee
19
21
  end
@@ -128,6 +130,12 @@ class RelatableTest < Test::Unit::TestCase
128
130
  Relatee.expects(:destroy_relationship).with(@model, "FOO").once
129
131
  @model.destroy_relationship(:foos)
130
132
  end
133
+
134
+ should "call read_relationship (to force the load if lazy)" do
135
+ Relatee.expects(:destroy_relationship).with(@model, "FOO").once
136
+ @model.expects(:read_relationship).with(:foos).once
137
+ @model.destroy_relationship(:foos)
138
+ end
131
139
  end
132
140
 
133
141
  context "all relationships" do
@@ -143,19 +151,66 @@ class RelatableTest < Test::Unit::TestCase
143
151
  end
144
152
  end
145
153
 
154
+ context "lazy relationships" do
155
+ class LazyRelatableModel < EmptyRelatableModel
156
+ relationship :foos, RelatableTest::Relatee, :lazy => true
157
+ relationship :bars, RelatableTest::BarRelatee
158
+ end
159
+
160
+ setup do
161
+ @model = LazyRelatableModel.new
162
+ end
163
+
164
+ should "return true if a relationship is lazy, and false if not, when checking" do
165
+ assert @model.lazy_relationship?(:foos)
166
+ assert !@model.lazy_relationship?(:bars)
167
+ end
168
+
169
+ should "not be loaded by default" do
170
+ assert !@model.loaded_relationship?(:foos)
171
+ end
172
+
173
+ should "call `load_relationship` on initial load" do
174
+ @model.expects(:load_relationship).with(:foos).once
175
+ @model.foos
176
+ end
177
+
178
+ should "not call `load_relationship` for non lazy attributes" do
179
+ @model.expects(:load_relationship).never
180
+ @model.bars
181
+ end
182
+
183
+ should "mark a relationship as loaded on populate_relationship" do
184
+ @model.populate_relationship(:foos, {})
185
+ assert @model.loaded_relationship?(:foos)
186
+ end
187
+
188
+ should "not populate the lazy relationship right away" do
189
+ Relatee.expects(:populate_relationship).never
190
+ BarRelatee.expects(:populate_relationship).once
191
+ @model.populate_relationships({})
192
+ end
193
+ end
194
+
146
195
  context "saving relationships" do
147
196
  setup do
148
197
  @model = RelatableModel.new
149
198
  end
150
199
 
200
+ should "call save_relationship for all relationships" do
201
+ @model.expects(:save_relationship).with(:foos)
202
+ @model.expects(:save_relationship).with(:bars)
203
+ @model.save_relationships
204
+ end
205
+
151
206
  should "call save_relationship on the related class" do
152
207
  Relatee.expects(:save_relationship).with(@model, @model.foos).once
153
- @model.save_relationships
208
+ @model.save_relationship(:foos)
154
209
  end
155
210
 
156
211
  should "forward parameters through" do
157
212
  Relatee.expects(:save_relationship).with(@model, @model.foos, "YES").once
158
- @model.save_relationships("YES")
213
+ @model.save_relationship(:foos, "YES")
159
214
  end
160
215
  end
161
216
 
@@ -193,8 +248,15 @@ class RelatableTest < Test::Unit::TestCase
193
248
  @model = RelatableModel.new
194
249
  end
195
250
 
196
- should "call populate_relationship on the related class" do
251
+ should "be able to populate a single relationship" do
197
252
  Relatee.expects(:populate_relationship).with(@model, @data).once
253
+ @model.populate_relationship(:foos, @data)
254
+ end
255
+
256
+ should "call populate_relationship on the related class" do
257
+ populate_seq = sequence("populate_seq")
258
+ @model.expects(:populate_relationship).with(:foos, @data).once.in_sequence(populate_seq)
259
+ @model.expects(:populate_relationship).with(:bars, @data).once.in_sequence(populate_seq)
198
260
  @model.populate_relationships(@data)
199
261
  end
200
262
 
@@ -19,6 +19,83 @@ class AbstractModelTest < Test::Unit::TestCase
19
19
  relationship :bars, Bar, :dependent => :destroy
20
20
  end
21
21
 
22
+ context "reloading" do
23
+ context "with a single class" do
24
+ setup do
25
+ @model = FakeModel.new
26
+ end
27
+
28
+ teardown do
29
+ FakeModel.reloaded!
30
+ end
31
+
32
+ should "not want to be reloaded initially" do
33
+ assert !FakeModel.reload?
34
+ end
35
+
36
+ should "want to be reloaded once signaled by the class method" do
37
+ FakeModel.reload!
38
+ assert FakeModel.reload?
39
+ end
40
+
41
+ should "want to be reloaded once signaled by the instance method" do
42
+ @model.reload!
43
+ assert FakeModel.reload?
44
+ end
45
+
46
+ should "not want to be reloaded once reloaded! is called" do
47
+ @model.reload!
48
+ assert FakeModel.reload?
49
+ FakeModel.reloaded!
50
+ assert !FakeModel.reload?
51
+ end
52
+ end
53
+
54
+ context "with inheritance" do
55
+ class SubModel < FakeModel
56
+ end
57
+
58
+ setup do
59
+ @lazy = FakeModel.new
60
+ @sub = SubModel.new
61
+ end
62
+
63
+ should "not interfere with each others reload flags" do
64
+ @lazy.reload!
65
+ assert !SubModel.reload?
66
+ assert FakeModel.reload?
67
+ end
68
+ end
69
+ end
70
+
71
+ context "lazy attributes and relationships" do
72
+ class LazyModel < VirtualBox::AbstractModel
73
+ attribute :foo, :lazy => true
74
+ attribute :bar
75
+ relationship :foos, AbstractModelTest::Foo, :lazy => true
76
+ relationship :bars, AbstractModelTest::Bar, :lazy => true
77
+ end
78
+
79
+ setup do
80
+ @model = LazyModel.new
81
+ end
82
+
83
+ should "return false on lazy_attribute? for all attributes if new" do
84
+ assert !@model.lazy_attribute?(:foo)
85
+ assert !@model.lazy_relationship?(:foos)
86
+ end
87
+
88
+ should "only save loaded relationships" do
89
+ @model.existing_record!
90
+ assert @model.lazy_relationship?(:foos)
91
+ assert @model.lazy_relationship?(:bars)
92
+ @model.stubs(:loaded_relationship?).with(:foos).returns(false)
93
+ @model.stubs(:loaded_relationship?).with(:bars).returns(true)
94
+ @model.expects(:save_relationship).with(:bars).once
95
+ @model.save
96
+ end
97
+ end
98
+
22
99
  context "inspecting" do
23
100
  setup do
24
101
  @model = FakeModel.new
@@ -27,6 +104,11 @@ class AbstractModelTest < Test::Unit::TestCase
27
104
  should "generate the proper inspect string" do
28
105
  assert_equal "#<AbstractModelTest::FakeModel :bar=nil, :bars=..., :foo=nil, :foos=...>", @model.inspect
29
106
  end
107
+
108
+ should "turn attributes which are AbstractModels into classes" do
109
+ @model.foo = @model.dup
110
+ assert_equal "#<AbstractModelTest::FakeModel :bar=nil, :bars=..., :foo=#<AbstractModelTest::FakeModel>, :foos=...>", @model.inspect
111
+ end
30
112
  end
31
113
 
32
114
  context "validation" do
@@ -166,11 +248,6 @@ class AbstractModelTest < Test::Unit::TestCase
166
248
  @model.save
167
249
  end
168
250
 
169
- should "call save_relationships" do
170
- @model.expects(:save_relationships).once
171
- @model.save
172
- end
173
-
174
251
  should "clear dirty state once saved" do
175
252
  @model.foo = "foo2"
176
253
  assert @model.foo_changed?
@@ -192,9 +269,57 @@ class AbstractModelTest < Test::Unit::TestCase
192
269
  @model = FakeModel.new
193
270
  end
194
271
 
195
- should "populate relationships at the same time as attributes" do
196
- Foo.expects(:populate_relationship).once
197
- @model.populate_attributes({})
272
+ context "populating attributes" do
273
+ should "populate relationships at the same time as attributes" do
274
+ Foo.expects(:populate_relationship).once
275
+ @model.populate_attributes({})
276
+ end
277
+
278
+ should "not populate relationships if :ignore_relationships is true" do
279
+ Foo.expects(:populate_relationship).never
280
+ @model.populate_attributes({}, :ignore_relationships => true)
281
+ end
282
+
283
+ should "cause the model to become an existing record" do
284
+ assert @model.new_record?
285
+ @model.populate_attributes({})
286
+ assert !@model.new_record?
287
+ end
288
+
289
+ should "not cause dirtiness" do
290
+ assert_nil @model.foo
291
+ @model.populate_attributes({ :foo => "foo" })
292
+ assert_equal "foo", @model.foo
293
+ assert !@model.changed?
294
+ end
295
+ end
296
+
297
+ context "populating relationships" do
298
+ should "cause the model to become an existing record" do
299
+ assert @model.new_record?
300
+ @model.populate_relationships({})
301
+ assert !@model.new_record?
302
+ end
303
+
304
+ should "not cause dirtiness" do
305
+ # TODO: This test doesn't do much right now. We need to actually compare
306
+ # the relationship values for dirtiness.
307
+ @model.populate_relationships({ :foo => "foo" })
308
+ assert !@model.changed?
309
+ end
310
+ end
311
+
312
+ context "populating a single relationship" do
313
+ should "cause the model to become an existing record" do
314
+ assert @model.new_record?
315
+ @model.populate_relationship(:foos, {})
316
+ assert !@model.new_record?
317
+ end
318
+
319
+ should "not cause dirtiness" do
320
+ @model.populate_relationship(:foos, {})
321
+ assert !@model.changed?
322
+ end
198
323
  end
199
324
  end
200
325
 
@@ -232,5 +357,12 @@ class AbstractModelTest < Test::Unit::TestCase
232
357
  assert @model.foo_changed?
233
358
  assert_equal "foo2", @model.foo
234
359
  end
360
+
361
+ should "not mark dirtiness on write_attribute if the attribute is lazy and not yet loaded" do
362
+ @model.expects(:lazy_attribute?).with(:foo).returns(true)
363
+ @model.expects(:loaded_attribute?).with(:foo).returns(false)
364
+ @model.expects(:set_dirty!).never
365
+ @model.write_attribute(:foo, "foo2")
366
+ end
235
367
  end
236
368
  end