LinkDBTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. <?php
  2. /**
  3. * Link datastore tests
  4. */
  5. require_once 'application/LinkDB.php';
  6. require_once 'application/Utils.php';
  7. require_once 'tests/utils/ReferenceLinkDB.php';
  8. define('PHPPREFIX', '<?php /* ');
  9. define('PHPSUFFIX', ' */ ?>');
  10. /**
  11. * Unitary tests for LinkDB
  12. */
  13. class LinkDBTest extends PHPUnit_Framework_TestCase
  14. {
  15. // datastore to test write operations
  16. protected static $testDatastore = 'tests/datastore.php';
  17. protected static $dummyDatastoreSHA1 = 'e3edea8ea7bb50be4bcb404df53fbb4546a7156e';
  18. protected static $refDB = null;
  19. protected static $publicLinkDB = null;
  20. protected static $privateLinkDB = null;
  21. /**
  22. * Instantiates public and private LinkDBs with test data
  23. *
  24. * The reference datastore contains public and private links that
  25. * will be used to test LinkDB's methods:
  26. * - access filtering (public/private),
  27. * - link searches:
  28. * - by day,
  29. * - by tag,
  30. * - by text,
  31. * - etc.
  32. */
  33. public static function setUpBeforeClass()
  34. {
  35. self::$refDB = new ReferenceLinkDB();
  36. self::$refDB->write(self::$testDatastore, PHPPREFIX, PHPSUFFIX);
  37. $GLOBALS['config']['DATASTORE'] = self::$testDatastore;
  38. self::$publicLinkDB = new LinkDB(false);
  39. self::$privateLinkDB = new LinkDB(true);
  40. }
  41. /**
  42. * Resets test data for each test
  43. */
  44. protected function setUp()
  45. {
  46. $GLOBALS['config']['DATASTORE'] = self::$testDatastore;
  47. if (file_exists(self::$testDatastore)) {
  48. unlink(self::$testDatastore);
  49. }
  50. }
  51. /**
  52. * Allows to test LinkDB's private methods
  53. *
  54. * @see
  55. * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
  56. * http://stackoverflow.com/a/2798203
  57. */
  58. protected static function getMethod($name)
  59. {
  60. $class = new ReflectionClass('LinkDB');
  61. $method = $class->getMethod($name);
  62. $method->setAccessible(true);
  63. return $method;
  64. }
  65. /**
  66. * Instantiate LinkDB objects - logged in user
  67. */
  68. public function testConstructLoggedIn()
  69. {
  70. new LinkDB(true);
  71. $this->assertFileExists(self::$testDatastore);
  72. }
  73. /**
  74. * Instantiate LinkDB objects - logged out or public instance
  75. */
  76. public function testConstructLoggedOut()
  77. {
  78. new LinkDB(false);
  79. $this->assertFileExists(self::$testDatastore);
  80. }
  81. /**
  82. * Attempt to instantiate a LinkDB whereas the datastore is not writable
  83. *
  84. * @expectedException PHPUnit_Framework_Error_Warning
  85. * @expectedExceptionMessageRegExp /failed to open stream: No such file or directory/
  86. */
  87. public function testConstructDatastoreNotWriteable()
  88. {
  89. $GLOBALS['config']['DATASTORE'] = 'null/store.db';
  90. new LinkDB(false);
  91. }
  92. /**
  93. * The DB doesn't exist, ensure it is created with dummy content
  94. */
  95. public function testCheckDBNew()
  96. {
  97. $linkDB = new LinkDB(false);
  98. unlink(self::$testDatastore);
  99. $this->assertFileNotExists(self::$testDatastore);
  100. $checkDB = self::getMethod('checkDB');
  101. $checkDB->invokeArgs($linkDB, array());
  102. $this->assertFileExists(self::$testDatastore);
  103. // ensure the correct data has been written
  104. $this->assertEquals(
  105. self::$dummyDatastoreSHA1,
  106. sha1_file(self::$testDatastore)
  107. );
  108. }
  109. /**
  110. * The DB exists, don't do anything
  111. */
  112. public function testCheckDBLoad()
  113. {
  114. $linkDB = new LinkDB(false);
  115. $this->assertEquals(
  116. self::$dummyDatastoreSHA1,
  117. sha1_file(self::$testDatastore)
  118. );
  119. $checkDB = self::getMethod('checkDB');
  120. $checkDB->invokeArgs($linkDB, array());
  121. // ensure the datastore is left unmodified
  122. $this->assertEquals(
  123. self::$dummyDatastoreSHA1,
  124. sha1_file(self::$testDatastore)
  125. );
  126. }
  127. /**
  128. * Load an empty DB
  129. */
  130. public function testReadEmptyDB()
  131. {
  132. file_put_contents(self::$testDatastore, PHPPREFIX.'S7QysKquBQA='.PHPSUFFIX);
  133. $emptyDB = new LinkDB(false);
  134. $this->assertEquals(0, sizeof($emptyDB));
  135. $this->assertEquals(0, count($emptyDB));
  136. }
  137. /**
  138. * Load public links from the DB
  139. */
  140. public function testReadPublicDB()
  141. {
  142. $this->assertEquals(
  143. self::$refDB->countPublicLinks(),
  144. sizeof(self::$publicLinkDB)
  145. );
  146. }
  147. /**
  148. * Load public and private links from the DB
  149. */
  150. public function testReadPrivateDB()
  151. {
  152. $this->assertEquals(
  153. self::$refDB->countLinks(),
  154. sizeof(self::$privateLinkDB)
  155. );
  156. }
  157. /**
  158. * Save the links to the DB
  159. */
  160. public function testSaveDB()
  161. {
  162. $testDB = new LinkDB(true);
  163. $dbSize = sizeof($testDB);
  164. $link = array(
  165. 'title'=>'an additional link',
  166. 'url'=>'http://dum.my',
  167. 'description'=>'One more',
  168. 'private'=>0,
  169. 'linkdate'=>'20150518_190000',
  170. 'tags'=>'unit test'
  171. );
  172. $testDB[$link['linkdate']] = $link;
  173. // TODO: move PageCache to a proper class/file
  174. function invalidateCaches() {}
  175. $testDB->savedb();
  176. $testDB = new LinkDB(true);
  177. $this->assertEquals($dbSize + 1, sizeof($testDB));
  178. }
  179. /**
  180. * Count existing links
  181. */
  182. public function testCount()
  183. {
  184. $this->assertEquals(
  185. self::$refDB->countPublicLinks(),
  186. self::$publicLinkDB->count()
  187. );
  188. $this->assertEquals(
  189. self::$refDB->countLinks(),
  190. self::$privateLinkDB->count()
  191. );
  192. }
  193. /**
  194. * List the days for which links have been posted
  195. */
  196. public function testDays()
  197. {
  198. $this->assertEquals(
  199. ['20121206', '20130614', '20150310'],
  200. self::$publicLinkDB->days()
  201. );
  202. $this->assertEquals(
  203. ['20121206', '20130614', '20141125', '20150310'],
  204. self::$privateLinkDB->days()
  205. );
  206. }
  207. /**
  208. * The URL corresponds to an existing entry in the DB
  209. */
  210. public function testGetKnownLinkFromURL()
  211. {
  212. $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
  213. $this->assertNotEquals(false, $link);
  214. $this->assertEquals(
  215. 'A free software media publishing platform',
  216. $link['description']
  217. );
  218. }
  219. /**
  220. * The URL is not in the DB
  221. */
  222. public function testGetUnknownLinkFromURL()
  223. {
  224. $this->assertEquals(
  225. false,
  226. self::$publicLinkDB->getLinkFromUrl('http://dev.null')
  227. );
  228. }
  229. /**
  230. * Lists all tags
  231. */
  232. public function testAllTags()
  233. {
  234. $this->assertEquals(
  235. [
  236. 'web' => 3,
  237. 'cartoon' => 2,
  238. 'gnu' => 2,
  239. 'dev' => 1,
  240. 'samba' => 1,
  241. 'media' => 1,
  242. 'software' => 1,
  243. 'stallman' => 1,
  244. 'free' => 1
  245. ],
  246. self::$publicLinkDB->allTags()
  247. );
  248. $this->assertEquals(
  249. [
  250. 'web' => 4,
  251. 'cartoon' => 3,
  252. 'gnu' => 2,
  253. 'dev' => 2,
  254. 'samba' => 1,
  255. 'media' => 1,
  256. 'software' => 1,
  257. 'stallman' => 1,
  258. 'free' => 1,
  259. 'html' => 1,
  260. 'w3c' => 1,
  261. 'css' => 1,
  262. 'Mercurial' => 1
  263. ],
  264. self::$privateLinkDB->allTags()
  265. );
  266. }
  267. /**
  268. * Filter links using a tag
  269. */
  270. public function testFilterOneTag()
  271. {
  272. $this->assertEquals(
  273. 3,
  274. sizeof(self::$publicLinkDB->filterTags('web', false))
  275. );
  276. $this->assertEquals(
  277. 4,
  278. sizeof(self::$privateLinkDB->filterTags('web', false))
  279. );
  280. }
  281. /**
  282. * Filter links using a tag - case-sensitive
  283. */
  284. public function testFilterCaseSensitiveTag()
  285. {
  286. $this->assertEquals(
  287. 0,
  288. sizeof(self::$privateLinkDB->filterTags('mercurial', true))
  289. );
  290. $this->assertEquals(
  291. 1,
  292. sizeof(self::$privateLinkDB->filterTags('Mercurial', true))
  293. );
  294. }
  295. /**
  296. * Filter links using a tag combination
  297. */
  298. public function testFilterMultipleTags()
  299. {
  300. $this->assertEquals(
  301. 1,
  302. sizeof(self::$publicLinkDB->filterTags('dev cartoon', false))
  303. );
  304. $this->assertEquals(
  305. 2,
  306. sizeof(self::$privateLinkDB->filterTags('dev cartoon', false))
  307. );
  308. }
  309. /**
  310. * Filter links using a non-existent tag
  311. */
  312. public function testFilterUnknownTag()
  313. {
  314. $this->assertEquals(
  315. 0,
  316. sizeof(self::$publicLinkDB->filterTags('null', false))
  317. );
  318. }
  319. /**
  320. * Return links for a given day
  321. */
  322. public function testFilterDay()
  323. {
  324. $this->assertEquals(
  325. 2,
  326. sizeof(self::$publicLinkDB->filterDay('20121206'))
  327. );
  328. $this->assertEquals(
  329. 3,
  330. sizeof(self::$privateLinkDB->filterDay('20121206'))
  331. );
  332. }
  333. /**
  334. * 404 - day not found
  335. */
  336. public function testFilterUnknownDay()
  337. {
  338. $this->assertEquals(
  339. 0,
  340. sizeof(self::$publicLinkDB->filterDay('19700101'))
  341. );
  342. $this->assertEquals(
  343. 0,
  344. sizeof(self::$privateLinkDB->filterDay('19700101'))
  345. );
  346. }
  347. /**
  348. * Use an invalid date format
  349. */
  350. public function testFilterInvalidDay()
  351. {
  352. $this->assertEquals(
  353. 0,
  354. sizeof(self::$privateLinkDB->filterDay('Rainy day, dream away'))
  355. );
  356. // TODO: check input format
  357. $this->assertEquals(
  358. 6,
  359. sizeof(self::$privateLinkDB->filterDay('20'))
  360. );
  361. }
  362. /**
  363. * Retrieve a link entry with its hash
  364. */
  365. public function testFilterSmallHash()
  366. {
  367. $links = self::$privateLinkDB->filterSmallHash('IuWvgA');
  368. $this->assertEquals(
  369. 1,
  370. sizeof($links)
  371. );
  372. $this->assertEquals(
  373. 'MediaGoblin',
  374. $links['20130614_184135']['title']
  375. );
  376. }
  377. /**
  378. * No link for this hash
  379. */
  380. public function testFilterUnknownSmallHash()
  381. {
  382. $this->assertEquals(
  383. 0,
  384. sizeof(self::$privateLinkDB->filterSmallHash('Iblaah'))
  385. );
  386. }
  387. /**
  388. * Full-text search - result from a link's URL
  389. */
  390. public function testFilterFullTextURL()
  391. {
  392. $this->assertEquals(
  393. 2,
  394. sizeof(self::$publicLinkDB->filterFullText('ars.userfriendly.org'))
  395. );
  396. }
  397. /**
  398. * Full-text search - result from a link's title only
  399. */
  400. public function testFilterFullTextTitle()
  401. {
  402. // use miscellaneous cases
  403. $this->assertEquals(
  404. 2,
  405. sizeof(self::$publicLinkDB->filterFullText('userfriendly -'))
  406. );
  407. $this->assertEquals(
  408. 2,
  409. sizeof(self::$publicLinkDB->filterFullText('UserFriendly -'))
  410. );
  411. $this->assertEquals(
  412. 2,
  413. sizeof(self::$publicLinkDB->filterFullText('uSeRFrIendlY -'))
  414. );
  415. // use miscellaneous case and offset
  416. $this->assertEquals(
  417. 2,
  418. sizeof(self::$publicLinkDB->filterFullText('RFrIendL'))
  419. );
  420. }
  421. /**
  422. * Full-text search - result from the link's description only
  423. */
  424. public function testFilterFullTextDescription()
  425. {
  426. $this->assertEquals(
  427. 1,
  428. sizeof(self::$publicLinkDB->filterFullText('media publishing'))
  429. );
  430. }
  431. /**
  432. * Full-text search - result from the link's tags only
  433. */
  434. public function testFilterFullTextTags()
  435. {
  436. $this->assertEquals(
  437. 2,
  438. sizeof(self::$publicLinkDB->filterFullText('gnu'))
  439. );
  440. }
  441. /**
  442. * Full-text search - result set from mixed sources
  443. */
  444. public function testFilterFullTextMixed()
  445. {
  446. $this->assertEquals(
  447. 2,
  448. sizeof(self::$publicLinkDB->filterFullText('free software'))
  449. );
  450. }
  451. }
  452. ?>