PageRenderTime 171ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/test/unit/sfLuceneTest.php

https://bitbucket.org/anycode/sfluceneplugin
PHP | 446 lines | 327 code | 106 blank | 13 comment | 12 complexity | 775809b30f3222823caa7174c2552d4d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of the sfLucenePlugin package
  4. * (c) 2007 - 2008 Carl Vondrick <carl@carlsoft.net>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * @package sfLucenePlugin
  11. * @subpackage Test
  12. * @author Carl Vondrick
  13. * @version SVN: $Id: sfLuceneTest.php 7108 2008-01-20 07:44:42Z Carl.Vondrick $
  14. */
  15. require dirname(__FILE__) . '/../bootstrap/unit.php';
  16. $t = new limeade_test(91, limeade_output::get());
  17. $limeade = new limeade_sf($t);
  18. $app = $limeade->bootstrap();
  19. $luceneade = new limeade_lucene($limeade);
  20. $luceneade->configure()->clear_sandbox();
  21. $t->diag('testing ::getInstance()');
  22. $t->ok(!is_dir(sfConfig::get('sf_data_dir') . '/index/testLucene/en'), 'Lucene directory does not initially exist');
  23. try {
  24. $e = $t->no_exception('::getInstance() allows valid cultures');
  25. $lucene = sfLucene::getInstance('testLucene','en');
  26. $e->no();
  27. } catch (Exception $ex) {
  28. $e->caught($ex);
  29. }
  30. $t->ok(is_dir(sfConfig::get('sf_data_dir') . '/index/testLucene/en'), '::getInstance() creates the index');
  31. $stat = stat(sfConfig::get('sf_data_dir') . '/index/testLucene/en/segments.gen');
  32. $lucene->unlatch();
  33. unset($lucene);
  34. try {
  35. $lucene = sfLucene::getInstance('testLucene', 'en');
  36. clearstatcache();
  37. $t->is_deeply(stat(sfConfig::get('sf_data_dir') . '/index/testLucene/en/segments.gen'), $stat, '::getInstance() again opens the index');
  38. } catch (Exception $e) {
  39. $t->skip('::getInstance() agains opens the index');
  40. }
  41. try {
  42. $e = $t->exception('::getInstance() rejects invalid cultures');
  43. sfLucene::getInstance('testLucene', 'piglatin');
  44. $e->no();
  45. } catch (Exception $ex) {
  46. $e->caught($ex);
  47. }
  48. try {
  49. $e = $t->exception('::getInstance() rejects invalid names');
  50. sfLucene::getInstance('badname', 'en');
  51. $e->no();
  52. } catch (Exception $ex) {
  53. $e->caught($ex);
  54. }
  55. try {
  56. sfLucene::getInstance('testLucene', 'en', true);
  57. $t->fail('::getInstance() fails to rebuild index if index is already open');
  58. } catch (Exception $e) {
  59. $t->pass('::getInstance() fails to rebuild index if index is already open');
  60. }
  61. try {
  62. $e = $t->no_exception('::getInstance() allows to rebuild index if closed');
  63. $new = sfLucene::getInstance('testLucene', 'fr', true);
  64. $e->no();
  65. } catch (Exception $ex) {
  66. $e->caught($ex);
  67. }
  68. try {
  69. sfContext::getInstance()->getUser()->setCulture('en');
  70. $t->is(sfLucene::getInstance('testLucene')->getParameter('culture'), 'en', '::getInstance() can guess the culture');
  71. } catch (Exception $e) {
  72. $t->fail('::getInstance() can guess the culture');
  73. }
  74. if ($new) {
  75. $t->ok($new->getParameter('is_new'), 'property "is_new" is true on a new index');
  76. $t->is($new->numDocs(), 0, '->numDocs() indicates index is empty');
  77. } else {
  78. $t->skip('index has new status new status on new index');
  79. $t->skip('->numDocs() indicates index is empty');
  80. }
  81. $t->diag('testing ::getAllInstances()');
  82. try {
  83. $t->no_exception('::getAllInstance() executes without exception');
  84. $instances = sfLucene::getAllInstances();
  85. $e->no();
  86. } catch (Exception $ex) {
  87. $instances = array();
  88. $e->caught($ex);
  89. }
  90. $t->is_deeply($instances, array(sfLucene::getInstance('testLucene','en'), sfLucene::getInstance('testLucene','fr'), sfLucene::getInstance('fooLucene','en')), '::getAllInstances() returns all instances');
  91. $t->is_deeply(sfLucene::getAllNames(), array('testLucene', 'fooLucene'), '::getAllNames() returns all configured names');
  92. $t->diag('testing ->loadConfig()');
  93. $h = $lucene->getParameterHolder();
  94. $t->isa_ok($h, 'sfParameterHolder', '->getParameterHolder() returns a parameter holder');
  95. $t->is($h->get('name'), 'testLucene', 'property "name" is the name of the index');
  96. $t->is($h->get('culture'), 'en', 'property "culture" is the culture of the index');
  97. $t->is($h->get('enabled_cultures'), array('en', 'fr'), 'property "enabled_cultures" contains all enabled cultures');
  98. $t->like($h->get('index_location'), '#/index/testLucene/en$#', 'property "index_location" is the correct path');
  99. $t->is($h->get('encoding'), 'UTF-8', 'property "encoding" is the encoding');
  100. $t->is($h->get('stop_words'), array('and', 'the'), 'property "stop_words" contains the stop words');
  101. $t->is($h->get('short_words'), 2, 'property "short_words" is the short word limit');
  102. $t->is($h->get('mb_string'), true, 'property "mb_string" indicates if to use mb_string functions');
  103. $t->isa_ok($h->get('models'), 'sfParameterHolder', 'property "models" is a sfParameterHolder');
  104. $t->isa_ok($h->get('models')->get('FakeForum'), 'sfParameterHolder', 'properties of "models" are sfParameterHolders');
  105. $m = $h->get('models')->get('FakeForum');
  106. $t->is($m->get('title'), 'title', 'model property "title" is the correct title field');
  107. $t->is($m->get('description'), 'description', 'model property "description" is the correct description field');
  108. $t->is($m->get('categories'), array('Forum'), 'model property "categories" contains the correct categories');
  109. $t->is($m->get('route'), 'forum/showForum?id=%id%', 'model property "route" is the correct route');
  110. $t->is($m->get('validator'), 'isIndexable', 'model property "validator" is the correct validator');
  111. $t->is($m->get('peer'), 'FakeForumPeer', 'model property "peer" is the correct peer');
  112. $t->is($m->get('rebuild_limit'), 5, 'model property "rebuild_limit" is the correct rebuild limit');
  113. $t->is($m->get('partial'), 'forumResult', 'model property "partial" is the correct partial');
  114. $f = $m->get('fields');
  115. $t->isa_ok($f, 'sfParameterHolder', 'model property "fields" is a sfParameterHolder');
  116. $t->is($f->getNames(), array('id','title','description'), 'model property "fields" contains all the fields');
  117. $t->is($f->get('id')->get('type'), 'unindexed', 'field property "type" is the type');
  118. $t->is($f->get('id')->get('boost'), 1, 'field property "boost" is the boost');
  119. $t->diag('testing ::getConfig()');
  120. $cswap = $app->cswap($luceneade->config_dir . '/search.yml')->write('<?php $foo = 42;');
  121. try {
  122. $e = $t->exception('::getConfig() fails if search.yml is corrupt');
  123. sfLucene::getConfig();
  124. $e->no();
  125. } catch (Exception $ex) {
  126. $e->caught($ex);
  127. }
  128. $cswap->write('<?php $config = array(1, 2, 3);');
  129. try {
  130. $t->is(sfLucene::getConfig(), array(1, 2, 3), '::getConfig() returns the $config variable in the search.yml file');
  131. } catch (Exception $e) {
  132. $t->fail('::getConfig() returns the $config variable in the search.yml file');
  133. }
  134. $cswap->restore();
  135. $t->diag('testing ->getCategoriesHarness()');
  136. $cats = $lucene->getCategoriesHarness();
  137. $t->isa_ok($cats, 'sfLuceneCategories', '->getCategories() returns an instance of sfLuceneCategories');
  138. $t->ok($lucene->getCategoriesHarness() === $cats, '->getCategories() is a singleton');
  139. $t->diag('testing ->getIndexerFactory()');
  140. $indexer = $lucene->getIndexerFactory();
  141. $t->isa_ok($indexer, 'sfLuceneIndexerFactory', '->getIndexer() returns an instance of sfLuceneIndexerFactory');
  142. $t->diag('testing ->getContext()');
  143. $t->isa_ok($lucene->getContext(), 'sfContext', '->getContext() returns an instance of sfContext');
  144. $t->is($lucene->getContext(), sfContext::getInstance(), '->getContext() returns the same context');
  145. $t->diag('testing ->configure()');
  146. $lucene->configure();
  147. $t->is(Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding(), 'UTF-8', '->configure() configures the query parsers encoding');
  148. foreach (array('Text', 'TextNum', 'Utf8', 'Utf8Num') as $type)
  149. {
  150. $lucene->setParameter('analyzer', $type);
  151. $lucene->configure();
  152. $class = 'Zend_Search_Lucene_Analysis_Analyzer_Common_' . $type;
  153. $expected = new $class();
  154. $expected->addFilter(new sfLuceneLowerCaseFilter(true));
  155. $expected->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_StopWords(array('and', 'the')));
  156. $expected->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_ShortWords(2));
  157. $actual = Zend_Search_Lucene_Analysis_Analyzer::getDefault();
  158. $t->ok($actual == $expected, '->configure() configures the analyzer for ' . $type);
  159. }
  160. $lucene->setParameter('analyzer', 'foobar');
  161. try {
  162. $lucene->configure();
  163. $t->fail('->configure() analyzer must be of text, textnum, utf8, or utf8num');
  164. } catch (Exception $e) {
  165. $t->pass('->configure() analyzer must be of text, textnum, utf8, or utf8num');
  166. }
  167. $lucene->setParameter('analyzer', 'utf8num');
  168. $t->diag('testing ->find()');
  169. class MockLucene
  170. {
  171. public $args;
  172. public $scoring;
  173. public $e = false;
  174. public function find()
  175. {
  176. if ($this->e) throw new Exception('Because you said so');
  177. $this->args = func_get_args();
  178. $this->scoring = Zend_Search_Lucene_Search_Similarity::getDefault();
  179. return range(1, 100);
  180. }
  181. }
  182. class MockScoring extends Zend_Search_Lucene_Search_Similarity_Default {}
  183. $mock = new MockLucene;
  184. $originalLucene = $lucene->getLucene();
  185. $lucene->forceLucene($mock);
  186. $t->is($lucene->find('foo'), range(1, 100), '->find() returns what ZSL returns');
  187. $t->ok(sfLuceneCriteria::newInstance($lucene)->add('foo')->getQuery() == $mock->args[0], '->find() parses string queries');
  188. $t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() with a string uses default scoring algorithm');
  189. $query = sfLuceneCriteria::newInstance($lucene)->add('foo')->addRange('a', 'b', 'c');
  190. $lucene->find($query);
  191. $t->ok($query->getQuery() == $mock->args[0], '->find() accepts sfLuceneCriteria queries');
  192. $t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() without specified scorer uses default scoring algorithm');
  193. $query = new Zend_Search_Lucene_Search_Query_Boolean();
  194. $lucene->find($query);
  195. $t->ok($query == $mock->args[0], '->find() accepts Zend API queries');
  196. $t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() with a Zend API queries uses default scoring algorithm');
  197. $scoring = new MockScoring;
  198. $lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->setScoringAlgorithm($scoring));
  199. $t->is($mock->scoring, $scoring, '->find() changes the scoring algorithm if sfLuceneCriteria specifies it');
  200. $t->isa_ok(Zend_Search_Lucene_Search_Similarity::getDefault(), 'Zend_Search_Lucene_Search_Similarity_Default', '->find() resets the default scoring algorithm after processing');
  201. $lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->addAscendingSortBy('sort1')->addDescendingSortBy('sort2', SORT_NUMERIC));
  202. $t->is_deeply(array_splice($mock->args, 1), array('sort1', SORT_REGULAR, SORT_ASC, 'sort2', SORT_NUMERIC, SORT_DESC), '->find() uses sorting rules from sfLuceneCriteria');
  203. $results = $lucene->friendlyFind('foo');
  204. $t->isa_ok($results, 'sfLuceneResults', '->friendlyFind() returns an instance of sfLuceneResults');
  205. $t->is($results->toArray(), range(1, 100), '->friendlyFind() houses the data from ZSL');
  206. $t->is($results->getSearch(), $lucene, '->friendlyFind() is connected to the Lucene instance');
  207. $mock->e = true;
  208. try {
  209. $lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->setScoringAlgorithm(new MockScoring));
  210. $t->fail('if ZSL throws exception, ->find() also throws the exception');
  211. $t->skip('if ZSL throws exception, ->find() stills resets the scoring algorithm');
  212. } catch (Exception $e) {
  213. $t->pass('if ZSL throws exception, ->find() also throws the exception');
  214. $t->isa_ok(Zend_Search_Lucene_Search_Similarity::getDefault(), 'Zend_Search_Lucene_Search_Similarity_Default', 'if ZSL throws exception, ->find() stills resets the scoring algorithm');
  215. }
  216. $lucene->forceLucene($originalLucene);
  217. $t->diag('testing ->rebuildIndex()');
  218. class MockIndexerFactory
  219. {
  220. public $handlers, $deleteLock = false, $search;
  221. public function __construct($h, $s)
  222. {
  223. $this->handlers = $h;
  224. $this->search = $s;
  225. }
  226. public function getHandlers()
  227. {
  228. $this->deleteLock = $this->search->getParameter('delete_lock');
  229. return $this->handlers;
  230. }
  231. }
  232. class MockIndexerHandler
  233. {
  234. public $count = 0;
  235. public function rebuild()
  236. {
  237. $this->count++;
  238. }
  239. }
  240. $handlers = array(new MockIndexerHandler, new MockIndexerHandler);
  241. $factory = new MockIndexerFactory($handlers, $lucene);
  242. $originalFactory = $lucene->getIndexerFactory();
  243. $lucene->forceIndexerFactory($factory);
  244. $lucene->getCategoriesHarness()->getCategory('foo');
  245. $lucene->getCategoriesHarness()->save();
  246. $lucene->rebuildIndex();
  247. $t->is($factory->deleteLock, true, '->rebuildIndex() enables the delete lock');
  248. $t->ok($handlers[0]->count == 1 && $handlers[0]->count == 1, '->rebuildIndex() calls each handler\'s ->rebuild() only once');
  249. $t->is($lucene->getCategoriesHarness()->getAllCategories(), array(), '->rebuildIndex() clears the category list');
  250. $lucene->forceIndexerFactory($originalFactory);
  251. $t->diag('testing wrappers');
  252. try {
  253. $lucene->optimize();
  254. $t->pass('->optimize() optimizes the index without exception');
  255. } catch (Exception $e) {
  256. $t->fail('->optimize() optimizes the index without exception');
  257. }
  258. try {
  259. $t->is($lucene->count(), 0, '->count() returns the document count');
  260. $t->pass('->count() counts the index without exception');
  261. } catch (Exception $e) {
  262. $t->skip('->count() returns the document count');
  263. $t->fail('->count() counts the index without exception');
  264. }
  265. try {
  266. $t->is($lucene->numDocs(), 0, '->numDocs() returns the document count');
  267. $t->pass('->numDocs() counts the index without exception');
  268. } catch (Exception $e) {
  269. $t->skip('->numDocs() returns the document count');
  270. $t->fail('->numDocs() counts the index without exception');
  271. }
  272. try {
  273. $lucene->commit();
  274. $t->pass('->commit() commits the index without exception');
  275. } catch (Exception $e) {
  276. $t->fail('->commit() commits the index without exception');
  277. }
  278. $t->diag('testing statistics');
  279. $originalLocation = $lucene->getParameter('index_location');
  280. $lucene->setParameter('index_location', $luceneade->data_dir . '/foo');
  281. $t->is($lucene->byteSize(), 8222, '->byteSize() returns the correct size in bytes');
  282. $t->is($lucene->segmentCount(), 2, '->segmentCount() returns the correct segment count');
  283. $lucene->setParameter('index_location', $originalLocation);
  284. $t->diag('testing modes');
  285. class FooController
  286. {
  287. public $cli = true;
  288. public function inCLI()
  289. {
  290. return $this->cli;
  291. }
  292. }
  293. $controller = new FooController();
  294. $oldController = sfContext::getInstance()->get('controller');
  295. sfContext::getInstance()->set('controller', $controller);
  296. $lucene->setAutomaticMode();
  297. $t->is($lucene->getLucene()->getMaxBufferedDocs(), 500, '->setAutomaticMode() sets MaxBufferedDocs to 500 in a CLI environment');
  298. $t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setAutomaticMode() sets MaxMaxMergeDocs to PHP_INT_MAX in a CLI environment');
  299. $t->is($lucene->getLucene()->getMergeFactor(), 50, '->setAutomaticMode() sets MergeFactor to 50 in a CLI environment');
  300. $controller->cli = false;
  301. $lucene->setAutomaticMode();
  302. $t->is($lucene->getLucene()->getMaxBufferedDocs(), 10, '->setAutomaticMode() sets MaxBufferedDocs to 10 in a web environment');
  303. $t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setAutomaticMode() sets MaxMaxMergeDocs to PHP_INT_MAX in a web environment');
  304. $t->is($lucene->getLucene()->getMergeFactor(), 10, '->setAutomaticMode() sets MergeFactor to 10 in a web environment');
  305. sfContext::getInstance()->set('controller', $oldController);
  306. $lucene->setBatchMode();
  307. $t->is($lucene->getLucene()->getMaxBufferedDocs(), 500, '->setBatchMode() sets MaxBufferedDocs to 500');
  308. $t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setBatchMode() sets MaxMaxMergeDocs to PHP_INT_MAX');
  309. $t->is($lucene->getLucene()->getMergeFactor(), 50, '->setBatchMode() sets MergeFactor to 50');
  310. $lucene->setInteractiveMode();
  311. $t->is($lucene->getLucene()->getMaxBufferedDocs(), 10, '->setInteractiveMode() sets MaxBufferedDocs to 10');
  312. $t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setInteractiveMode() sets MaxMaxMergeDocs to PHP_INT_MAX');
  313. $t->is($lucene->getLucene()->getMergeFactor(), 10, '->setInteractiveMode() sets MergeFactor to 10');
  314. $t->diag('testing mixins');
  315. function callListener($event)
  316. {
  317. if ($event['method'] == 'goodMethod')
  318. {
  319. $args = $event['arguments'];
  320. $event->setReturnValue($args[0] + 1);
  321. return true;
  322. }
  323. return false;
  324. }
  325. $lucene->getEventDispatcher()->connect('lucene.method_not_found', 'callListener');
  326. try {
  327. $lucene->someBadMethod();
  328. $t->fail('__call() rejects bad methods');
  329. } catch (Exception $e) {
  330. $t->pass('__call() rejects bad methods');
  331. }
  332. try {
  333. $return = $lucene->goodMethod(2);
  334. $t->pass('__call() accepts good methods');
  335. $t->is($return, 3, '__call() passes arguments');
  336. } catch (Exception $e) {
  337. $t->fail('__call() accepts good methods and passes arguments');
  338. $e->printStackTrace();
  339. $t->skip('__call() passes arguments');
  340. }