test_graph.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. import pytest
  2. from shutil import rmtree
  3. from rdflib import Graph, Namespace, URIRef
  4. from lakesuperior.model.graph.graph import SimpleGraph, Imr
  5. from lakesuperior.store.ldp_rs.lmdb_store import LmdbStore
  6. @pytest.fixture(scope='class')
  7. def store():
  8. """
  9. Test LMDB store.
  10. This store has a different life cycle than the one used for tests in higher
  11. levels of the stack and is not bootstrapped (i.e. starts completely empty).
  12. """
  13. env_path = '/tmp/test_lmdbstore'
  14. # Remove previous test DBs
  15. rmtree(env_path, ignore_errors=True)
  16. store = LmdbStore(env_path)
  17. yield store
  18. store.close()
  19. store.destroy()
  20. @pytest.fixture(scope='class')
  21. def trp():
  22. return (
  23. (URIRef('urn:s:0'), URIRef('urn:p:0'), URIRef('urn:o:0')),
  24. # Exact same as [0].
  25. (URIRef('urn:s:0'), URIRef('urn:p:0'), URIRef('urn:o:0')),
  26. # NOTE: s and o are in reversed order.
  27. (URIRef('urn:o:0'), URIRef('urn:p:0'), URIRef('urn:s:0')),
  28. (URIRef('urn:s:0'), URIRef('urn:p:1'), URIRef('urn:o:0')),
  29. (URIRef('urn:s:0'), URIRef('urn:p:1'), URIRef('urn:o:1')),
  30. (URIRef('urn:s:1'), URIRef('urn:p:1'), URIRef('urn:o:1')),
  31. (URIRef('urn:s:1'), URIRef('urn:p:2'), URIRef('urn:o:2')),
  32. )
  33. @pytest.mark.usefixtures('trp')
  34. @pytest.mark.usefixtures('store')
  35. class TestGraphInit:
  36. """
  37. Test initialization of graphs with different base data sets.
  38. """
  39. def test_empty(self):
  40. """
  41. Test creation of an empty graph.
  42. """
  43. gr = SimpleGraph()
  44. assert len(gr) == 0
  45. def test_init_triples(self, trp):
  46. """
  47. Test creation using a Python set.
  48. """
  49. gr = SimpleGraph(data=set(trp))
  50. assert len(gr) == 6
  51. for t in trp:
  52. assert t in gr
  53. @pytest.mark.skip(reason='TODO')
  54. def test_init_keyset(self):
  55. """
  56. Test creation using a keyset.
  57. TODO
  58. """
  59. pass
  60. def test_init_lookup(self, trp, store):
  61. """
  62. Test creation by store lookup.
  63. """
  64. with store.txn_ctx(True):
  65. for t in trp:
  66. store.add(t)
  67. with store.txn_ctx():
  68. gr1 = SimpleGraph(store=store, lookup=((None, None, None)))
  69. assert len(gr1) == 6
  70. with store.txn_ctx():
  71. gr2 = SimpleGraph(store=store, lookup=((URIRef('urn:s:1'), None, None)))
  72. assert len(gr1) == 2
  73. @pytest.mark.usefixtures('trp')
  74. class TestGraphLookup:
  75. """
  76. Test triple lookup.
  77. TODO
  78. """
  79. @pytest.mark.skip(reason='TODO')
  80. def test_lookup_pattern(self, trp):
  81. """
  82. Test lookup by basic pattern.
  83. """
  84. pass
  85. @pytest.mark.usefixtures('trp')
  86. class TestGraphOps:
  87. """
  88. Test various graph operations.
  89. """
  90. def test_len(self, trp):
  91. """
  92. Test the length of a graph with and without duplicates.
  93. """
  94. gr = SimpleGraph()
  95. assert len(gr) == 0
  96. gr.add((trp[0],))
  97. assert len(gr) == 1
  98. gr.add((trp[1],)) # Same values
  99. assert len(gr) == 1
  100. gr.add((trp[2],))
  101. assert len(gr) == 2
  102. gr.add(trp)
  103. assert len(gr) == 6
  104. def test_dup(self, trp):
  105. """
  106. Test operations with duplicate triples.
  107. """
  108. gr = SimpleGraph()
  109. #import pdb; pdb.set_trace()
  110. gr.add((trp[0],))
  111. assert trp[1] in gr
  112. assert trp[2] not in gr
  113. def test_remove(self, trp):
  114. """
  115. Test adding and removing triples.
  116. """
  117. gr = SimpleGraph()
  118. gr.add(trp)
  119. gr.remove(trp[0])
  120. assert len(gr) == 5
  121. assert trp[0] not in gr
  122. assert trp[1] not in gr
  123. # This is the duplicate triple.
  124. gr.remove(trp[1])
  125. assert len(gr) == 5
  126. # This is the triple in reverse order.
  127. gr.remove(trp[2])
  128. assert len(gr) == 4
  129. gr.remove(trp[4])
  130. assert len(gr) == 3
  131. def test_union(self, trp):
  132. """
  133. Test graph union.
  134. """
  135. gr1 = SimpleGraph()
  136. gr2 = SimpleGraph()
  137. gr1.add(trp[0:3])
  138. gr2.add(trp[2:6])
  139. gr3 = gr1 | gr2
  140. assert len(gr3) == 5
  141. assert trp[0] in gr3
  142. assert trp[4] in gr3
  143. def test_ip_union(self, trp):
  144. """
  145. Test graph in-place union.
  146. """
  147. gr1 = SimpleGraph()
  148. gr2 = SimpleGraph()
  149. gr1.add(trp[0:3])
  150. gr2.add(trp[2:6])
  151. gr1 |= gr2
  152. assert len(gr1) == 5
  153. assert trp[0] in gr1
  154. assert trp[4] in gr1
  155. def test_addition(self, trp):
  156. """
  157. Test graph addition.
  158. """
  159. gr1 = SimpleGraph()
  160. gr2 = SimpleGraph()
  161. gr1.add(trp[0:3])
  162. gr2.add(trp[2:6])
  163. gr3 = gr1 + gr2
  164. assert len(gr3) == 5
  165. assert trp[0] in gr3
  166. assert trp[4] in gr3
  167. def test_ip_addition(self, trp):
  168. """
  169. Test graph in-place addition.
  170. """
  171. gr1 = SimpleGraph()
  172. gr2 = SimpleGraph()
  173. gr1.add(trp[0:3])
  174. gr2.add(trp[2:6])
  175. gr1 += gr2
  176. assert len(gr1) == 5
  177. assert trp[0] in gr1
  178. assert trp[4] in gr1
  179. def test_subtraction(self, trp):
  180. """
  181. Test graph addition.
  182. """
  183. gr1 = SimpleGraph()
  184. gr2 = SimpleGraph()
  185. gr1.add(trp[0:4])
  186. gr2.add(trp[2:6])
  187. gr3 = gr1 - gr2
  188. assert len(gr3) == 1
  189. assert trp[0] in gr3
  190. assert trp[1] in gr3
  191. assert trp[2] not in gr3
  192. assert trp[3] not in gr3
  193. assert trp[4] not in gr3
  194. gr3 = gr2 - gr1
  195. assert len(gr3) == 2
  196. assert trp[0] not in gr3
  197. assert trp[1] not in gr3
  198. assert trp[2] not in gr3
  199. assert trp[3] not in gr3
  200. assert trp[4] in gr3
  201. assert trp[5] in gr3
  202. def test_ip_subtraction(self, trp):
  203. """
  204. Test graph in-place addition.
  205. """
  206. gr1 = SimpleGraph()
  207. gr2 = SimpleGraph()
  208. gr1.add(trp[0:4])
  209. gr2.add(trp[2:6])
  210. gr1 -= gr2
  211. assert len(gr1) == 1
  212. assert trp[0] in gr1
  213. assert trp[1] in gr1
  214. assert trp[2] not in gr1
  215. assert trp[3] not in gr1
  216. assert trp[4] not in gr1
  217. def test_intersect(self, trp):
  218. """
  219. Test graph intersextion.
  220. """
  221. gr1 = SimpleGraph()
  222. gr2 = SimpleGraph()
  223. gr1.add(trp[0:4])
  224. gr2.add(trp[2:6])
  225. gr3 = gr1 & gr2
  226. assert len(gr3) == 2
  227. assert trp[2] in gr3
  228. assert trp[3] in gr3
  229. assert trp[0] not in gr3
  230. assert trp[5] not in gr3
  231. def test_ip_intersect(self, trp):
  232. """
  233. Test graph intersextion.
  234. """
  235. gr1 = SimpleGraph()
  236. gr2 = SimpleGraph()
  237. gr1.add(trp[0:4])
  238. gr2.add(trp[2:6])
  239. gr1 &= gr2
  240. assert len(gr1) == 2
  241. assert trp[2] in gr1
  242. assert trp[3] in gr1
  243. assert trp[0] not in gr1
  244. assert trp[5] not in gr1
  245. def test_xor(self, trp):
  246. """
  247. Test graph intersextion.
  248. """
  249. gr1 = SimpleGraph()
  250. gr2 = SimpleGraph()
  251. gr1.add(trp[0:4])
  252. gr2.add(trp[2:6])
  253. gr3 = gr1 ^ gr2
  254. assert len(gr3) == 3
  255. assert trp[2] not in gr3
  256. assert trp[3] not in gr3
  257. assert trp[0] in gr3
  258. assert trp[5] in gr3
  259. def test_ip_xor(self, trp):
  260. """
  261. Test graph intersextion.
  262. """
  263. gr1 = SimpleGraph()
  264. gr2 = SimpleGraph()
  265. gr1.add(trp[0:4])
  266. gr2.add(trp[2:6])
  267. gr1 ^= gr2
  268. assert len(gr1) == 3
  269. assert trp[2] not in gr1
  270. assert trp[3] not in gr1
  271. assert trp[0] in gr1
  272. assert trp[5] in gr1
  273. @pytest.mark.usefixtures('trp')
  274. class TestImrOps:
  275. """
  276. Test various graph operations.
  277. """
  278. def test_len(self, trp):
  279. """
  280. Test the length of a graph with and without duplicates.
  281. """
  282. imr = Imr(uri='http://example.edu/imr01')
  283. assert len(imr) == 0
  284. imr.add((trp[0],))
  285. assert len(imr) == 1
  286. imr.add((trp[1],)) # Same values
  287. assert len(imr) == 1
  288. imr.add((trp[2],))
  289. assert len(imr) == 2
  290. imr.add(trp)
  291. assert len(imr) == 6
  292. def test_dup(self, trp):
  293. """
  294. Test operations with duplicate triples.
  295. """
  296. imr = Imr(uri='http://example.edu/imr01')
  297. #import pdb; pdb.set_trace()
  298. imr.add((trp[0],))
  299. assert trp[1] in imr
  300. assert trp[2] not in imr
  301. def test_remove(self, trp):
  302. """
  303. Test adding and removing triples.
  304. """
  305. imr = Imr(uri='http://example.edu/imr01')
  306. imr.add(trp)
  307. imr.remove(trp[0])
  308. assert len(imr) == 5
  309. assert trp[0] not in imr
  310. assert trp[1] not in imr
  311. # This is the duplicate triple.
  312. imr.remove(trp[1])
  313. assert len(imr) == 5
  314. # This is the triple in reverse order.
  315. imr.remove(trp[2])
  316. assert len(imr) == 4
  317. imr.remove(trp[4])
  318. assert len(imr) == 3
  319. def test_union(self, trp):
  320. """
  321. Test graph union.
  322. """
  323. gr1 = Imr(uri='http://example.edu/imr01')
  324. gr2 = Imr(uri='http://example.edu/imr02')
  325. gr1.add(trp[0:3])
  326. gr2.add(trp[2:6])
  327. gr3 = gr1 | gr2
  328. assert len(gr3) == 5
  329. assert trp[0] in gr3
  330. assert trp[4] in gr3
  331. assert gr3.uri == 'http://example.edu/imr01'
  332. def test_ip_union(self, trp):
  333. """
  334. Test graph in-place union.
  335. """
  336. gr1 = Imr(uri='http://example.edu/imr01')
  337. gr2 = Imr(uri='http://example.edu/imr02')
  338. gr1.add(trp[0:3])
  339. gr2.add(trp[2:6])
  340. gr1 |= gr2
  341. assert len(gr1) == 5
  342. assert trp[0] in gr1
  343. assert trp[4] in gr1
  344. assert gr1.uri == 'http://example.edu/imr01'
  345. def test_addition(self, trp):
  346. """
  347. Test graph addition.
  348. """
  349. gr1 = Imr(uri='http://example.edu/imr01')
  350. gr2 = Imr(uri='http://example.edu/imr02')
  351. gr1.add(trp[0:3])
  352. gr2.add(trp[2:6])
  353. gr3 = gr1 + gr2
  354. assert len(gr3) == 5
  355. assert trp[0] in gr3
  356. assert trp[4] in gr3
  357. assert gr3.uri == 'http://example.edu/imr01'
  358. def test_ip_addition(self, trp):
  359. """
  360. Test graph in-place addition.
  361. """
  362. gr1 = Imr(uri='http://example.edu/imr01')
  363. gr2 = Imr(uri='http://example.edu/imr02')
  364. gr1.add(trp[0:3])
  365. gr2.add(trp[2:6])
  366. gr1 += gr2
  367. assert len(gr1) == 5
  368. assert trp[0] in gr1
  369. assert trp[4] in gr1
  370. assert gr1.uri == 'http://example.edu/imr01'
  371. def test_subtraction(self, trp):
  372. """
  373. Test graph addition.
  374. """
  375. gr1 = Imr(uri='http://example.edu/imr01')
  376. gr2 = Imr(uri='http://example.edu/imr02')
  377. gr1.add(trp[0:4])
  378. gr2.add(trp[2:6])
  379. gr3 = gr1 - gr2
  380. assert len(gr3) == 1
  381. assert trp[0] in gr3
  382. assert trp[1] in gr3
  383. assert trp[2] not in gr3
  384. assert trp[3] not in gr3
  385. assert trp[4] not in gr3
  386. assert gr3.uri == 'http://example.edu/imr01'
  387. gr3 = gr2 - gr1
  388. assert len(gr3) == 2
  389. assert trp[0] not in gr3
  390. assert trp[1] not in gr3
  391. assert trp[2] not in gr3
  392. assert trp[3] not in gr3
  393. assert trp[4] in gr3
  394. assert trp[5] in gr3
  395. assert gr3.uri == 'http://example.edu/imr02'
  396. def test_ip_subtraction(self, trp):
  397. """
  398. Test graph in-place addition.
  399. """
  400. gr1 = Imr(uri='http://example.edu/imr01')
  401. gr2 = Imr(uri='http://example.edu/imr02')
  402. gr1.add(trp[0:4])
  403. gr2.add(trp[2:6])
  404. gr1 -= gr2
  405. assert len(gr1) == 1
  406. assert trp[0] in gr1
  407. assert trp[1] in gr1
  408. assert trp[2] not in gr1
  409. assert trp[3] not in gr1
  410. assert trp[4] not in gr1
  411. assert gr1.uri == 'http://example.edu/imr01'
  412. def test_intersect(self, trp):
  413. """
  414. Test graph intersextion.
  415. """
  416. gr1 = Imr(uri='http://example.edu/imr01')
  417. gr2 = Imr(uri='http://example.edu/imr02')
  418. gr1.add(trp[0:4])
  419. gr2.add(trp[2:6])
  420. gr3 = gr1 & gr2
  421. assert len(gr3) == 2
  422. assert trp[2] in gr3
  423. assert trp[3] in gr3
  424. assert trp[0] not in gr3
  425. assert trp[5] not in gr3
  426. assert gr3.uri == 'http://example.edu/imr01'
  427. def test_ip_intersect(self, trp):
  428. """
  429. Test graph intersextion.
  430. """
  431. gr1 = Imr(uri='http://example.edu/imr01')
  432. gr2 = Imr(uri='http://example.edu/imr02')
  433. gr1.add(trp[0:4])
  434. gr2.add(trp[2:6])
  435. gr1 &= gr2
  436. assert len(gr1) == 2
  437. assert trp[2] in gr1
  438. assert trp[3] in gr1
  439. assert trp[0] not in gr1
  440. assert trp[5] not in gr1
  441. assert gr1.uri == 'http://example.edu/imr01'
  442. def test_xor(self, trp):
  443. """
  444. Test graph intersextion.
  445. """
  446. gr1 = Imr(uri='http://example.edu/imr01')
  447. gr2 = Imr(uri='http://example.edu/imr02')
  448. gr1.add(trp[0:4])
  449. gr2.add(trp[2:6])
  450. gr3 = gr1 ^ gr2
  451. assert len(gr3) == 3
  452. assert trp[2] not in gr3
  453. assert trp[3] not in gr3
  454. assert trp[0] in gr3
  455. assert trp[5] in gr3
  456. assert gr3.uri == 'http://example.edu/imr01'
  457. def test_ip_xor(self, trp):
  458. """
  459. Test graph intersextion.
  460. """
  461. gr1 = Imr(uri='http://example.edu/imr01')
  462. gr2 = Imr(uri='http://example.edu/imr02')
  463. gr1.add(trp[0:4])
  464. gr2.add(trp[2:6])
  465. gr1 ^= gr2
  466. assert len(gr1) == 3
  467. assert trp[2] not in gr1
  468. assert trp[3] not in gr1
  469. assert trp[0] in gr1
  470. assert trp[5] in gr1
  471. assert gr1.uri == 'http://example.edu/imr01'
  472. @pytest.mark.usefixtures('trp')
  473. class TestHybridOps:
  474. """
  475. Test operations between IMR and graph.
  476. """
  477. def test_union(self, trp):
  478. """
  479. Test hybrid IMR + graph union.
  480. """
  481. gr1 = Imr(uri='http://example.edu/imr01')
  482. gr2 = SimpleGraph()
  483. gr1.add(trp[0:3])
  484. gr2.add(trp[2:6])
  485. gr3 = gr1 | gr2
  486. assert len(gr3) == 5
  487. assert trp[0] in gr3
  488. assert trp[4] in gr3
  489. assert isinstance(gr3, Imr)
  490. assert gr3.uri == 'http://example.edu/imr01'
  491. gr4 = gr2 | gr1
  492. assert isinstance(gr4, SimpleGraph)
  493. assert gr3 == gr4
  494. def test_ip_union_imr(self, trp):
  495. """
  496. Test IMR + graph in-place union.
  497. """
  498. gr1 = Imr(uri='http://example.edu/imr01')
  499. gr2 = SimpleGraph()
  500. gr1.add(trp[0:3])
  501. gr2.add(trp[2:6])
  502. gr1 |= gr2
  503. assert len(gr1) == 5
  504. assert trp[0] in gr1
  505. assert trp[4] in gr1
  506. assert gr1.uri == 'http://example.edu/imr01'
  507. def test_ip_union_gr(self, trp):
  508. """
  509. Test graph + IMR in-place union.
  510. """
  511. gr1 = SimpleGraph()
  512. gr2 = Imr(uri='http://example.edu/imr01')
  513. gr1.add(trp[0:3])
  514. gr2.add(trp[2:6])
  515. gr1 |= gr2
  516. assert len(gr1) == 5
  517. assert trp[0] in gr1
  518. assert trp[4] in gr1
  519. assert isinstance(gr1, SimpleGraph)