|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "testutils.h" |
|
19 #include "testcorpus.h" |
|
20 #include "config.h" |
|
21 #include "itk.h" |
|
22 #include "setupsentry.h" |
|
23 |
|
24 #include <iostream> |
|
25 |
|
26 #include "cpixsearch.h" |
|
27 |
|
28 // Disable test cases, which prevent running other cases |
|
29 #define DISABLE_CRASHING_TEST_CASES |
|
30 |
|
31 class DestructiveTests : public Itk::ITestContext |
|
32 { |
|
33 private: // data |
|
34 |
|
35 SmsIdxUtil* idxUtil_; |
|
36 LineTestCorpusRef testCorpus_; |
|
37 |
|
38 cpix_Analyzer* analyzer_; |
|
39 cpix_QueryParser* uidQueryParser_; |
|
40 cpix_QueryParser* contentQueryParser_; |
|
41 cpix_IdxSearcher * searcher_; |
|
42 |
|
43 public: // Constructors & destructors |
|
44 |
|
45 DestructiveTests() |
|
46 : idxUtil_(NULL), |
|
47 testCorpus_(DEFAULT_TEST_CORPUS_PATH), |
|
48 analyzer_(NULL), |
|
49 uidQueryParser_(NULL), |
|
50 contentQueryParser_(NULL), |
|
51 searcher_(NULL) |
|
52 { |
|
53 ; |
|
54 } |
|
55 |
|
56 |
|
57 ~DestructiveTests() |
|
58 { |
|
59 cleanup(); |
|
60 } |
|
61 |
|
62 |
|
63 void setup() throw (Itk::PanicExc) |
|
64 { |
|
65 SetupSentry |
|
66 ss(*this); |
|
67 |
|
68 cpix_Result |
|
69 result; |
|
70 |
|
71 // cpix_setLogLevel(CPIX_LL_DEBUG); |
|
72 |
|
73 cpix_IdxDb_dbgScrapAll(&result); |
|
74 |
|
75 if (cpix_Failed(&result)) |
|
76 { |
|
77 ITK_PANIC("Could not scrap all"); |
|
78 } |
|
79 |
|
80 idxUtil_ = new SmsIdxUtil; |
|
81 idxUtil_->init( true ); |
|
82 |
|
83 analyzer_ = cpix_CreateSimpleAnalyzer(&result); |
|
84 if ( !analyzer_ ) |
|
85 { |
|
86 ITK_PANIC("Analyzer could not be created"); |
|
87 } |
|
88 |
|
89 uidQueryParser_ = cpix_QueryParser_create( &result, |
|
90 LCPIX_DOCUID_FIELD, |
|
91 analyzer_ ); |
|
92 if ( !( uidQueryParser_ ) ) |
|
93 { |
|
94 ITK_PANIC("Query parser could not be created"); |
|
95 } |
|
96 |
|
97 contentQueryParser_ = cpix_QueryParser_create( &result, |
|
98 LBODY_FIELD, |
|
99 analyzer_ ); |
|
100 if ( !( contentQueryParser_ ) ) |
|
101 { |
|
102 ITK_PANIC("Query parser could not be created"); |
|
103 } |
|
104 |
|
105 ss.setupComplete(); |
|
106 } |
|
107 |
|
108 |
|
109 |
|
110 void tearDown() throw () |
|
111 { |
|
112 cleanup(); |
|
113 |
|
114 // cpix_setLogLevel(CPIX_LL_TRACE); |
|
115 } |
|
116 |
|
117 public: // Test cases |
|
118 |
|
119 void cleanup() |
|
120 { |
|
121 cpix_Analyzer_destroy( analyzer_ ); |
|
122 analyzer_ = NULL; |
|
123 cpix_QueryParser_destroy( uidQueryParser_ ); |
|
124 uidQueryParser_ = NULL; |
|
125 cpix_QueryParser_destroy( contentQueryParser_ ); |
|
126 contentQueryParser_ = NULL; |
|
127 delete idxUtil_; |
|
128 idxUtil_ = NULL; |
|
129 cpix_IdxSearcher_releaseDb(searcher_); |
|
130 searcher_ = NULL; |
|
131 } |
|
132 |
|
133 void testWritingWhenHitIterating(Itk::TestMgr* testMgr) { |
|
134 testWritingWhenHitIterating(testMgr, |
|
135 idxUtil_->idxDb(), |
|
136 &cpix_IdxDb_search, |
|
137 3); |
|
138 } |
|
139 |
|
140 |
|
141 void testWritingWhenHitIterating2(Itk::TestMgr* testMgr) { |
|
142 testWritingWhenHitIterating(testMgr, |
|
143 searcher(testMgr), |
|
144 &cpix_IdxSearcher_search, |
|
145 3); |
|
146 } |
|
147 |
|
148 void testInvalidation(Itk::TestMgr* testMgr) |
|
149 { |
|
150 for (int i = 0; i < 25; i++) |
|
151 { |
|
152 idxUtil_->indexSms( i, |
|
153 testCorpus_.item(i).c_str(), |
|
154 analyzer_, |
|
155 testMgr, |
|
156 false ); |
|
157 } |
|
158 idxUtil_->flush(); |
|
159 |
|
160 cpix_Query* query = cpix_QueryParser_parse( contentQueryParser_, L"ok" ); |
|
161 |
|
162 ITK_ASSERT( testMgr, query, "Query parsing failed" ); |
|
163 |
|
164 cpix_Hits *hits = |
|
165 cpix_IdxDb_search(idxUtil_->idxDb(), query ); |
|
166 |
|
167 if ( cpix_Failed( idxUtil_->idxDb() ) ) { |
|
168 cpix_Query_destroy( query ); |
|
169 ITK_PANIC( "Search failed" ); |
|
170 } |
|
171 printf("Accessing hits before closing... "); |
|
172 |
|
173 cpix_Hits_length( hits ); |
|
174 ITK_ASSERT( testMgr, cpix_Succeeded( hits ), "Accessing hit length failed" ); |
|
175 printf("OK. Hits could be accessed.\n"); |
|
176 |
|
177 /* OBS |
|
178 // cleanup |
|
179 idxUtil_->close(); |
|
180 */ |
|
181 |
|
182 |
|
183 for (int i = 0; i < 5; i++) |
|
184 { |
|
185 idxUtil_->indexSms( i, |
|
186 testCorpus_.item(i).c_str(), |
|
187 analyzer_, |
|
188 testMgr, |
|
189 false ); |
|
190 } |
|
191 cpix_IdxDb_flush(idxUtil_->idxDb()); |
|
192 ITK_EXPECT(testMgr, |
|
193 cpix_Succeeded(idxUtil_->idxDb()), |
|
194 "Flushing failed"); |
|
195 |
|
196 |
|
197 cpix_IdxSearcher_releaseDb(searcher_); |
|
198 searcher_ = NULL; |
|
199 idxUtil_->close(); |
|
200 |
|
201 // Confirm no crash and that access fails |
|
202 |
|
203 printf("Accessing hits after closing... \n"); |
|
204 cpix_Document |
|
205 doc; |
|
206 |
|
207 printf("doc #0: "); |
|
208 cpix_Hits_doc(hits, |
|
209 0, |
|
210 &doc); |
|
211 ITK_EXPECT( testMgr, |
|
212 cpix_Succeeded( hits ), |
|
213 "Accessing hit(0) should succeeded for closed database (hits still holds a reference to its originator)." ); |
|
214 |
|
215 if (cpix_Failed(hits)) |
|
216 { |
|
217 wchar_t |
|
218 buf[256]; |
|
219 cpix_Error_report(hits->err_, |
|
220 buf, |
|
221 sizeof(buf) / sizeof(wchar_t)); |
|
222 printf("%S\n", buf); |
|
223 cpix_ClearError(hits); |
|
224 } |
|
225 |
|
226 printf("\ndoc #20: "); |
|
227 cpix_Hits_doc(hits, |
|
228 20, |
|
229 &doc); |
|
230 ITK_EXPECT( testMgr, |
|
231 cpix_Failed( hits ), |
|
232 "Accessing hit(20) should NOT succeeded for closed database (hits still holds a reference to its originator)." ); |
|
233 |
|
234 if (cpix_Failed(hits)) |
|
235 { |
|
236 wchar_t |
|
237 buf[256]; |
|
238 cpix_Error_report(hits->err_, |
|
239 buf, |
|
240 sizeof(buf) / sizeof(wchar_t)); |
|
241 printf("%S\n", buf); |
|
242 cpix_ClearError(hits); |
|
243 } |
|
244 |
|
245 cpix_Hits_destroy( hits ); |
|
246 cpix_Query_destroy( query ); |
|
247 } |
|
248 |
|
249 |
|
250 /** |
|
251 * The purpose of this test is to test the stack unwinding problem, |
|
252 * which occurs e.g. if we provide bad schema and the idxdb will react |
|
253 * by throwing an exception. |
|
254 */ |
|
255 void testStackunwinding(Itk::TestMgr* testMgr) |
|
256 { |
|
257 SchemaId wrongSchema = idxUtil_->schemaId(); |
|
258 cpix_Result |
|
259 result; |
|
260 |
|
261 delete idxUtil_; |
|
262 idxUtil_ = NULL; |
|
263 |
|
264 cpix_IdxDb |
|
265 * idxDb = cpix_IdxDb_openDb(&result, |
|
266 SMS_QBASEAPPCLASS, |
|
267 cpix_IDX_OPEN); |
|
268 // Open index without redefining schema |
|
269 |
|
270 if (cpix_Failed(&result)) |
|
271 { |
|
272 ITK_PANIC("Index could not be opened"); |
|
273 } |
|
274 |
|
275 // Try to index things |
|
276 for (int i = 0; i < 5; i++) |
|
277 { |
|
278 std::wstring id = GetItemId( i ); |
|
279 std::wstring content = testCorpus_.item( i ); |
|
280 |
|
281 const wchar_t |
|
282 * fields[4]; |
|
283 fields[0] = L"+3585553412"; // to |
|
284 fields[1] = L"+3585559078"; // from |
|
285 fields[2] = L"inbox"; // folder |
|
286 fields[3] = content.c_str();// body |
|
287 |
|
288 |
|
289 cpix_IdxDb_add2( idxDb, |
|
290 wrongSchema, |
|
291 id.c_str(), |
|
292 // OBS DEFAULT_APPTYPE, |
|
293 SMSAPPCLASS, |
|
294 content.c_str(), |
|
295 NULL, |
|
296 fields, |
|
297 analyzer_ ); |
|
298 |
|
299 bool |
|
300 succeeded = cpix_Succeeded(idxDb); |
|
301 |
|
302 ITK_ASSERT( testMgr, !succeeded, "Schema is persistent?" ); |
|
303 } |
|
304 |
|
305 cpix_IdxDb_releaseDb(idxDb); |
|
306 idxDb = NULL; |
|
307 |
|
308 idxUtil_ = new SmsIdxUtil; |
|
309 idxUtil_->init( true ); |
|
310 |
|
311 } |
|
312 |
|
313 |
|
314 private: |
|
315 template<typename IDX> |
|
316 void testWritingWhenHitIterating(Itk::TestMgr * testMgr, |
|
317 IDX * idx, |
|
318 cpix_Hits * (* searcher)(IDX*,cpix_Query*), |
|
319 int32_t matches) |
|
320 { |
|
321 wprintf(L"Testing writing to index, while hit object is continuosly read.\n"); |
|
322 |
|
323 // Index |
|
324 for (int i = 0; i < 25; i++) { |
|
325 idxUtil_->indexSms( i, |
|
326 testCorpus_.item(i).c_str(), |
|
327 analyzer_, |
|
328 testMgr, |
|
329 false ); |
|
330 } |
|
331 idxUtil_->flush(); |
|
332 |
|
333 printf("25 items indexed.\n"); |
|
334 |
|
335 cpix_Query* query = cpix_QueryParser_parse( contentQueryParser_, L"ok" ); |
|
336 |
|
337 if ( query != NULL ) { |
|
338 cpix_Hits *hits = |
|
339 (*searcher)(idx, query ); |
|
340 |
|
341 if ( hits ) |
|
342 { |
|
343 // We know that 25 first message contain this many 'ok's. |
|
344 ITK_EXPECT( testMgr, cpix_Hits_length( hits ) == matches, |
|
345 "There should be %d matches instead of %d", |
|
346 matches, |
|
347 cpix_Hits_length(hits)); |
|
348 int length = 0; |
|
349 |
|
350 printf("Hits after indexing: \n"); |
|
351 idxUtil_->printHits( hits, testMgr ); |
|
352 |
|
353 // Should this also crash? By the way, this is one of the document results |
|
354 idxUtil_->indexSms( 25, |
|
355 testCorpus_.item(25).c_str(), |
|
356 analyzer_, |
|
357 testMgr, |
|
358 false ); |
|
359 |
|
360 ITK_EXPECT( testMgr, cpix_Succeeded( idx ), "Adding 25th item failed" ); |
|
361 |
|
362 printf("1 item indexed. \n"); |
|
363 |
|
364 cpix_Hits_length( hits ); |
|
365 ITK_EXPECT( testMgr, cpix_Succeeded( hits ), "Accessing hit of index 1 failed" ); |
|
366 |
|
367 printf("Hits after adding 1 item.\n"); |
|
368 idxUtil_->printHits( hits, testMgr ); |
|
369 |
|
370 cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 15 ).c_str() ); |
|
371 ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 15 failed" ); |
|
372 |
|
373 printf("Line 16 deleted.\n"); |
|
374 |
|
375 printf("Hits after deletion: \n"); |
|
376 idxUtil_->printHits( hits, testMgr ); |
|
377 |
|
378 cpix_IdxDb_flush(idxUtil_->idxDb() ); |
|
379 ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Flushing failed" ); |
|
380 printf("Flushed.\n"); |
|
381 |
|
382 printf("Hits after flush:\n"); |
|
383 idxUtil_->printHits( hits, testMgr, true ); |
|
384 |
|
385 cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 14 ).c_str() ); |
|
386 ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 14 failed" ); |
|
387 |
|
388 printf("Line 15 deleted.\n"); |
|
389 printf("Hits after deletion:\n"); |
|
390 idxUtil_->printHits( hits, testMgr ); |
|
391 |
|
392 cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 9 ).c_str() ); |
|
393 ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 9 failed" ); |
|
394 |
|
395 printf("Line 10 deleted.\n"); |
|
396 printf("Hits after deletion:\n"); |
|
397 idxUtil_->printHits( hits, testMgr ); |
|
398 |
|
399 cpix_IdxDb_flush(idxUtil_->idxDb() ); |
|
400 ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Flushing failed" ); |
|
401 printf("Flushed.\n"); |
|
402 |
|
403 printf("Hits after flush:\n"); |
|
404 idxUtil_->printHits( hits, testMgr, true ); |
|
405 |
|
406 ITK_EXPECT( testMgr, cpix_Succeeded( hits ), "Accessing hit length failed" ); |
|
407 ITK_EXPECT( testMgr, length == 0, "The items were not deleted." ); |
|
408 |
|
409 cpix_Hits_destroy( hits ); |
|
410 } |
|
411 else |
|
412 { |
|
413 ITK_PANIC("Hits was null"); |
|
414 } |
|
415 cpix_Query_destroy( query ); |
|
416 } else { |
|
417 ITK_PANIC("Could not create query"); |
|
418 } |
|
419 } |
|
420 |
|
421 |
|
422 cpix_IdxSearcher * searcher(Itk::TestMgr * ) |
|
423 { |
|
424 if (searcher_ == NULL) |
|
425 { |
|
426 cpix_Result |
|
427 result; |
|
428 searcher_ = cpix_IdxSearcher_openDb(&result, |
|
429 SMSAPPCLASS); |
|
430 if (searcher_ == NULL) |
|
431 { |
|
432 ITK_PANIC("Searcher could not be created"); |
|
433 } |
|
434 } |
|
435 return searcher_; |
|
436 } |
|
437 }; |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 /** |
|
444 * This test case is incomplete, it is supposed to test for a fix for |
|
445 * the LuceneError flying through the catch(...) problem - but the |
|
446 * real cause is still unidentified, so this test is not enabled yet. |
|
447 */ |
|
448 class CLuceneErrorBugCtxt : public Itk::ITestContext |
|
449 { |
|
450 private: |
|
451 SmsIdxUtil * idxUtil_; |
|
452 |
|
453 cpix_Analyzer * analyzer_; |
|
454 cpix_Query * query_; |
|
455 cpix_QueryParser * queryParser_; |
|
456 |
|
457 |
|
458 public: |
|
459 |
|
460 CLuceneErrorBugCtxt() |
|
461 : idxUtil_(NULL), |
|
462 analyzer_(NULL), |
|
463 query_(NULL), |
|
464 queryParser_(NULL) |
|
465 { |
|
466 ; |
|
467 } |
|
468 |
|
469 |
|
470 ~CLuceneErrorBugCtxt() |
|
471 { |
|
472 cleanup(); |
|
473 } |
|
474 |
|
475 |
|
476 void setup() throw (Itk::PanicExc) |
|
477 { |
|
478 SetupSentry |
|
479 ss(*this); |
|
480 |
|
481 idxUtil_ = new SmsIdxUtil; |
|
482 idxUtil_->init(true); |
|
483 |
|
484 cpix_Result |
|
485 result; |
|
486 |
|
487 analyzer_ = cpix_CreateSimpleAnalyzer(&result); |
|
488 if (cpix_Failed(&result)) |
|
489 { |
|
490 ITK_PANIC("Analyzer could not be created"); |
|
491 } |
|
492 |
|
493 |
|
494 queryParser_ = cpix_QueryParser_create(&result, |
|
495 LBODY_FIELD, |
|
496 analyzer_); |
|
497 |
|
498 if (cpix_Failed(&result)) |
|
499 { |
|
500 ITK_PANIC("QueryParser could not be create4d"); |
|
501 } |
|
502 |
|
503 query_ = cpix_QueryParser_parse(queryParser_, |
|
504 L"c*"); |
|
505 |
|
506 if (query_ == NULL) |
|
507 { |
|
508 ITK_PANIC("Query could not be created for 'c*'"); |
|
509 } |
|
510 |
|
511 ss.setupComplete(); |
|
512 } |
|
513 |
|
514 |
|
515 void tearDown() throw () |
|
516 { |
|
517 cleanup(); |
|
518 } |
|
519 |
|
520 |
|
521 void indexGeneratedLines(Itk::TestMgr * testMgr) |
|
522 { |
|
523 static const int |
|
524 wordsPerLine = 10; |
|
525 |
|
526 // we generate a lot of lines, like "a... a... a...", |
|
527 // "b... b... b...", ..., "j... j... j..." even if what we are |
|
528 // interested in is "c... c... c...". Reason: we need a big |
|
529 // index to produce crash-failure. |
|
530 static const int |
|
531 prefixCount = 10; |
|
532 |
|
533 std::wstring |
|
534 lines[prefixCount]; |
|
535 |
|
536 for (int i = 0; i < 1030; ++i) |
|
537 { |
|
538 if (i % 50 == 0) |
|
539 { |
|
540 ITK_DBGMSG(testMgr, |
|
541 "."); |
|
542 } |
|
543 |
|
544 |
|
545 if (i % wordsPerLine == 0) |
|
546 { |
|
547 for (int j = 0; j < prefixCount; ++j) |
|
548 { |
|
549 lines[j] = L'a' + j; |
|
550 } |
|
551 } |
|
552 else |
|
553 { |
|
554 for (int j = 0; j < prefixCount; ++j) |
|
555 { |
|
556 lines[j] += L' '; |
|
557 lines[j] += L'a' + j; |
|
558 } |
|
559 } |
|
560 |
|
561 std::wstring |
|
562 postfix; |
|
563 |
|
564 static const int |
|
565 charNum = int('z') - int('a') + 1; |
|
566 static const int |
|
567 digits = 4; |
|
568 |
|
569 // we generate a postfix |
|
570 int |
|
571 generator = i; |
|
572 for (int d = 0; d < digits; ++d) |
|
573 { |
|
574 postfix += char('a' + generator % charNum); |
|
575 generator /= charNum; |
|
576 } |
|
577 |
|
578 for (int j = 0; j < prefixCount; ++j) |
|
579 { |
|
580 lines[j] += postfix; |
|
581 |
|
582 if (i % wordsPerLine == (wordsPerLine - 1)) |
|
583 { |
|
584 idxUtil_->indexSms(i - j, |
|
585 lines[j].c_str(), |
|
586 analyzer_, |
|
587 testMgr, |
|
588 false); // addition, not update |
|
589 |
|
590 ITK_ASSERT(testMgr, |
|
591 cpix_Succeeded(idxUtil_->idxDb()), |
|
592 "Addition of c... words should have succeeded"); |
|
593 } |
|
594 } |
|
595 } |
|
596 } |
|
597 |
|
598 |
|
599 void searchCWildCard(Itk::TestMgr * testMgr) |
|
600 { |
|
601 cpix_Hits |
|
602 * hits = cpix_IdxDb_search(idxUtil_->idxDb(), |
|
603 query_); |
|
604 |
|
605 ITK_EXPECT(testMgr, |
|
606 cpix_Failed(idxUtil_->idxDb()), |
|
607 "Wildcard search 'c*' should fail gracefully"); |
|
608 |
|
609 cpix_Hits_destroy(hits); |
|
610 } |
|
611 |
|
612 |
|
613 |
|
614 private: |
|
615 void cleanup() |
|
616 { |
|
617 cpix_Analyzer_destroy(analyzer_); |
|
618 analyzer_ = NULL; |
|
619 |
|
620 cpix_Query_destroy(query_); |
|
621 query_ = NULL; |
|
622 |
|
623 delete idxUtil_; |
|
624 idxUtil_ = NULL; |
|
625 |
|
626 cpix_QueryParser_destroy(queryParser_); |
|
627 queryParser_ = NULL; |
|
628 } |
|
629 }; |
|
630 |
|
631 |
|
632 Itk::TesterBase * CreateCLuceneErrorTests() |
|
633 { |
|
634 using namespace Itk; |
|
635 |
|
636 CLuceneErrorBugCtxt |
|
637 * cebc = new CLuceneErrorBugCtxt; |
|
638 ContextTester |
|
639 * ct = new ContextTester("clerror", |
|
640 cebc); |
|
641 |
|
642 ct->add("indexGeneratedLines", |
|
643 cebc, |
|
644 &CLuceneErrorBugCtxt::indexGeneratedLines, |
|
645 "indexGeneratedLines"); |
|
646 ct->add("searchCWildCard", |
|
647 cebc, |
|
648 &CLuceneErrorBugCtxt::searchCWildCard); |
|
649 |
|
650 return ct; |
|
651 } |
|
652 |
|
653 |
|
654 Itk::TesterBase * CreateDestructiveTests() |
|
655 { |
|
656 using namespace Itk; |
|
657 |
|
658 DestructiveTests* context = new DestructiveTests(); |
|
659 |
|
660 SuiteTester |
|
661 * suiteTester = new Itk::ContextTester("destructive", context); |
|
662 |
|
663 suiteTester->add( "stackUnwinding", |
|
664 context, |
|
665 &DestructiveTests::testStackunwinding ); |
|
666 |
|
667 #define TEST "writingWhenHitIterating" |
|
668 suiteTester->add(TEST, |
|
669 context, |
|
670 &DestructiveTests::testWritingWhenHitIterating, |
|
671 TEST); |
|
672 #undef TEST |
|
673 |
|
674 #define TEST "writingWhenHitIterating2" |
|
675 suiteTester->add(TEST, |
|
676 context, |
|
677 &DestructiveTests::testWritingWhenHitIterating2, |
|
678 TEST); |
|
679 #undef TEST |
|
680 |
|
681 suiteTester->add("invalidation", |
|
682 context, |
|
683 &DestructiveTests::testInvalidation, |
|
684 "invalidation"); |
|
685 |
|
686 return suiteTester; |
|
687 } |