mapping.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. #-*- coding: utf-8
  2. import unittest
  3. import odml
  4. import odml.terminology
  5. import odml.tools.dumper as dumper
  6. from test.samplefile import parse
  7. import odml.mapping as mapping
  8. class TestMapping(unittest.TestCase):
  9. """
  10. Testcases for the mapping mechanisms and rules.
  11. Also useful to understand, how mappings work.
  12. Also have a look at the actual sourcefile (``test/mapping.py``)
  13. which provides illustrations to the rule-definitions.
  14. """
  15. def check(self, src, dst, do_map=True):
  16. """
  17. check if the mapping of *src* is equivalent to *dst*
  18. if map is False, just compare src to dst, assuming the mapping
  19. has already been applied manually
  20. """
  21. if do_map:
  22. mapped = mapping.create_mapping(src)
  23. else:
  24. mapped = src
  25. if mapped != dst:
  26. print('\n')
  27. dumper.dumpDoc(mapped)
  28. print("---- vs ----")
  29. dumper.dumpDoc(dst)
  30. print('\n')
  31. self.assertEqual(mapped, dst)
  32. self.assertEqual(dst, mapped) # do the vice versa test too
  33. return mapped
  34. def test_parse(self):
  35. s = """
  36. s1[t1] mapping [T1]
  37. - p1 mapping [T2:P2]
  38. - s2[t2] mapping [T2]
  39. - p3
  40. - p4 mapping [T3:P1]
  41. s2[t1]
  42. - s21[t2] linked to /s1/s2
  43. """
  44. doc = parse(s)
  45. #for sec in doc:
  46. # dumper.dumpSection(sec)
  47. def test_rule1(self):
  48. """
  49. 1. Sections und Properties koennen Mapping Information tragen. Wenn keine
  50. vorhanden ist, kann diese auch in einer eventuell angegebenen Terminologie
  51. zu finden sein.
  52. 1. Enthält eine Section ein Mapping, dann ändert sich der Typ der Section,
  53. der Name wird übernommen.
  54. s1[t1] mapping [T1] --> s1[T1]
  55. """
  56. odml.terminology.terminologies['map'] = parse("S1[T1]")
  57. odml.terminology.terminologies['term'] = parse("SX[t1] mapping [T1]")
  58. src = parse("s1[t1]")
  59. dst = parse("s1[T1]")
  60. src.repository = 'term'
  61. dst.repository = 'term' # dst needs to be equal to src for the comparism
  62. self.check(src, dst)
  63. def test_rule1_SectionNotFound(self):
  64. """
  65. a MappingError is raised when the mapping cannot be resolved
  66. """
  67. odml.terminology.terminologies['map'] = parse("S1[T1]")
  68. src = parse("s1[t1] mapping [T2]")
  69. with self.assertRaises(mapping.MappingError):
  70. self.check(src, None)
  71. def test_rule2(self):
  72. """
  73. 2. Enthält eine Section kein Mapping und es gibt auch keines in der
  74. Terminologie, dann bleibt alles beim alten
  75. """
  76. src = parse("s1[t1]")
  77. dst = parse("s1[t1]")
  78. self.check(src, dst)
  79. odml.terminology.terminologies['map'] = parse("""
  80. S1[T1]
  81. S11[T11]
  82. S21[T21]
  83. """)
  84. src = parse("""
  85. s1[t1] mapping [T1]
  86. - s11[t11] mapping [T11]
  87. - s12[t12]
  88. s2[t2]
  89. - s21[t21] mapping [T21]
  90. """)
  91. dst = parse("""
  92. s1[T1]
  93. - s11[T11]
  94. - s12[t12]
  95. s2[t2]
  96. - s21[T21]
  97. """)
  98. self.check(src, dst)
  99. def test_rule3(self):
  100. """
  101. 3: Enthält eine Property kein Mapping und es ist auch keines in der
  102. Terminologie vorhanden, so bleibt alles beim Alten. Die Property landet
  103. in der Section, in die sein Elternteil gemappt wurde.
  104. """
  105. odml.terminology.terminologies['map'] = parse("S1[T1]")
  106. src = parse("""
  107. s1[t1] mapping [T1]
  108. - p1
  109. """)
  110. dst = parse("""
  111. s1[T1]
  112. - p1
  113. """)
  114. self.check(src, dst)
  115. src = parse("""
  116. s1[t1]
  117. - p1
  118. """)
  119. dst = src.clone()
  120. self.check(src, dst)
  121. def map_rule4(self):
  122. """
  123. set up the terminology for rule4 tests
  124. """
  125. odml.terminology.terminologies['map'] = parse("""
  126. S1[T1]
  127. - P2
  128. S2[T2]
  129. - P1
  130. S3[T3]
  131. - P1
  132. - P2
  133. - P3
  134. """)
  135. def test_rule4c(self):
  136. """
  137. 4. Wenn ein mapping vorhanden ist, dann gilt es verschiedenes zu überprüfen.
  138. Hier muss beachtet werden, ob es eine Abhängigkeit gibt die beachtet
  139. werden und erhalten werden müssen...
  140. 4c: Ist der Zieltyp gleich dem der Elternsection, oder nicht?
  141. Wenn ja, dann einfach hinzufügen. (s3.p1 und s3.p2)
  142. """
  143. self.map_rule4()
  144. src = parse("""
  145. s3[t3] mapping [T3]
  146. - p1 mapping [T3:P2]
  147. - p2 mapping [T3:P3]
  148. """)
  149. dst = parse("""
  150. s3[T3]
  151. - P2
  152. - P3
  153. """)
  154. self.check(src, dst)
  155. def test_rule4d1(self):
  156. """
  157. 4d: Wenn dem nicht so ist (Elternsection != Zieltyp), dann wird zunächst
  158. überprüft, ob eine Kindsection der gemappten Elternsection dem
  159. geforderten Typ entspricht.
  160. 4d1: Wenn ja, dann dahin (wenn eindeutig TODO) weil dies die stärkste Verwandschaftsbeziehung darstellt.
  161. """
  162. self.map_rule4()
  163. src = parse("""
  164. s1[t1]
  165. - s2[t2] mapping [T2]
  166. - p2 mapping [T2:P1]
  167. """)
  168. dst = parse("""
  169. s1[t1]
  170. - s2[T2]
  171. - P1
  172. """)
  173. self.check(src, dst)
  174. def test_rule4d2(self):
  175. """
  176. 4d2: Wenn nicht (mehrere Kinder des Typs), MappingError
  177. """
  178. self.map_rule4()
  179. src = parse("""
  180. s1[t1]
  181. - p2 mapping [T2:P1]
  182. - s2[t2] mapping [T2]
  183. - s3[T2]
  184. """)
  185. dst = parse("""
  186. s1[t1]
  187. - s2[T2]
  188. - s3[T2]
  189. S2[T2]
  190. - P1
  191. """)
  192. with self.assertRaises(mapping.MappingError):
  193. self.check(src, dst)
  194. def test_rule4e1(self):
  195. """
  196. 4d3: Wenn nicht (keine Kinder des Typs), dann gehe ich im Moment nur
  197. einen Schritt nach oben und überprüfe,
  198. 4e: ob eine Geschwistersection der gemappten Elternsection dem Property
  199. Zieltypen entspricht.
  200. 4e1: Wenn ja und diese nur eine related-section des Typs der gemappten
  201. Elternsection hat, dort hinzufügen
  202. """
  203. self.map_rule4()
  204. src = parse("""
  205. s1[t1]
  206. - p2 mapping [T2:P1]
  207. s2[t2] mapping [T2]
  208. """)
  209. dst = parse("""
  210. s1[t1]
  211. s2[T2]
  212. - P1
  213. """)
  214. self.check(src, dst)
  215. def test_rule4e2(self):
  216. """
  217. 4e2: Wenn ja und diese mehrere related-section des Typs der gemappten
  218. Elternsection hat, die Section mit einem link erstellen
  219. """
  220. self.map_rule4()
  221. src = parse("""
  222. s1[t1]
  223. - p2 mapping [T2:P1]
  224. s2[t2] mapping [T2]
  225. s3[t1]
  226. """)
  227. dst = parse("""
  228. s1[t1]
  229. - s2[T2] linked to /s2
  230. - P1
  231. s2[T2]
  232. s3[t1]
  233. """)
  234. self.check(src, dst)
  235. # nochmal das selbe mit entfernterer verwandtschaft
  236. src = parse("""
  237. s1[t1]
  238. - p2 mapping [T2:P1]
  239. s2[t2] mapping [T2]
  240. - s3[t1]
  241. """)
  242. dst = parse("""
  243. s1[t1]
  244. - s2[T2] linked to /s2
  245. - P1
  246. s2[T2]
  247. - s3[t1]
  248. """)
  249. self.check(src, dst)
  250. # now test multiple links
  251. src = parse("""
  252. s1[t1]
  253. - p2 mapping [T3:P1]
  254. - p3 mapping [T3:P2]
  255. s2[t2] mapping [T3]
  256. - s3[t1]
  257. """)
  258. dst = parse("""
  259. s1[t1]
  260. - s2[T3] linked to /s2
  261. - P1
  262. - P2
  263. s2[T3]
  264. - s3[t1]
  265. """)
  266. self.check(src, dst)
  267. def test_rule4f(self):
  268. """
  269. 4f: Wenn nicht (kein Geschwister des Typs),
  270. dann erstelle eine entsprechende Section, füge sie mit Property der
  271. Elternsection hinzu
  272. (TODO oder auch nur wenn nicht mehr als eine related section der gemappten Elternsection?)
  273. """
  274. self.map_rule4()
  275. src = parse("""
  276. s1[t1]
  277. - p2 mapping [T2:P1]
  278. """)
  279. dst = parse("""
  280. s1[t1]
  281. - S2[T2]
  282. - P1
  283. """)
  284. self.check(src, dst)
  285. src = parse("""
  286. s1[t1]
  287. - p2 mapping [T2:P1]
  288. s2[t1]
  289. """)
  290. dst = parse("""
  291. s1[t1]
  292. - S2[T2]
  293. - P1
  294. s2[t1]
  295. """)
  296. self.check(src, dst)
  297. def test_multiple(self):
  298. self.map_rule4()
  299. src = parse("""
  300. s1[t1] mapping [T1]
  301. - p1 mapping [T2:P1]
  302. - p2 mapping [T1:P2]
  303. - p3
  304. - p4 mapping [T3:P1]
  305. s2[t1] mapping [T1]
  306. - p1 mapping [T2:P1]
  307. - p2 mapping [T1:P2]
  308. - p3
  309. - p4 mapping [T3:P1]
  310. s3[t3] mapping [T3]
  311. - p1 mapping [T3:P2]
  312. - p2 mapping [T3:P3]
  313. """)
  314. dst = parse("""
  315. s1[T1]
  316. - P2
  317. - p3
  318. - S2[T2]
  319. - P1
  320. - s3[T3] linked to /s3
  321. - P1
  322. s2[T1]
  323. - P2
  324. - p3
  325. - S2[T2]
  326. - P1
  327. - s3[T3] linked to /s3
  328. - P1
  329. s3[T3]
  330. - P2
  331. - P3
  332. """)
  333. self.check(src, dst)
  334. def test_editing(self):
  335. self.map_rule4()
  336. src = parse("""
  337. s1[t1]
  338. - p2 mapping [T2:P1]
  339. s2[t2] mapping [T2]
  340. """)
  341. map = mapping.create_mapping(src)
  342. src['s1'].properties['p2'].mapping = 'map#T3:P1'
  343. dst = parse("""
  344. s1[t1]
  345. - S3[T3]
  346. - P1
  347. s2[T2]
  348. """)
  349. self.check(map, dst, do_map=False)
  350. src['s1'].properties['p2'].mapping = 'map#T2:P1'
  351. dst = parse("""
  352. s1[t1]
  353. s2[T2]
  354. - P1
  355. """)
  356. self.check(map, dst, do_map=False)
  357. with self.assertRaises(mapping.MappingError):
  358. src['s2'].mapping = 'map#T3'
  359. src['s1'].properties['p2'].mapping = ''
  360. dst = parse("""
  361. s1[t1]
  362. - p2
  363. s2[T2]
  364. """)
  365. self.check(map, dst, do_map=False)
  366. src['s1'].mapping = 'map#T1'
  367. # this currently changes the order of the sections in the mapping
  368. # however the resulting document should still be fine
  369. dst = parse("""
  370. s2[T2]
  371. s1[T1]
  372. - p2
  373. """)
  374. self.check(map, dst, do_map=False) # see above if this fails
  375. if __name__ == '__main__':
  376. unittest.main()