/test/virtualbox/abstract_model/relatable_test.rb

https://github.com/botsie/virtualbox · Ruby · 369 lines · 311 code · 58 blank · 0 comment · 19 complexity · 30a0d27a8be9b528f554d401e4eb8f5c MD5 · raw file

  1. require File.expand_path("../../../test_helper", __FILE__)
  2. class RelatableTest < Test::Unit::TestCase
  3. class Relatee
  4. def self.populate_relationship(caller, data)
  5. "FOO"
  6. end
  7. end
  8. class BarRelatee
  9. def self.set_relationship(caller, old_value, new_value)
  10. end
  11. end
  12. class EmptyRelatableModel
  13. include VirtualBox::AbstractModel::Relatable
  14. end
  15. class RelatableModel < EmptyRelatableModel
  16. relationship :foos, RelatableTest::Relatee
  17. relationship :bars, RelatableTest::BarRelatee
  18. end
  19. setup do
  20. @data = {}
  21. end
  22. context "class methods" do
  23. should "read back relationships in order added" do
  24. order = mock("order")
  25. order_seq = sequence("order_seq")
  26. order.expects(:foos).in_sequence(order_seq)
  27. order.expects(:bars).in_sequence(order_seq)
  28. RelatableModel.relationships.each do |name, options|
  29. order.send(name)
  30. end
  31. end
  32. end
  33. context "setting a relationship" do
  34. setup do
  35. @model = RelatableModel.new
  36. end
  37. should "have a magic method relationship= which calls set_relationship" do
  38. @model.expects(:set_relationship).with(:foos, "FOOS!")
  39. @model.foos = "FOOS!"
  40. end
  41. should "raise a NonSettableRelationshipException if relationship can't be set" do
  42. assert_raises(VirtualBox::Exceptions::NonSettableRelationshipException) {
  43. @model.foos = "FOOS!"
  44. }
  45. end
  46. should "call set_relationship on the relationship class" do
  47. BarRelatee.expects(:populate_relationship).returns("foo")
  48. @model.populate_relationships({})
  49. BarRelatee.expects(:set_relationship).with(@model, "foo", "bars")
  50. assert_nothing_raised { @model.bars = "bars" }
  51. end
  52. should "set the result of set_relationship as the new relationship data" do
  53. BarRelatee.stubs(:set_relationship).returns("hello")
  54. @model.bars = "zoo"
  55. assert_equal "hello", @model.bars
  56. end
  57. end
  58. context "subclasses" do
  59. class SubRelatableModel < RelatableModel
  60. relationship :bars, RelatableTest::Relatee
  61. end
  62. setup do
  63. @relationships = SubRelatableModel.relationships
  64. end
  65. should "inherit relationships of parent" do
  66. assert SubRelatableModel.has_relationship?(:foos)
  67. assert SubRelatableModel.has_relationship?(:bars)
  68. end
  69. should "inherit options of relationships" do
  70. assert_equal Relatee, SubRelatableModel.relationships_hash[:foos][:klass]
  71. end
  72. end
  73. context "default callbacks" do
  74. setup do
  75. @model = RelatableModel.new
  76. end
  77. should "not raise an error if populate_relationship doesn't exist" do
  78. assert !BarRelatee.respond_to?(:populate_relationship)
  79. assert_nothing_raised { @model.populate_relationships(nil) }
  80. end
  81. should "not raise an error when saving relationships if the callback doesn't exist" do
  82. assert !Relatee.respond_to?(:save_relationship)
  83. assert_nothing_raised { @model.save_relationships }
  84. end
  85. should "not raise an error in destroying relationships if the callback doesn't exist" do
  86. assert !Relatee.respond_to?(:destroy_relationship)
  87. assert_nothing_raised { @model.destroy_relationships }
  88. end
  89. end
  90. context "destroying" do
  91. setup do
  92. @model = RelatableModel.new
  93. @model.populate_relationships({})
  94. end
  95. context "a single relationship" do
  96. should "call destroy_relationship only for the given relationship" do
  97. Relatee.expects(:destroy_relationship).once
  98. BarRelatee.expects(:destroy_relationship).never
  99. @model.destroy_relationship(:foos)
  100. end
  101. should "forward any args passed into destroy_relationship" do
  102. Relatee.expects(:destroy_relationship).with(@model, anything, "HELLO").once
  103. @model.destroy_relationship(:foos, "HELLO")
  104. end
  105. should "pass the data into destroy_relationship" do
  106. Relatee.expects(:destroy_relationship).with(@model, "FOO").once
  107. @model.destroy_relationship(:foos)
  108. end
  109. should "call read_relationship (to force the load if lazy)" do
  110. Relatee.expects(:destroy_relationship).with(@model, "FOO").once
  111. @model.expects(:read_relationship).with(:foos).once
  112. @model.destroy_relationship(:foos)
  113. end
  114. end
  115. context "all relationships" do
  116. should "call destroy_relationship on the related class" do
  117. Relatee.expects(:destroy_relationship).with(@model, anything).once
  118. @model.destroy_relationships
  119. end
  120. should "forward any args passed into destroy relationships" do
  121. Relatee.expects(:destroy_relationship).with(@model, anything, "HELLO").once
  122. @model.destroy_relationships("HELLO")
  123. end
  124. end
  125. end
  126. context "resetting relationships" do
  127. class ResetRelatableModel < EmptyRelatableModel
  128. relationship :foos, RelatableTest::Relatee
  129. relationship :bars, RelatableTest::BarRelatee, :lazy => true
  130. end
  131. setup do
  132. @model = ResetRelatableModel.new
  133. end
  134. should "reset only the lazy relationship" do
  135. @model.relationship_data[:foos] = "YES"
  136. @model.relationship_data[:bars] = "YES"
  137. assert @model.loaded_relationship?(:bars)
  138. @model.reset_relationships
  139. assert !@model.loaded_relationship?(:bars)
  140. assert_equal "YES", @model.foos
  141. end
  142. end
  143. context "lazy relationships" do
  144. class LazyRelatableModel < EmptyRelatableModel
  145. relationship :foos, RelatableTest::Relatee, :lazy => true
  146. relationship :bars, RelatableTest::BarRelatee
  147. end
  148. setup do
  149. @model = LazyRelatableModel.new
  150. end
  151. should "return true if a relationship is lazy, and false if not, when checking" do
  152. assert @model.lazy_relationship?(:foos)
  153. assert !@model.lazy_relationship?(:bars)
  154. end
  155. should "not be loaded by default" do
  156. assert !@model.loaded_relationship?(:foos)
  157. end
  158. should "call `load_relationship` on initial load" do
  159. @model.expects(:load_relationship).with(:foos).once
  160. @model.foos
  161. end
  162. should "not call `load_relationship` for non lazy attributes" do
  163. @model.expects(:load_relationship).never
  164. @model.bars
  165. end
  166. should "mark a relationship as loaded on populate_relationship" do
  167. @model.populate_relationship(:foos, {})
  168. assert @model.loaded_relationship?(:foos)
  169. end
  170. should "not populate the lazy relationship right away" do
  171. Relatee.expects(:populate_relationship).never
  172. BarRelatee.expects(:populate_relationship).once
  173. @model.populate_relationships({})
  174. end
  175. end
  176. context "saving relationships" do
  177. class RelatableWithLazyModel < RelatableModel
  178. relationship :bazs, RelatableTest::Relatee, :lazy => true
  179. relationship :vers, RelatableTest::Relatee, :version => "3.1"
  180. def load_relationship(name)
  181. populate_relationship(:bazs, "foo")
  182. end
  183. end
  184. setup do
  185. @model = RelatableWithLazyModel.new
  186. VirtualBox.stubs(:version).returns("3.1.3")
  187. end
  188. should "call save_relationship for all relationships" do
  189. @model.expects(:save_relationship).with(:foos).returns(true)
  190. @model.expects(:save_relationship).with(:bars).returns(true)
  191. @model.expects(:save_relationship).with(:bazs).returns(true)
  192. @model.expects(:save_relationship).with(:vers).returns(true)
  193. assert @model.save_relationships
  194. end
  195. should "not call save_relationship on non-loaded relations" do
  196. Relatee.expects(:save_relationship).never
  197. @model.save_relationship(:bazs)
  198. end
  199. should "not call save_relationship on relationships with mismatched versions" do
  200. VirtualBox.stubs(:version).returns("3.2.4")
  201. Relatee.expects(:save_relationship).never
  202. @model.save_relationship(:vers)
  203. end
  204. should "call save_relationship on loaded lazy relationships" do
  205. @model.load_relationship(:bazs)
  206. Relatee.expects(:save_relationship).once
  207. @model.save_relationship(:bazs)
  208. end
  209. should "call save_relationship on the related class" do
  210. Relatee.expects(:save_relationship).with(@model, @model.foos).once.returns(:r)
  211. assert_equal :r, @model.save_relationship(:foos)
  212. end
  213. should "forward parameters through" do
  214. Relatee.expects(:save_relationship).with(@model, @model.foos, "YES").once
  215. @model.save_relationship(:foos, "YES")
  216. end
  217. end
  218. context "reading relationships" do
  219. class VersionedRelatableModel < RelatableModel
  220. relationship :ver, :Ver, :version => "3.1"
  221. end
  222. setup do
  223. @model = VersionedRelatableModel.new
  224. end
  225. should "provide a read method for relationships" do
  226. assert_nothing_raised { @model.foos }
  227. end
  228. should "raise an exception if invalid version for versioned relationships" do
  229. VirtualBox.stubs(:version).returns("3.0.14")
  230. assert_raises(VirtualBox::Exceptions::UnsupportedVersionException) {
  231. @model.ver
  232. }
  233. end
  234. should "not raise an exception if valid version for versioned relationship" do
  235. VirtualBox.stubs(:version).returns("3.1.8")
  236. assert_nothing_raised {
  237. @model.ver
  238. }
  239. end
  240. end
  241. context "checking for relationships" do
  242. setup do
  243. @model = RelatableModel.new
  244. end
  245. should "have a class method as well" do
  246. assert RelatableModel.has_relationship?(:foos)
  247. assert !RelatableModel.has_relationship?(:bazs)
  248. end
  249. should "return true for existing relationships" do
  250. assert @model.has_relationship?(:foos)
  251. end
  252. should "return false for nonexistent relationships" do
  253. assert !@model.has_relationship?(:bazs)
  254. end
  255. end
  256. context "determining the class of relationships" do
  257. class ClassRelatableModel < EmptyRelatableModel
  258. relationship :foo, RelatableTest::Relatee
  259. relationship :bar, "RelatableTest::BarRelatee"
  260. end
  261. setup do
  262. @model = ClassRelatableModel.new
  263. end
  264. should "just return the class for Class types" do
  265. assert_equal Relatee, @model.relationship_class(:foo)
  266. end
  267. should "turn string into class" do
  268. assert_equal BarRelatee, @model.relationship_class(:bar)
  269. end
  270. end
  271. context "populating relationships" do
  272. class PopulatingRelatableModel < RelatableModel
  273. relationship :bazs, RelatableTest::Relatee, :version => "3.1"
  274. end
  275. setup do
  276. @model = PopulatingRelatableModel.new
  277. VirtualBox.stubs(:version).returns("3.1.4")
  278. end
  279. should "be able to populate a single relationship" do
  280. Relatee.expects(:populate_relationship).with(@model, @data).once
  281. @model.populate_relationship(:foos, @data)
  282. end
  283. should "not populate versioned relationships if version mismatch" do
  284. VirtualBox.stubs(:version).returns("3.0.4")
  285. Relatee.expects(:populate_relationship).never
  286. @model.populate_relationship(:bazs, @data)
  287. end
  288. should "call populate_relationship on the related class" do
  289. populate_seq = sequence("populate_seq")
  290. @model.expects(:populate_relationship).with(:foos, @data).once.in_sequence(populate_seq)
  291. @model.expects(:populate_relationship).with(:bars, @data).once.in_sequence(populate_seq)
  292. @model.expects(:populate_relationship).with(:bazs, @data).once.in_sequence(populate_seq)
  293. @model.populate_relationships(@data)
  294. end
  295. should "properly save returned value as the value for the relationship" do
  296. Relatee.expects(:populate_relationship).twice.returns("HEY")
  297. @model.populate_relationships(@data)
  298. assert_equal "HEY", @model.foos
  299. end
  300. end
  301. end