virtualbox 0.4.3 → 0.5.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.
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