sfluceneplugin /test/unit/sfLuceneTest.php

Language PHP Lines 446
MD5 Hash 775809b30f3222823caa7174c2552d4d Estimated Cost $8,301 (why?)
Repository https://bitbucket.org/anycode/sfluceneplugin.git View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
<?php
/*
 * This file is part of the sfLucenePlugin package
 * (c) 2007 - 2008 Carl Vondrick <carl@carlsoft.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
  * @package sfLucenePlugin
  * @subpackage Test
  * @author Carl Vondrick
  * @version SVN: $Id: sfLuceneTest.php 7108 2008-01-20 07:44:42Z Carl.Vondrick $
  */

require dirname(__FILE__) . '/../bootstrap/unit.php';

$t = new limeade_test(91, limeade_output::get());
$limeade = new limeade_sf($t);
$app = $limeade->bootstrap();

$luceneade = new limeade_lucene($limeade);
$luceneade->configure()->clear_sandbox();

$t->diag('testing ::getInstance()');

$t->ok(!is_dir(sfConfig::get('sf_data_dir') . '/index/testLucene/en'), 'Lucene directory does not initially exist');

try {
  $e = $t->no_exception('::getInstance() allows valid cultures');
  $lucene = sfLucene::getInstance('testLucene','en');
  $e->no();
} catch (Exception $ex) {
  $e->caught($ex);
}

$t->ok(is_dir(sfConfig::get('sf_data_dir') . '/index/testLucene/en'), '::getInstance() creates the index');
$stat = stat(sfConfig::get('sf_data_dir') . '/index/testLucene/en/segments.gen');

$lucene->unlatch();
unset($lucene);

try {
  $lucene = sfLucene::getInstance('testLucene', 'en');
  clearstatcache();
  $t->is_deeply(stat(sfConfig::get('sf_data_dir') . '/index/testLucene/en/segments.gen'), $stat, '::getInstance() again opens the index');
} catch (Exception $e) {
  $t->skip('::getInstance() agains opens the index');
}

try {
  $e = $t->exception('::getInstance() rejects invalid cultures');
  sfLucene::getInstance('testLucene', 'piglatin');
  $e->no();
} catch (Exception $ex) {
  $e->caught($ex);
}

try {
  $e = $t->exception('::getInstance() rejects invalid names');
  sfLucene::getInstance('badname', 'en');
  $e->no();
} catch (Exception $ex) {
  $e->caught($ex);
}

try {
  sfLucene::getInstance('testLucene', 'en', true);
  $t->fail('::getInstance() fails to rebuild index if index is already open');
} catch (Exception $e) {
  $t->pass('::getInstance() fails to rebuild index if index is already open');
}

try {
  $e = $t->no_exception('::getInstance() allows to rebuild index if closed');
  $new = sfLucene::getInstance('testLucene', 'fr', true);
  $e->no();
} catch (Exception $ex) {
  $e->caught($ex);
}

try {
  sfContext::getInstance()->getUser()->setCulture('en');
  $t->is(sfLucene::getInstance('testLucene')->getParameter('culture'), 'en', '::getInstance() can guess the culture');
} catch (Exception $e) {
  $t->fail('::getInstance() can guess the culture');
}

if ($new) {
  $t->ok($new->getParameter('is_new'), 'property "is_new" is true on a new index');
  $t->is($new->numDocs(), 0, '->numDocs() indicates index is empty');
} else {
  $t->skip('index has new status new status on new index');
  $t->skip('->numDocs() indicates index is empty');
}

$t->diag('testing ::getAllInstances()');

try {
  $t->no_exception('::getAllInstance() executes without exception');
  $instances = sfLucene::getAllInstances();
  $e->no();
} catch (Exception $ex) {
  $instances = array();
  $e->caught($ex);
}

$t->is_deeply($instances, array(sfLucene::getInstance('testLucene','en'), sfLucene::getInstance('testLucene','fr'), sfLucene::getInstance('fooLucene','en')), '::getAllInstances() returns all instances');

$t->is_deeply(sfLucene::getAllNames(), array('testLucene', 'fooLucene'), '::getAllNames() returns all configured names');

$t->diag('testing ->loadConfig()');

$h = $lucene->getParameterHolder();
$t->isa_ok($h, 'sfParameterHolder', '->getParameterHolder() returns a parameter holder');

$t->is($h->get('name'), 'testLucene', 'property "name" is the name of the index');
$t->is($h->get('culture'), 'en', 'property "culture" is the culture of the index');
$t->is($h->get('enabled_cultures'), array('en', 'fr'), 'property "enabled_cultures" contains all enabled cultures');
$t->like($h->get('index_location'), '#/index/testLucene/en$#', 'property "index_location" is the correct path');
$t->is($h->get('encoding'), 'UTF-8', 'property "encoding" is the encoding');
$t->is($h->get('stop_words'), array('and', 'the'), 'property "stop_words" contains the stop words');
$t->is($h->get('short_words'), 2, 'property "short_words" is the short word limit');
$t->is($h->get('mb_string'), true, 'property "mb_string" indicates if to use mb_string functions');

$t->isa_ok($h->get('models'), 'sfParameterHolder', 'property "models" is a sfParameterHolder');
$t->isa_ok($h->get('models')->get('FakeForum'), 'sfParameterHolder', 'properties of "models" are sfParameterHolders');

$m = $h->get('models')->get('FakeForum');

$t->is($m->get('title'), 'title', 'model property "title" is the correct title field');
$t->is($m->get('description'), 'description', 'model property "description" is the correct description field');
$t->is($m->get('categories'), array('Forum'), 'model property "categories" contains the correct categories');
$t->is($m->get('route'), 'forum/showForum?id=%id%', 'model property "route" is the correct route');
$t->is($m->get('validator'), 'isIndexable', 'model property "validator" is the correct validator');
$t->is($m->get('peer'), 'FakeForumPeer', 'model property "peer" is the correct peer');
$t->is($m->get('rebuild_limit'), 5, 'model property "rebuild_limit" is the correct rebuild limit');
$t->is($m->get('partial'), 'forumResult', 'model property "partial" is the correct partial');

$f = $m->get('fields');
$t->isa_ok($f, 'sfParameterHolder', 'model property "fields" is a sfParameterHolder');
$t->is($f->getNames(), array('id','title','description'), 'model property "fields" contains all the fields');
$t->is($f->get('id')->get('type'), 'unindexed', 'field property "type" is the type');
$t->is($f->get('id')->get('boost'), 1, 'field property "boost" is the boost');

$t->diag('testing ::getConfig()');

$cswap = $app->cswap($luceneade->config_dir . '/search.yml')->write('<?php $foo = 42;');

try {
  $e = $t->exception('::getConfig() fails if search.yml is corrupt');
  sfLucene::getConfig();
  $e->no();
} catch (Exception $ex) {
  $e->caught($ex);
}

$cswap->write('<?php $config = array(1, 2, 3);');

try {
  $t->is(sfLucene::getConfig(), array(1, 2, 3), '::getConfig() returns the $config variable in the search.yml file');
} catch (Exception $e) {
  $t->fail('::getConfig() returns the $config variable in the search.yml file');
}

$cswap->restore();

$t->diag('testing ->getCategoriesHarness()');
$cats = $lucene->getCategoriesHarness();

$t->isa_ok($cats, 'sfLuceneCategories', '->getCategories() returns an instance of sfLuceneCategories');
$t->ok($lucene->getCategoriesHarness() === $cats, '->getCategories() is a singleton');

$t->diag('testing ->getIndexerFactory()');
$indexer = $lucene->getIndexerFactory();
$t->isa_ok($indexer, 'sfLuceneIndexerFactory', '->getIndexer() returns an instance of sfLuceneIndexerFactory');

$t->diag('testing ->getContext()');
$t->isa_ok($lucene->getContext(), 'sfContext', '->getContext() returns an instance of sfContext');
$t->is($lucene->getContext(), sfContext::getInstance(), '->getContext() returns the same context');

$t->diag('testing ->configure()');
$lucene->configure();

$t->is(Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding(), 'UTF-8', '->configure() configures the query parsers encoding');

foreach (array('Text', 'TextNum', 'Utf8', 'Utf8Num') as $type)
{
  $lucene->setParameter('analyzer', $type);
  $lucene->configure();

  $class = 'Zend_Search_Lucene_Analysis_Analyzer_Common_' . $type;
  $expected = new $class();
  $expected->addFilter(new sfLuceneLowerCaseFilter(true));
  $expected->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_StopWords(array('and', 'the')));
  $expected->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_ShortWords(2));

  $actual = Zend_Search_Lucene_Analysis_Analyzer::getDefault();

  $t->ok($actual == $expected, '->configure() configures the analyzer for ' . $type);
}

$lucene->setParameter('analyzer', 'foobar');

try {
  $lucene->configure();
  $t->fail('->configure() analyzer must be of text, textnum, utf8, or utf8num');
} catch (Exception $e) {
  $t->pass('->configure() analyzer must be of text, textnum, utf8, or utf8num');
}

$lucene->setParameter('analyzer', 'utf8num');

$t->diag('testing ->find()');

class MockLucene
{
  public $args;
  public $scoring;
  public $e = false;

  public function find()
  {
    if ($this->e) throw new Exception('Because you said so');

    $this->args = func_get_args();
    $this->scoring = Zend_Search_Lucene_Search_Similarity::getDefault();

    return range(1, 100);
  }
}

class MockScoring extends Zend_Search_Lucene_Search_Similarity_Default {}

$mock = new MockLucene;

$originalLucene = $lucene->getLucene();
$lucene->forceLucene($mock);

$t->is($lucene->find('foo'), range(1, 100), '->find() returns what ZSL returns');
$t->ok(sfLuceneCriteria::newInstance($lucene)->add('foo')->getQuery() == $mock->args[0], '->find() parses string queries');
$t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() with a string uses default scoring algorithm');

$query = sfLuceneCriteria::newInstance($lucene)->add('foo')->addRange('a', 'b', 'c');
$lucene->find($query);
$t->ok($query->getQuery() == $mock->args[0], '->find() accepts sfLuceneCriteria queries');
$t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() without specified scorer uses default scoring algorithm');

$query = new Zend_Search_Lucene_Search_Query_Boolean();
$lucene->find($query);
$t->ok($query == $mock->args[0], '->find() accepts Zend API queries');
$t->isa_ok($mock->scoring, 'Zend_Search_Lucene_Search_Similarity_Default', '->find() with a Zend API queries uses default scoring algorithm');

$scoring = new MockScoring;
$lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->setScoringAlgorithm($scoring));
$t->is($mock->scoring, $scoring, '->find() changes the scoring algorithm if sfLuceneCriteria specifies it');
$t->isa_ok(Zend_Search_Lucene_Search_Similarity::getDefault(), 'Zend_Search_Lucene_Search_Similarity_Default', '->find() resets the default scoring algorithm after processing');

$lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->addAscendingSortBy('sort1')->addDescendingSortBy('sort2', SORT_NUMERIC));

$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');

$results = $lucene->friendlyFind('foo');
$t->isa_ok($results, 'sfLuceneResults', '->friendlyFind() returns an instance of sfLuceneResults');
$t->is($results->toArray(), range(1, 100), '->friendlyFind() houses the data from ZSL');
$t->is($results->getSearch(), $lucene, '->friendlyFind() is connected to the Lucene instance');

$mock->e = true;
try {
  $lucene->find(sfLuceneCriteria::newInstance($lucene)->add('foo')->setScoringAlgorithm(new MockScoring));
  $t->fail('if ZSL throws exception, ->find() also throws the exception');
  $t->skip('if ZSL throws exception, ->find() stills resets the scoring algorithm');
} catch (Exception $e) {
  $t->pass('if ZSL throws exception, ->find() also throws the exception');
  $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');
}

$lucene->forceLucene($originalLucene);

$t->diag('testing ->rebuildIndex()');

class MockIndexerFactory
{
  public $handlers, $deleteLock = false, $search;

  public function __construct($h, $s)
  {
    $this->handlers = $h;
    $this->search = $s;
  }

  public function getHandlers()
  {
    $this->deleteLock = $this->search->getParameter('delete_lock');
    return $this->handlers;
  }
}

class MockIndexerHandler
{
  public $count = 0;

  public function rebuild()
  {
    $this->count++;
  }
}

$handlers = array(new MockIndexerHandler, new MockIndexerHandler);
$factory = new MockIndexerFactory($handlers, $lucene);

$originalFactory = $lucene->getIndexerFactory();
$lucene->forceIndexerFactory($factory);

$lucene->getCategoriesHarness()->getCategory('foo');
$lucene->getCategoriesHarness()->save();

$lucene->rebuildIndex();

$t->is($factory->deleteLock, true, '->rebuildIndex() enables the delete lock');
$t->ok($handlers[0]->count == 1 && $handlers[0]->count == 1, '->rebuildIndex() calls each handler\'s ->rebuild() only once');

$t->is($lucene->getCategoriesHarness()->getAllCategories(), array(), '->rebuildIndex() clears the category list');

$lucene->forceIndexerFactory($originalFactory);

$t->diag('testing wrappers');

try {
  $lucene->optimize();
  $t->pass('->optimize() optimizes the index without exception');
} catch (Exception $e) {
  $t->fail('->optimize() optimizes the index without exception');
}

try {
  $t->is($lucene->count(), 0, '->count() returns the document count');
  $t->pass('->count() counts the index without exception');
} catch (Exception $e) {
  $t->skip('->count() returns the document count');
  $t->fail('->count() counts the index without exception');
}

try {
  $t->is($lucene->numDocs(), 0, '->numDocs() returns the document count');
  $t->pass('->numDocs() counts the index without exception');
} catch (Exception $e) {
  $t->skip('->numDocs() returns the document count');
  $t->fail('->numDocs() counts the index without exception');
}

try {
  $lucene->commit();
  $t->pass('->commit() commits the index without exception');
} catch (Exception $e) {
  $t->fail('->commit() commits the index without exception');
}

$t->diag('testing statistics');

$originalLocation = $lucene->getParameter('index_location');

$lucene->setParameter('index_location', $luceneade->data_dir . '/foo');

$t->is($lucene->byteSize(), 8222, '->byteSize() returns the correct size in bytes');
$t->is($lucene->segmentCount(), 2, '->segmentCount() returns the correct segment count');

$lucene->setParameter('index_location', $originalLocation);

$t->diag('testing modes');

class FooController
{
  public $cli = true;

  public function inCLI()
  {
    return $this->cli;
  }
}

$controller = new FooController();
$oldController = sfContext::getInstance()->get('controller');
sfContext::getInstance()->set('controller', $controller);

$lucene->setAutomaticMode();
$t->is($lucene->getLucene()->getMaxBufferedDocs(), 500, '->setAutomaticMode() sets MaxBufferedDocs to 500 in a CLI environment');
$t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setAutomaticMode() sets MaxMaxMergeDocs to PHP_INT_MAX in a CLI environment');
$t->is($lucene->getLucene()->getMergeFactor(), 50, '->setAutomaticMode() sets MergeFactor to 50 in a CLI environment');

$controller->cli = false;

$lucene->setAutomaticMode();
$t->is($lucene->getLucene()->getMaxBufferedDocs(), 10, '->setAutomaticMode() sets MaxBufferedDocs to 10 in a web environment');
$t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setAutomaticMode() sets MaxMaxMergeDocs to PHP_INT_MAX in a web environment');
$t->is($lucene->getLucene()->getMergeFactor(), 10, '->setAutomaticMode() sets MergeFactor to 10 in a web environment');

sfContext::getInstance()->set('controller', $oldController);

$lucene->setBatchMode();
$t->is($lucene->getLucene()->getMaxBufferedDocs(), 500, '->setBatchMode() sets MaxBufferedDocs to 500');
$t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setBatchMode() sets MaxMaxMergeDocs to PHP_INT_MAX');
$t->is($lucene->getLucene()->getMergeFactor(), 50, '->setBatchMode() sets MergeFactor to 50');

$lucene->setInteractiveMode();
$t->is($lucene->getLucene()->getMaxBufferedDocs(), 10, '->setInteractiveMode() sets MaxBufferedDocs to 10');
$t->is($lucene->getLucene()->getMaxMergeDocs(), PHP_INT_MAX, '->setInteractiveMode() sets MaxMaxMergeDocs to PHP_INT_MAX');
$t->is($lucene->getLucene()->getMergeFactor(), 10, '->setInteractiveMode() sets MergeFactor to 10');

$t->diag('testing mixins');

function callListener($event)
{
  if ($event['method'] == 'goodMethod')
  {
    $args = $event['arguments'];

    $event->setReturnValue($args[0] + 1);

    return true;
  }

  return false;
}

$lucene->getEventDispatcher()->connect('lucene.method_not_found', 'callListener');

try {
  $lucene->someBadMethod();
  $t->fail('__call() rejects bad methods');
} catch (Exception $e) {
  $t->pass('__call() rejects bad methods');
}

try {
  $return = $lucene->goodMethod(2);
  $t->pass('__call() accepts good methods');
  $t->is($return, 3, '__call() passes arguments');
} catch (Exception $e) {
  $t->fail('__call() accepts good methods and passes arguments');

  $e->printStackTrace();

  $t->skip('__call() passes arguments');
}
Back to Top