test_section.py 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. import unittest
  2. from odml import Property, Section, Document
  3. from odml.doc import BaseDocument
  4. from odml.section import BaseSection
  5. class TestSection(unittest.TestCase):
  6. def setUp(self):
  7. pass
  8. def test_simple_attributes(self):
  9. sec_name = "sec name"
  10. sec_type = "sec type"
  11. sec_def = "an odml test section"
  12. sec_ref = "from over there"
  13. sec = Section(name=sec_name, type=sec_type, definition=sec_def, reference=sec_ref)
  14. self.assertEqual(sec.name, sec_name)
  15. self.assertEqual(sec.type, sec_type)
  16. self.assertEqual(sec.definition, sec_def)
  17. self.assertEqual(sec.reference, sec_ref)
  18. # Test setting attributes
  19. sec.name = "%s_edit" % sec_name
  20. self.assertEqual(sec.name, "%s_edit" % sec_name)
  21. sec.type = "%s_edit" % sec_type
  22. self.assertEqual(sec.type, "%s_edit" % sec_type)
  23. sec.definition = "%s_edit" % sec_def
  24. self.assertEqual(sec.definition, "%s_edit" % sec_def)
  25. sec.reference = "%s_edit" % sec_ref
  26. self.assertEqual(sec.reference, "%s_edit" % sec_ref)
  27. # Test setting attributes to None when '' is passed.
  28. sec.reference = ""
  29. self.assertIsNone(sec.reference)
  30. sec.definition = ""
  31. self.assertIsNone(sec.definition)
  32. def test_name(self):
  33. # Test id is used when name is not provided
  34. sec = Section()
  35. self.assertIsNotNone(sec.name)
  36. self.assertEqual(sec.name, sec.id)
  37. # Test name is properly set on init
  38. name = "rumpelstilzchen"
  39. sec = Section(name)
  40. self.assertEqual(sec.name, name)
  41. name = "rumpelstilzchen"
  42. sec = Section(name=name)
  43. self.assertEqual(sec.name, name)
  44. # Test name can be properly set on single and connected Sections
  45. sec = Section()
  46. self.assertNotEqual(sec.name, "sec")
  47. sec.name = "sec"
  48. self.assertEqual(sec.name, "sec")
  49. subsec_a = Section(parent=sec)
  50. self.assertNotEqual(subsec_a.name, "subsec_a")
  51. subsec_a.name = "subsec_a"
  52. self.assertEqual(subsec_a.name, "subsec_a")
  53. # Test subsection name can be changed with siblings
  54. subsec_b = Section(name="subsec_b", parent=sec)
  55. self.assertEqual(subsec_b.name, "subsec_b")
  56. subsec_b.name = "subsec"
  57. self.assertEqual(subsec_b.name, "subsec")
  58. # Test subsection name set will fail on existing sibling with same name
  59. with self.assertRaises(KeyError):
  60. subsec_b.name = "subsec_a"
  61. self.assertEqual(subsec_b.name, "subsec")
  62. # Test section name set will fail on existing same name document sibling
  63. doc = Document()
  64. _ = Section(name="a", parent=doc)
  65. sec_b = Section(name="b", parent=doc)
  66. with self.assertRaises(KeyError):
  67. sec_b.name = "a"
  68. def test_parent(self):
  69. sec = Section("Section")
  70. self.assertIsNone(sec.parent)
  71. sec.parent = None
  72. self.assertIsNone(sec.parent)
  73. sec.parent = Document()
  74. self.assertIsInstance(sec.parent, BaseDocument)
  75. self.assertIsInstance(sec.parent._sections[0], BaseSection)
  76. # Test if child is removed from _sections of a parent after
  77. # assigning a new parent to the child.
  78. sec_parent = sec.parent
  79. sec.parent = Section("S")
  80. self.assertEqual(len(sec_parent._sections), 0)
  81. sec = Section("section_doc", parent=Document())
  82. self.assertIsInstance(sec.parent, BaseDocument)
  83. self.assertEqual(len(sec.parent._sections), 1)
  84. sec_parent = sec.parent
  85. sec.parent = None
  86. self.assertEqual(len(sec_parent._sections), 0)
  87. self.assertEqual(sec.parent, None)
  88. sec = Section("section_sec", parent=Section("S"))
  89. self.assertIsInstance(sec.parent, BaseSection)
  90. self.assertEqual(len(sec.parent._sections), 1)
  91. sec_parent = sec.parent
  92. sec.parent = None
  93. self.assertEqual(len(sec_parent._sections), 0)
  94. self.assertEqual(sec.parent, None)
  95. with self.assertRaises(ValueError):
  96. Section("section_property", parent=Property("P"))
  97. def test_path(self):
  98. sec = Section(name="center")
  99. self.assertEqual(sec.get_path(), "/")
  100. subsec = Section(name="leaf", parent=sec)
  101. self.assertEqual(subsec.get_path(), "/leaf")
  102. doc = Document()
  103. sec.parent = doc
  104. self.assertEqual(sec.get_path(), "/center")
  105. self.assertEqual(subsec.get_path(), "/center/leaf")
  106. top = Section(name="top", parent=doc)
  107. sec.parent = top
  108. self.assertEqual(sec.get_path(), "/top/center")
  109. self.assertEqual(subsec.get_path(), "/top/center/leaf")
  110. subsec.parent = None
  111. self.assertEqual(subsec.get_path(), "/")
  112. def test_children(self):
  113. sec = Section(name="sec")
  114. # Test set sections
  115. subsec = Section(name="subsec", parent=sec)
  116. newsec = Section(name="newsec")
  117. self.assertEqual(subsec.parent, sec)
  118. self.assertEqual(sec.sections[0], subsec)
  119. self.assertEqual(len(sec.sections), 1)
  120. self.assertIsNone(newsec.parent)
  121. sec.sections[0] = newsec
  122. self.assertEqual(newsec.parent, sec)
  123. self.assertEqual(sec.sections[0], newsec)
  124. self.assertEqual(len(sec.sections), 1)
  125. self.assertIsNone(subsec.parent)
  126. # Test parent cleanup
  127. root = Section(name="root")
  128. sec.parent = root
  129. subsec.parent = newsec
  130. self.assertEqual(len(newsec.sections), 1)
  131. self.assertEqual(newsec.sections[0], subsec)
  132. self.assertEqual(subsec.parent, newsec)
  133. self.assertEqual(len(root.sections), 1)
  134. self.assertEqual(root.sections[0], sec)
  135. subsec.parent = root
  136. self.assertEqual(len(newsec.sections), 0)
  137. self.assertEqual(subsec.parent, root)
  138. self.assertEqual(len(root.sections), 2)
  139. self.assertEqual(root.sections[1], subsec)
  140. # Test set section fails
  141. with self.assertRaises(ValueError):
  142. sec.sections[0] = Document()
  143. with self.assertRaises(ValueError):
  144. sec.sections[0] = Property("fail")
  145. with self.assertRaises(ValueError):
  146. sec.sections[0] = "subsec"
  147. # Test set properties
  148. prop = Property(name="prop", parent=sec)
  149. newprop = Property(name="newprop")
  150. self.assertEqual(prop.parent, sec)
  151. self.assertEqual(sec.properties[0], prop)
  152. self.assertEqual(len(sec.properties), 1)
  153. self.assertIsNone(newprop.parent)
  154. sec.properties[0] = newprop
  155. self.assertEqual(newprop.parent, sec)
  156. self.assertEqual(sec.properties[0], newprop)
  157. self.assertEqual(len(sec.properties), 1)
  158. self.assertIsNone(prop.parent)
  159. # Test set property fails
  160. with self.assertRaises(ValueError):
  161. sec.properties[0] = Document()
  162. with self.assertRaises(ValueError):
  163. sec.properties[0] = newsec
  164. with self.assertRaises(ValueError):
  165. sec.properties[0] = "prop"
  166. # same tests with props alias
  167. prop = Property(name="prop2", parent=sec)
  168. newprop = Property(name="newprop2")
  169. self.assertEqual(prop.parent, sec)
  170. self.assertEqual(sec.props[1], prop)
  171. self.assertEqual(len(sec.props), 2)
  172. self.assertIsNone(newprop.parent)
  173. sec.props[1] = newprop
  174. self.assertEqual(newprop.parent, sec)
  175. self.assertEqual(sec.props[1], newprop)
  176. self.assertEqual(len(sec.props), 2)
  177. self.assertIsNone(prop.parent)
  178. # Test set property fails
  179. with self.assertRaises(ValueError):
  180. sec.props[1] = Document()
  181. with self.assertRaises(ValueError):
  182. sec.props[1] = newsec
  183. with self.assertRaises(ValueError):
  184. sec.props[1] = "prop2"
  185. def test_id(self):
  186. sec = Section(name="S")
  187. self.assertIsNotNone(sec.id)
  188. sec = Section("S", oid="79b613eb-a256-46bf-84f6-207df465b8f7")
  189. self.assertEqual(sec.id, "79b613eb-a256-46bf-84f6-207df465b8f7")
  190. sec = Section("S", oid="id")
  191. self.assertNotEqual(sec.id, "id")
  192. # Make sure id cannot be reset programmatically.
  193. with self.assertRaises(AttributeError):
  194. sec.id = "someId"
  195. def test_new_id(self):
  196. sec = Section(name="sec")
  197. old_id = sec.id
  198. # Test assign new generated id.
  199. sec.new_id()
  200. self.assertNotEqual(old_id, sec.id)
  201. # Test assign new custom id.
  202. old_id = sec.id
  203. sec.new_id("79b613eb-a256-46bf-84f6-207df465b8f7")
  204. self.assertNotEqual(old_id, sec.id)
  205. self.assertEqual("79b613eb-a256-46bf-84f6-207df465b8f7", sec.id)
  206. # Test invalid custom id exception.
  207. with self.assertRaises(ValueError):
  208. sec.new_id("crash and burn")
  209. def test_clone(self):
  210. # Check parent removal in clone.
  211. psec = Section(name="parent")
  212. sec = Section(name="original", parent=psec)
  213. clone_sec = sec.clone()
  214. self.assertEqual(sec.parent, psec)
  215. self.assertIsNone(clone_sec.parent)
  216. # Check new id in clone.
  217. sec = Section(name="original")
  218. clone_sec = sec.clone()
  219. self.assertEqual(sec, clone_sec)
  220. self.assertNotEqual(sec.id, clone_sec.id)
  221. # Check child Sections and Properties are cloned and have new ids.
  222. Section(name="sec_one", parent=sec)
  223. Section(name="sec_two", parent=sec)
  224. Property(name="prop_one", parent=sec)
  225. Property(name="prop_two", parent=sec)
  226. clone_sec = sec.clone()
  227. # Check sections
  228. self.assertListEqual(sec.sections, clone_sec.sections)
  229. self.assertEqual(sec.sections["sec_one"], clone_sec.sections["sec_one"])
  230. self.assertNotEqual(sec.sections["sec_one"].id, clone_sec.sections["sec_one"].id)
  231. # Check properties
  232. self.assertListEqual(sec.properties, clone_sec.properties)
  233. self.assertEqual(sec.properties["prop_one"], clone_sec.properties["prop_one"])
  234. self.assertNotEqual(sec.properties["prop_one"].id,
  235. clone_sec.properties["prop_one"].id)
  236. # Check child Sections and Properties are not cloned.
  237. clone_sec = sec.clone(children=False)
  238. self.assertListEqual(clone_sec.sections, [])
  239. self.assertListEqual(clone_sec.properties, [])
  240. def test_clone_keep_id(self):
  241. # Check id kept in clone.
  242. sec = Section(name="original")
  243. clone_sec = sec.clone(keep_id=True)
  244. self.assertEqual(sec, clone_sec)
  245. self.assertEqual(sec.id, clone_sec.id)
  246. # Check cloned child Sections keep their ids.
  247. Section(name="sec_one", parent=sec)
  248. Section(name="sec_two", parent=sec)
  249. clone_sec = sec.clone(keep_id=True)
  250. self.assertListEqual(sec.sections, clone_sec.sections)
  251. self.assertEqual(sec.sections["sec_one"], clone_sec.sections["sec_one"])
  252. self.assertEqual(sec.sections["sec_one"].id, clone_sec.sections["sec_one"].id)
  253. # Check cloned child Properties keep their ids.
  254. Property(name="prop_one", parent=sec)
  255. Property(name="prop_two", parent=sec)
  256. clone_sec = sec.clone(keep_id=True)
  257. self.assertListEqual(sec.properties, clone_sec.properties)
  258. self.assertEqual(sec.properties["prop_one"], clone_sec.properties["prop_one"])
  259. self.assertEqual(sec.properties["prop_one"].id,
  260. clone_sec.properties["prop_one"].id)
  261. def test_reorder(self):
  262. # Test reorder of document sections
  263. doc = Document()
  264. sec_one = Section(name="sec_one", parent=doc)
  265. sec_two = Section(name="sec_two", parent=doc)
  266. sec_three = Section(name="sec_three", parent=doc)
  267. self.assertEqual(doc.sections[0].name, sec_one.name)
  268. self.assertEqual(doc.sections[2].name, sec_three.name)
  269. sec_three.reorder(0)
  270. self.assertEqual(doc.sections[0].name, sec_three.name)
  271. self.assertEqual(doc.sections[2].name, sec_two.name)
  272. # Test reorder of document sections
  273. sec = Section(name="main")
  274. sec_one = Section(name="sec_one", parent=sec)
  275. sec_two = Section(name="sec_two", parent=sec)
  276. sec_three = Section(name="sec_three", parent=sec)
  277. self.assertEqual(sec.sections[0].name, sec_one.name)
  278. self.assertEqual(sec.sections[2].name, sec_three.name)
  279. sec_three.reorder(0)
  280. self.assertEqual(sec.sections[0].name, sec_three.name)
  281. self.assertEqual(sec.sections[2].name, sec_two.name)
  282. # Test Exception on unconnected section
  283. with self.assertRaises(ValueError):
  284. sec.reorder(0)
  285. def test_append(self):
  286. main = Section(name="main")
  287. self.assertListEqual(main.sections, [])
  288. self.assertListEqual(main.properties, [])
  289. # Test append Section
  290. sec = Section(name="sec1")
  291. main.append(sec)
  292. self.assertEqual(len(main.sections), 1)
  293. self.assertEqual(sec.parent, main)
  294. # Test fail on Section list or tuple append
  295. with self.assertRaises(ValueError):
  296. main.append([Section(name="sec2"), Section(name="sec3")])
  297. with self.assertRaises(ValueError):
  298. main.append((Section(name="sec2"), Section(name="sec3")))
  299. self.assertEqual(len(main.sections), 1)
  300. # Test append Property
  301. prop = Property(name="prop")
  302. main.append(prop)
  303. self.assertEqual(len(main.properties), 1)
  304. self.assertEqual(prop.parent, main)
  305. # Test fail on Property list or tuple append
  306. with self.assertRaises(ValueError):
  307. main.append([Property(name="prop2"), Property(name="prop3")])
  308. with self.assertRaises(ValueError):
  309. main.append((Property(name="prop2"), Property(name="prop3")))
  310. self.assertEqual(len(main.properties), 1)
  311. # Test fail on unsupported value
  312. with self.assertRaises(ValueError):
  313. main.append(Document())
  314. with self.assertRaises(ValueError):
  315. main.append("Section")
  316. # Test fail on same name entities
  317. with self.assertRaises(KeyError):
  318. main.append(Section(name="sec1"))
  319. self.assertEqual(len(main.sections), 1)
  320. with self.assertRaises(KeyError):
  321. main.append(Property(name="prop"))
  322. self.assertEqual(len(main.properties), 1)
  323. def test_extend(self):
  324. sec = Section(name="main")
  325. self.assertListEqual(sec.sections, [])
  326. self.assertListEqual(sec.properties, [])
  327. # Test extend with Section list
  328. sec.extend([Section(name="sec1"), Section(name="sec2")])
  329. self.assertEqual(len(sec), 2)
  330. self.assertEqual(len(sec.sections), 2)
  331. self.assertEqual(sec.sections[0].name, "sec1")
  332. # Test extend with Property list
  333. sec.extend((Property(name="prop1"), Property(name="prop2")))
  334. self.assertEqual(len(sec), 4)
  335. self.assertEqual(len(sec.properties), 2)
  336. self.assertEqual(sec.properties[0].name, "prop1")
  337. # Test extend with mixed list
  338. sec.extend([Section(name="sec3"), Property(name="prop3")])
  339. self.assertEqual(len(sec), 6)
  340. self.assertEqual(len(sec.sections), 3)
  341. self.assertEqual(len(sec.properties), 3)
  342. # Test fail on non iterable
  343. with self.assertRaises(TypeError):
  344. sec.extend(1)
  345. # Test fail on non Section/Property list entry
  346. with self.assertRaises(ValueError):
  347. sec.extend([Property(name="prop4"), 5])
  348. # Test fail on same name entities
  349. with self.assertRaises(KeyError):
  350. sec.extend([Property(name="new"), Property(name="prop3")])
  351. self.assertEqual(len(sec.properties), 3)
  352. with self.assertRaises(KeyError):
  353. sec.extend([Section(name="new"), Section(name="sec3")])
  354. self.assertEqual(len(sec.sections), 3)
  355. def test_remove(self):
  356. sec = Section(name="remsec")
  357. ssec_one = Section(name="subsec_one", parent=sec)
  358. ssec_two = Section(name="subsec_two", parent=sec)
  359. self.assertEqual(len(sec.sections), 2)
  360. self.assertIsNotNone(ssec_one.parent)
  361. sec.remove(ssec_one)
  362. self.assertEqual(len(sec.sections), 1)
  363. self.assertEqual(sec.sections[0].name, ssec_two.name)
  364. self.assertIsNone(ssec_one.parent)
  365. with self.assertRaises(ValueError):
  366. sec.remove(ssec_one)
  367. self.assertEqual(len(sec.sections), 1)
  368. prop_one = Property(name="prop_one", parent=sec)
  369. prop_two = Property(name="prop_two", parent=sec)
  370. self.assertEqual(len(sec.properties), 2)
  371. self.assertIsNotNone(prop_one.parent)
  372. sec.remove(prop_one)
  373. self.assertEqual(len(sec.properties), 1)
  374. self.assertEqual(sec.properties[0].name, prop_two.name)
  375. self.assertIsNone(prop_one.parent)
  376. with self.assertRaises(ValueError):
  377. sec.remove(prop_one)
  378. self.assertEqual(len(sec.properties), 1)
  379. with self.assertRaises(ValueError):
  380. sec.remove("prop_two")
  381. def test_insert(self):
  382. sec = Section(name="root")
  383. _ = Section(name="subsec_one", parent=sec)
  384. _ = Section(name="subsec_two", parent=sec)
  385. subsec = Section(name="subsec_three")
  386. self.assertNotEqual(sec.sections[1].name, subsec.name)
  387. sec.insert(1, subsec)
  388. self.assertEqual(len(sec.sections), 3)
  389. self.assertEqual(sec.sections[1].name, subsec.name)
  390. self.assertEqual(subsec.parent.name, sec.name)
  391. _ = Property(name="prop_one", parent=sec)
  392. _ = Property(name="prop_two", parent=sec)
  393. prop = Property(name="prop_three")
  394. self.assertNotEqual(sec.properties[1].name, prop.name)
  395. sec.insert(1, prop)
  396. self.assertEqual(len(sec.properties), 3)
  397. self.assertEqual(sec.properties[1].name, prop.name)
  398. self.assertEqual(prop.parent.name, sec.name)
  399. # Test invalid object
  400. with self.assertRaises(ValueError):
  401. sec.insert(1, Document())
  402. with self.assertRaises(ValueError):
  403. sec.insert(1, "some info")
  404. self.assertEqual(len(sec), 6)
  405. # Test same name entries
  406. with self.assertRaises(ValueError):
  407. sec.insert(0, subsec)
  408. with self.assertRaises(ValueError):
  409. sec.insert(0, prop)
  410. self.assertEqual(len(sec), 6)
  411. def test_contains(self):
  412. sec = Section(name="root")
  413. subsec = Section(name="subsec", type="test")
  414. prop = Property(name="prop")
  415. # Test not contains on empty child-lists.
  416. self.assertIsNone(sec.contains(subsec))
  417. self.assertIsNone(sec.contains(prop))
  418. # Test contains of Section and Property
  419. subsec.parent = sec
  420. simisec = Section(name="subsec", type="test")
  421. self.assertEqual(sec.contains(simisec).name, subsec.name)
  422. prop.parent = sec
  423. simiprop = Property(name="prop")
  424. self.assertEqual(sec.contains(simiprop).name, prop.name)
  425. # Test not contains on mismatching Section name/type and Property name
  426. self.assertIsNone(sec.contains(Section(name="subsec", type="typetest")))
  427. self.assertIsNone(sec.contains(Section(name="typesec", type="test")))
  428. self.assertIsNone(sec.contains(Property(name="prop_two")))
  429. # Test fail on non-Section/Property objects
  430. with self.assertRaises(ValueError):
  431. sec.contains(Document())
  432. with self.assertRaises(ValueError):
  433. sec.contains("some info")
  434. def test_merge_check(self):
  435. # -- Root level Section checks
  436. # Test empty Section check
  437. source = Section(name="source")
  438. destination = Section(name="destination")
  439. destination.merge_check(source, True)
  440. # Test definition check
  441. source = Section(name="source", definition="def")
  442. destination = Section(name="destination", definition="def")
  443. destination.merge_check(source, True)
  444. source.definition = "other def"
  445. with self.assertRaises(ValueError):
  446. destination.merge_check(source, True)
  447. # Test reference check
  448. source = Section(name="source", reference="ref")
  449. destination = Section(name="destination", reference="ref")
  450. destination.merge_check(source, True)
  451. source.reference = "other ref"
  452. with self.assertRaises(ValueError):
  453. destination.merge_check(source, True)
  454. # -- First child level Section checks
  455. source = Section(name="source")
  456. destination = Section(name="destination")
  457. s_sec_one = Section(name="lvl", type="one",
  458. reference="ref", definition="def", parent=source)
  459. _ = Section(name="unrelated", type="one",
  460. reference="one", definition="one", parent=source)
  461. _ = Section(name="lvl", type="one",
  462. reference="ref", definition="def", parent=destination)
  463. _ = Section(name="unrelated", type="two",
  464. reference="two", definition="two", parent=destination)
  465. # Test Section child level definition check
  466. destination.merge_check(source, True)
  467. s_sec_one.definition = "other def"
  468. with self.assertRaises(ValueError):
  469. destination.merge_check(source, True)
  470. # Test Section child level reference check
  471. s_sec_one.definition = "def"
  472. s_sec_one.reference = "other ref"
  473. with self.assertRaises(ValueError):
  474. destination.merge_check(source, True)
  475. # -- Second child level Section checks
  476. source = Section(name="source")
  477. destination = Section(name="destination")
  478. s_sec_one = Section(name="lvl", type="one",
  479. reference="ref", definition="def", parent=source)
  480. s_subsec_one = Section(name="lvl", type="two",
  481. reference="ref2", definition="def2", parent=s_sec_one)
  482. s_sec_two = Section(name="unrelated", type="one",
  483. reference="one", definition="one", parent=source)
  484. _ = Section(name="lvl", type="two",
  485. reference="none1", definition="none1", parent=s_sec_two)
  486. d_sec_one = Section(name="lvl", type="one",
  487. reference="ref", definition="def", parent=destination)
  488. _ = Section(name="lvl", type="two",
  489. reference="ref2", definition="def2", parent=d_sec_one)
  490. d_sec_two = Section(name="unrelated", type="two",
  491. reference="two", definition="two", parent=destination)
  492. _ = Section(name="lvl", type="two",
  493. reference="none2", definition="none2", parent=d_sec_two)
  494. # Test Section 2nd child level definition check
  495. # Check no definition/reference ValueError between s_subsec_two and d_subsec_one
  496. # since their parents will not be merged.
  497. destination.merge_check(source, True)
  498. # Raise a definition ValueError between s_subsec_one and d_subsec_one
  499. # since their parents will be merged.
  500. s_subsec_one.definition = "other def"
  501. with self.assertRaises(ValueError):
  502. destination.merge_check(source, True)
  503. # Test Section 2nd child level reference check
  504. s_subsec_one.definition = "def2"
  505. # Raise a reference ValueError between s_subsec_one and d_subsec_one
  506. # since their parents will be merged.
  507. s_subsec_one.reference = "other ref"
  508. with self.assertRaises(ValueError):
  509. destination.merge_check(source, True)
  510. # -- Root level Property checks
  511. # All Property checks will only test unit failure in the Section merge context.
  512. # Other failures are covered by the specific Property merge check tests.
  513. source = Section(name="source")
  514. destination = Section(name="destination")
  515. s_prop = Property(name="prop", parent=source)
  516. d_prop = Property(name="prop", parent=destination)
  517. destination.merge_check(source, True)
  518. s_prop.unit = "Hz"
  519. d_prop.unit = "s"
  520. with self.assertRaises(ValueError):
  521. destination.merge_check(source, True)
  522. # -- First child level Property checks
  523. source = Section(name="source")
  524. destination = Section(name="destination")
  525. s_prop_one = Property(name="lvl one", unit="Hz", parent=source)
  526. _ = Property(name="unrelated one", unit="one", parent=source)
  527. _ = Property(name="lvl one", unit="Hz", parent=destination)
  528. _ = Property(name="unrelated two", unit="two", parent=destination)
  529. # Test Property child level check
  530. destination.merge_check(source, True)
  531. # Test raise ValueError between s_prop_one and d_prop_one
  532. s_prop_one.unit = "other unit"
  533. with self.assertRaises(ValueError):
  534. destination.merge_check(source, True)
  535. # -- Second child level Property checks
  536. source = Section(name="source")
  537. destination = Section(name="destination")
  538. s_sec_one = Section(name="lvl", type="one", parent=source)
  539. s_subprop_one = Property(name="lvl one", unit="Hz", parent=s_sec_one)
  540. s_sec_two = Section(name="unrelated", type="one", parent=source)
  541. _ = Property(name="unrelated one", unit="one", parent=s_sec_two)
  542. d_sec_one = Section(name="lvl", type="one", parent=destination)
  543. _ = Property(name="lvl one", unit="Hz", parent=d_sec_one)
  544. d_sec_two = Section(name="unrelated", type="two", parent=destination)
  545. _ = Property(name="unrelated one", unit="two", parent=d_sec_two)
  546. # Test Property 2nd child level definition check
  547. # Check no unit ValueError between s_subprop_two and d_subprop_one
  548. # since their parents will not be merged.
  549. destination.merge_check(source, True)
  550. # Raise a unit ValueError between s_subprop_one and d_subprop_one
  551. # since their parents will be merged.
  552. s_subprop_one.unit = "other unit"
  553. with self.assertRaises(ValueError):
  554. destination.merge_check(source, True)
  555. def test_merge(self):
  556. # -- Root level Section merge tests
  557. source = Section(name="source", definition="def", reference="ref")
  558. destination = Section(name="destination")
  559. destination.merge(source)
  560. self.assertEqual(destination.definition, source.definition)
  561. self.assertEqual(destination.reference, source.reference)
  562. # -- First child level Section merge tests
  563. s_sec_one = Section(name="lvl", type="one", definition="def", parent=source)
  564. s_sec_two = Section(name="other", type="one", parent=source)
  565. _ = Section(name="lvl", type="one", parent=destination)
  566. self.assertEqual(len(destination), 1)
  567. self.assertIsNone(destination.sections["lvl"].definition)
  568. self.assertIsNone(destination.sections["lvl"].reference)
  569. destination.merge(source)
  570. self.assertEqual(len(destination), 2)
  571. self.assertEqual(destination.sections["lvl"].definition, s_sec_one.definition)
  572. self.assertEqual(destination.sections["lvl"].reference, s_sec_one.reference)
  573. self.assertEqual(destination.sections["other"], s_sec_two)
  574. # -- Root level Property merge tests
  575. source = Section(name="source")
  576. destination = Section(name="destination")
  577. s_prop_one = Property(name="prop_one", unit="Hz", parent=source)
  578. s_prop_two = Property(name="prop_two", parent=source)
  579. _ = Property(name="prop_one", parent=destination)
  580. self.assertEqual(len(destination.properties), 1)
  581. self.assertIsNone(destination.properties["prop_one"].unit)
  582. destination.merge(source)
  583. self.assertEqual(len(destination.properties), 2)
  584. self.assertEqual(destination.properties["prop_one"].unit, s_prop_one.unit)
  585. self.assertEqual(destination.properties["prop_two"], s_prop_two)
  586. # -- First child level Property merge tests
  587. source = Section(name="source")
  588. destination = Section(name="destination")
  589. s_sec_one = Section(name="lvl", type="one", definition="def", parent=source)
  590. s_prop_one = Property(name="prop_one", unit="Hz", parent=s_sec_one)
  591. s_prop_two = Property(name="prop_two", parent=s_sec_one)
  592. d_sec_one = Section(name="lvl", type="one", parent=destination)
  593. _ = Property(name="prop_one", parent=d_sec_one)
  594. self.assertEqual(len(destination.properties), 0)
  595. self.assertEqual(len(destination.sections["lvl"].properties), 1)
  596. self.assertIsNone(destination.sections["lvl"].properties["prop_one"].unit)
  597. destination.merge(source)
  598. self.assertEqual(len(destination.properties), 0)
  599. self.assertEqual(len(destination.sections["lvl"].properties), 2)
  600. self.assertEqual(destination.sections["lvl"].properties["prop_one"].unit,
  601. s_prop_one.unit)
  602. self.assertEqual(destination.sections["lvl"].properties["prop_two"],
  603. s_prop_two)
  604. # -- Test nothing merged on second child level ValueError
  605. source = Section(name="source", definition="def", reference="ref")
  606. destination = Section(name="destination")
  607. s_sec_one = Section(name="lvl", type="one", definition="def", parent=source)
  608. _ = Section(name="other", type="one", parent=source)
  609. d_sec_one = Section(name="lvl", type="one", parent=destination)
  610. _ = Property(name="prop", value=[1, 2, 3], parent=s_sec_one)
  611. d_subprop_one = Property(name="prop", value=["four", "five"], parent=d_sec_one)
  612. self.assertEqual(len(destination.sections), 1)
  613. self.assertEqual(len(destination.sections["lvl"].properties), 1)
  614. self.assertIsNone(destination.definition)
  615. self.assertIsNone(destination.sections["lvl"].definition)
  616. self.assertEqual(destination.sections["lvl"].properties[0].values,
  617. d_subprop_one.values)
  618. with self.assertRaises(ValueError):
  619. destination.merge(source)
  620. self.assertEqual(len(destination.sections), 1)
  621. self.assertEqual(len(destination.sections["lvl"].properties), 1)
  622. self.assertIsNone(destination.definition)
  623. self.assertIsNone(destination.sections["lvl"].definition)
  624. self.assertEqual(destination.sections["lvl"].properties[0].values,
  625. d_subprop_one.values)
  626. def test_comparison(self):
  627. sec_name = "sec name"
  628. sec_type = "sec type"
  629. sec_def = "an odml test section"
  630. sec_ref = "from over there"
  631. sec_a = Section(name=sec_name, type=sec_type,
  632. definition=sec_def, reference=sec_ref)
  633. sec_b = Section(name=sec_name, type=sec_type,
  634. definition=sec_def, reference=sec_ref)
  635. self.assertEqual(sec_a, sec_b)
  636. sec_b.name = "newSecName"
  637. self.assertNotEqual(sec_a, sec_b)
  638. sec_b.name = sec_name
  639. # Test section equality with subsections
  640. # Test equality with subsection of different entities
  641. # with same content and same children order
  642. subsec_aa = Section(name="subsecA", type=sec_type,
  643. definition=sec_def, reference=sec_ref)
  644. subsec_ab = Section(name="subsecB", type=sec_type,
  645. definition=sec_def, reference=sec_ref)
  646. subsec_ba = Section(name="subsecA", type=sec_type,
  647. definition=sec_def, reference=sec_ref)
  648. subsec_bb = Section(name="subsecB", type=sec_type,
  649. definition=sec_def, reference=sec_ref)
  650. sec_a.extend([subsec_aa, subsec_ab])
  651. sec_b.extend([subsec_ba, subsec_bb])
  652. self.assertEqual(sec_a, sec_b)
  653. self.assertEqual(sec_a.sections, sec_b.sections)
  654. sec_b.sections[0].name = "newSubsecA"
  655. self.assertNotEqual(sec_a, sec_b)
  656. self.assertNotEqual(sec_a.sections, sec_b.sections)
  657. sec_b.sections[0].name = "subsecA"
  658. # Test inequality with different number of children
  659. sec_b.remove(sec_b.sections[1])
  660. self.assertNotEqual(sec_a, sec_b)
  661. self.assertNotEqual(sec_a.sections, sec_b.sections)
  662. # Test equality with subsection of different entities
  663. # with same content and different children order
  664. sec_b.remove(sec_b.sections[0])
  665. sec_b.extend([subsec_bb, subsec_ba])
  666. self.assertEqual(sec_a, sec_b)
  667. self.assertEqual(sec_a.sections, sec_b.sections)
  668. sec_b.sections[0].name = "newSubsecB"
  669. self.assertNotEqual(sec_a, sec_b)
  670. self.assertNotEqual(sec_a.sections, sec_b.sections)
  671. sec_b.sections[0].name = "subsecB"
  672. # Test section equality with properties
  673. # Test equality with properties of different entities
  674. # with same content and same children order
  675. prop_aa = Property(name="propA", definition="propDef")
  676. prop_ab = Property(name="propB", definition="propDef")
  677. prop_ba = Property(name="propA", definition="propDef")
  678. prop_bb = Property(name="propB", definition="propDef")
  679. sec_a.extend([prop_aa, prop_ab])
  680. sec_b.extend([prop_ba, prop_bb])
  681. self.assertEqual(sec_a, sec_b)
  682. self.assertEqual(sec_a.properties, sec_b.properties)
  683. sec_b.properties[0].name = "newPropA"
  684. self.assertNotEqual(sec_a, sec_b)
  685. self.assertNotEqual(sec_a.properties, sec_b.properties)
  686. sec_b.properties[0].name = "propA"
  687. # Test inequality with different number of children
  688. sec_b.remove(sec_b.properties[1])
  689. self.assertNotEqual(sec_a, sec_b)
  690. self.assertNotEqual(sec_a.properties, sec_b.properties)
  691. # Test equality with properties of different entities
  692. # with same content and different children order
  693. sec_b.remove(sec_b.properties[0])
  694. sec_b.extend([prop_bb, prop_ba])
  695. self.assertEqual(sec_a, sec_b)
  696. self.assertEqual(sec_a.properties, sec_b.properties)
  697. sec_b.properties[0].name = "newPropB"
  698. self.assertNotEqual(sec_a, sec_b)
  699. self.assertNotEqual(sec_a.properties, sec_b.properties)
  700. def test_create_section(self):
  701. root = Section("root")
  702. self.assertEqual(len(root.sections), 0)
  703. name = "subsec"
  704. type = "subtype"
  705. oid = "79b613eb-a256-46bf-84f6-207df465b8f7"
  706. subsec = root.create_section(name, type, oid)
  707. self.assertEqual(len(root.sections), 1)
  708. self.assertEqual(subsec.parent, root)
  709. self.assertEqual(root.sections[name], subsec)
  710. self.assertEqual(root.sections[name].type, type)
  711. self.assertEqual(root.sections[name].oid, oid)
  712. name = "othersec"
  713. subsec = root.create_section(name)
  714. self.assertEqual(len(root.sections), 2)
  715. self.assertEqual(subsec.parent, root)
  716. self.assertEqual(root.sections[name], subsec)
  717. self.assertEqual(root.sections[name].type, "n.s.")
  718. name = "subsubsec"
  719. subsec = root.sections[0].create_section(name)
  720. self.assertEqual(len(root.sections), 2)
  721. self.assertEqual(subsec.parent, root.sections[0])
  722. self.assertEqual(len(root.sections[0].sections), 1)
  723. self.assertEqual(root.sections[0].sections[0].name, name)
  724. def test_create_property(self):
  725. root = Section("root")
  726. self.assertEqual(len(root.properties), 0)
  727. name = "prop"
  728. oid = "79b613eb-a256-46bf-84f6-207df465b8f7"
  729. prop = root.create_property(name, oid=oid)
  730. self.assertEqual(len(root.properties), 1)
  731. self.assertEqual(prop.parent, root)
  732. self.assertEqual(root.properties[name].oid, oid)
  733. name = "test_values"
  734. values = ["a", "b"]
  735. prop = root.create_property(name, value=values)
  736. self.assertEqual(len(root.properties), 2)
  737. self.assertEqual(root.properties[name].values, values)
  738. name = "test_dtype"
  739. dtype = "str"
  740. prop = root.create_property(name, dtype=dtype)
  741. self.assertEqual(len(root.properties), 3)
  742. self.assertEqual(root.properties[name].dtype, dtype)
  743. name = "test_dtype_fail"
  744. dtype = "I do not exist"
  745. prop = root.create_property(name, dtype=dtype)
  746. self.assertIsNone(prop.dtype)
  747. def test_export_leaf(self):
  748. doc = Document()
  749. first = doc.create_section("first")
  750. second = first.create_section("second")
  751. third = first.create_section("third")
  752. name = "prop1"
  753. values = [1.3]
  754. first.create_property(name, value=values)
  755. name = "prop2"
  756. values = ["words"]
  757. first.create_property(name, value=values)
  758. name = "prop3"
  759. values = ["a", "b"]
  760. second.create_property(name, value=values)
  761. ex1 = first.export_leaf()
  762. self.assertEqual(len(ex1.sections), 1)
  763. self.assertEqual(len(ex1['first'].properties), 2)
  764. self.assertEqual(len(ex1['first'].sections), 0)
  765. ex2 = second.export_leaf()
  766. self.assertEqual(len(ex2.sections), 1)
  767. self.assertEqual(len(ex2['first'].properties), 2)
  768. self.assertEqual(len(ex2['first'].sections), 1)
  769. self.assertEqual(len(ex2['first']['second'].properties), 1)
  770. ex3 = third.export_leaf()
  771. self.assertEqual(len(ex3.sections), 1)
  772. self.assertEqual(len(ex3['first'].properties), 2)
  773. self.assertEqual(len(ex3['first'].sections), 1)
  774. self.assertEqual(len(ex3['first']['third']), 0)
  775. def _test_cardinality_re_assignment(self, obj, obj_attribute):
  776. """
  777. Tests the basic set of both Section properties and sub-sections cardinality.
  778. :param obj: odml Section
  779. :param obj_attribute: string with the cardinality attribute that is supposed to be tested.
  780. Should be either 'prop_cardinality' or 'sec_cardinality'.
  781. """
  782. oat = obj_attribute
  783. # Test Section prop/sec cardinality reset
  784. for non_val in [None, "", [], (), {}]:
  785. setattr(obj, oat, non_val)
  786. self.assertIsNone(getattr(obj, oat))
  787. setattr(obj, oat, 1)
  788. # Test Section prop/sec cardinality single int max assignment
  789. setattr(obj, oat, 10)
  790. self.assertEqual(getattr(obj, oat), (None, 10))
  791. # Test Section prop/sec cardinality tuple max assignment
  792. setattr(obj, oat, (None, 5))
  793. self.assertEqual(getattr(obj, oat), (None, 5))
  794. # Test Section prop/sec cardinality tuple min assignment
  795. setattr(obj, oat, (5, None))
  796. self.assertEqual(getattr(obj, oat), (5, None))
  797. # Test Section prop/sec cardinality min/max assignment
  798. setattr(obj, oat, (1, 5))
  799. self.assertEqual(getattr(obj, oat), (1, 5))
  800. # -- Test Section prop/sec cardinality assignment failures
  801. with self.assertRaises(ValueError):
  802. setattr(obj, oat, "a")
  803. with self.assertRaises(ValueError):
  804. setattr(obj, oat, -1)
  805. with self.assertRaises(ValueError):
  806. setattr(obj, oat, (1, "b"))
  807. with self.assertRaises(ValueError):
  808. setattr(obj, oat, (1, 2, 3))
  809. with self.assertRaises(ValueError):
  810. setattr(obj, oat, [1, 2, 3])
  811. with self.assertRaises(ValueError):
  812. setattr(obj, oat, {1: 2, 3: 4})
  813. with self.assertRaises(ValueError):
  814. setattr(obj, oat, (-1, 1))
  815. with self.assertRaises(ValueError):
  816. setattr(obj, oat, (1, -5))
  817. with self.assertRaises(ValueError):
  818. setattr(obj, oat, (5, 1))
  819. def test_properties_cardinality(self):
  820. """
  821. Tests the basic assignment rules for Section Properties cardinality
  822. on init and re-assignment but does not test properties assignment or
  823. the actual cardinality validation.
  824. """
  825. doc = Document()
  826. # -- Test set cardinality on Section init
  827. # Test empty init
  828. sec_prop_card_none = Section(name="sec_prop_card_none", type="test", parent=doc)
  829. self.assertIsNone(sec_prop_card_none.prop_cardinality)
  830. # Test single int max init
  831. sec_card_max = Section(name="prop_cardinality_max", prop_cardinality=10, parent=doc)
  832. self.assertEqual(sec_card_max.prop_cardinality, (None, 10))
  833. # Test tuple init
  834. sec_card_min = Section(name="prop_cardinality_min", prop_cardinality=(2, None), parent=doc)
  835. self.assertEqual(sec_card_min.prop_cardinality, (2, None))
  836. # -- Test Section properties cardinality re-assignment
  837. sec = Section(name="prop", prop_cardinality=(None, 10), parent=doc)
  838. self.assertEqual(sec.prop_cardinality, (None, 10))
  839. # Use general method to reduce redundancy
  840. self._test_cardinality_re_assignment(sec, 'prop_cardinality')
  841. def test_sections_cardinality(self):
  842. """
  843. Tests the basic assignment rules for Section sections cardinality
  844. on init and re-assignment but does not test sections assignment or
  845. the actual cardinality validation.
  846. """
  847. doc = Document()
  848. # -- Test set cardinality on Section init
  849. # Test empty init
  850. sec_card_none = Section(name="sec_cardinality_none", type="test", parent=doc)
  851. self.assertIsNone(sec_card_none.sec_cardinality)
  852. # Test single int max init
  853. sec_card_max = Section(name="sec_cardinality_max", sec_cardinality=10, parent=doc)
  854. self.assertEqual(sec_card_max.sec_cardinality, (None, 10))
  855. # Test tuple init
  856. sec_card_min = Section(name="sec_cardinality_min", sec_cardinality=(2, None), parent=doc)
  857. self.assertEqual(sec_card_min.sec_cardinality, (2, None))
  858. # -- Test Section properties cardinality re-assignment
  859. sec = Section(name="sec", sec_cardinality=(None, 10), parent=doc)
  860. self.assertEqual(sec.sec_cardinality, (None, 10))
  861. # Use general method to reduce redundancy
  862. self._test_cardinality_re_assignment(sec, 'sec_cardinality')
  863. def _test_set_cardinality_method(self, obj, obj_attribute, set_cardinality_method):
  864. """
  865. Tests the basic set convenience method of both Section properties and
  866. sub-sections cardinality.
  867. :param obj: odml Section
  868. :param obj_attribute: string with the cardinality attribute that is supposed to be tested.
  869. Should be either 'prop_cardinality' or 'sec_cardinality'.
  870. :param set_cardinality_method: The convenience method used to set the cardinality.
  871. """
  872. oba = obj_attribute
  873. # Test Section prop/sec cardinality min assignment
  874. set_cardinality_method(1)
  875. self.assertEqual(getattr(obj, oba), (1, None))
  876. # Test Section prop/sec cardinality keyword min assignment
  877. set_cardinality_method(min_val=2)
  878. self.assertEqual(getattr(obj, oba), (2, None))
  879. # Test Section prop/sec cardinality max assignment
  880. set_cardinality_method(None, 1)
  881. self.assertEqual(getattr(obj, oba), (None, 1))
  882. # Test Section prop/sec cardinality keyword max assignment
  883. set_cardinality_method(max_val=2)
  884. self.assertEqual(getattr(obj, oba), (None, 2))
  885. # Test Section prop/sec cardinality min max assignment
  886. set_cardinality_method(1, 2)
  887. self.assertEqual(getattr(obj, oba), (1, 2))
  888. # Test Section prop/sec cardinality keyword min max assignment
  889. set_cardinality_method(min_val=2, max_val=5)
  890. self.assertEqual(getattr(obj, oba), (2, 5))
  891. # Test Section prop/sec cardinality empty reset
  892. set_cardinality_method()
  893. self.assertIsNone(getattr(obj, oba))
  894. # Test Section prop/sec cardinality keyword empty reset
  895. set_cardinality_method(1)
  896. self.assertIsNotNone(getattr(obj, oba))
  897. set_cardinality_method(min_val=None, max_val=None)
  898. self.assertIsNone(getattr(obj, oba))
  899. def test_set_properties_cardinality(self):
  900. doc = Document()
  901. sec = Section(name="sec", type="test", parent=doc)
  902. # Use general method to reduce redundancy
  903. self._test_set_cardinality_method(sec, 'prop_cardinality', sec.set_properties_cardinality)
  904. def test_set_sections_cardinality(self):
  905. doc = Document()
  906. sec = Section(name="sec", type="test", parent=doc)
  907. # Use general method to reduce redundancy
  908. self._test_set_cardinality_method(sec, 'sec_cardinality', sec.set_sections_cardinality)
  909. def test_link(self):
  910. pass
  911. def test_include(self):
  912. pass
  913. def test_repository(self):
  914. pass
  915. def test_unmerge(self):
  916. pass