1 // QueryTest.cpp 2 3 #include <ctype.h> 4 #include <fs_info.h> 5 #include <stdio.h> 6 #include <string> 7 #include <unistd.h> 8 9 #include "QueryTest.h" 10 11 #include <Application.h> 12 #include <Message.h> 13 #include <MessageQueue.h> 14 #include <Messenger.h> 15 #include <NodeMonitor.h> 16 #include <OS.h> 17 #include <Path.h> 18 #include <Query.h> 19 #include <String.h> 20 #include <Volume.h> 21 #include <TestApp.h> 22 #include <TestUtils.h> 23 24 // Query 25 26 class Query : public BQuery { 27 public: 28 #if TEST_R5 29 status_t PushValue(int32 value) { PushInt32(value); return B_OK; } 30 status_t PushValue(uint32 value) { PushUInt32(value); return B_OK; } 31 status_t PushValue(int64 value) { PushInt64(value); return B_OK; } 32 status_t PushValue(uint64 value) { PushUInt64(value); return B_OK; } 33 status_t PushValue(float value) { PushFloat(value); return B_OK; } 34 status_t PushValue(double value) { PushDouble(value); return B_OK; } 35 status_t PushValue(const BString value, bool caseInsensitive = false) 36 { 37 PushString(value.String(), caseInsensitive); return B_OK; 38 } 39 status_t PushAttr(const char *attribute) 40 { 41 BQuery::PushAttr(attribute); 42 return B_OK; 43 } 44 status_t PushOp(query_op op) 45 { 46 BQuery::PushOp(op); 47 return B_OK; 48 } 49 #else 50 status_t PushValue(int32 value) { return PushInt32(value); } 51 status_t PushValue(uint32 value) { return PushUInt32(value); } 52 status_t PushValue(int64 value) { return PushInt64(value); } 53 status_t PushValue(uint64 value) { return PushUInt64(value); } 54 status_t PushValue(float value) { return PushFloat(value); } 55 status_t PushValue(double value) { return PushDouble(value); } 56 status_t PushValue(const BString value, bool caseInsensitive = false) 57 { 58 return PushString(value.String(), caseInsensitive); 59 } 60 #endif 61 }; 62 63 64 // PredicateNode 65 66 class PredicateNode { 67 public: 68 virtual ~PredicateNode() {} 69 70 virtual status_t push(Query &query) const = 0; 71 virtual BString toString() const = 0; 72 }; 73 74 75 // ValueNode 76 77 template<typename ValueType> 78 class ValueNode : public PredicateNode { 79 public: 80 ValueNode(ValueType v) : value(v) {} 81 82 virtual ~ValueNode() {} 83 84 virtual status_t push(Query &query) const 85 { 86 return query.PushValue(value); 87 } 88 89 virtual BString toString() const 90 { 91 return BString() << value; 92 } 93 94 ValueType value; 95 }; 96 97 // float specialization 98 template<> 99 BString 100 ValueNode<float>::toString() const 101 { 102 char buffer[32]; 103 sprintf(buffer, "0x%08lx", *(int32*)&value); 104 return BString() << buffer; 105 } 106 107 // double specialization 108 template<> 109 BString 110 ValueNode<double>::toString() const 111 { 112 char buffer[32]; 113 sprintf(buffer, "0x%016Lx", *(int64*)&value); 114 return BString() << buffer; 115 } 116 117 // StringNode 118 119 class StringNode : public PredicateNode { 120 public: 121 StringNode(BString v, bool caseInsensitive = false) 122 : value(v), caseInsensitive(caseInsensitive) 123 { 124 } 125 126 virtual ~StringNode() {} 127 128 virtual status_t push(Query &query) const 129 { 130 return query.PushValue(value, caseInsensitive); 131 } 132 133 virtual BString toString() const 134 { 135 BString escaped; 136 if (caseInsensitive) { 137 const char *str = value.String(); 138 int32 len = value.Length(); 139 for (int32 i = 0; i < len; i++) { 140 char c = str[i]; 141 if (isalpha(c)) { 142 int lower = tolower(c); 143 int upper = toupper(c); 144 if (lower < 0 || upper < 0) 145 escaped << c; 146 else 147 escaped << "[" << (char)lower << (char)upper << "]"; 148 } else 149 escaped << c; 150 } 151 } else 152 escaped = value; 153 escaped.CharacterEscape("\"\\'", '\\'); 154 return BString("\"") << escaped << "\""; 155 } 156 157 BString value; 158 bool caseInsensitive; 159 }; 160 161 162 // DateNode 163 164 class DateNode : public PredicateNode { 165 public: 166 DateNode(BString v) : value(v) {} 167 168 virtual ~DateNode() {} 169 170 virtual status_t push(Query &query) const 171 { 172 return query.PushDate(value.String()); 173 } 174 175 virtual BString toString() const 176 { 177 BString escaped(value); 178 escaped.CharacterEscape("%\"\\'", '\\'); 179 return BString("%") << escaped << "%"; 180 } 181 182 BString value; 183 }; 184 185 186 // AttributeNode 187 188 class AttributeNode : public PredicateNode { 189 public: 190 AttributeNode(BString v) : value(v) {} 191 192 virtual ~AttributeNode() {} 193 194 virtual status_t push(Query &query) const 195 { 196 return query.PushAttr(value.String()); 197 } 198 199 virtual BString toString() const 200 { 201 return value; 202 } 203 204 BString value; 205 }; 206 207 208 // short hands 209 typedef ValueNode<int32> Int32Node; 210 typedef ValueNode<uint32> UInt32Node; 211 typedef ValueNode<int64> Int64Node; 212 typedef ValueNode<uint64> UInt64Node; 213 typedef ValueNode<float> FloatNode; 214 typedef ValueNode<double> DoubleNode; 215 216 217 // ListNode 218 219 class ListNode : public PredicateNode { 220 public: 221 ListNode(PredicateNode *child1 = NULL, PredicateNode *child2 = NULL, 222 PredicateNode *child3 = NULL, PredicateNode *child4 = NULL, 223 PredicateNode *child5 = NULL, PredicateNode *child6 = NULL) 224 : children() 225 { 226 addChild(child1); 227 addChild(child2); 228 addChild(child3); 229 addChild(child4); 230 addChild(child5); 231 addChild(child6); 232 } 233 234 virtual ~ListNode() 235 { 236 for (int32 i = 0; PredicateNode *child = childAt(i); i++) 237 delete child; 238 } 239 240 virtual status_t push(Query &query) const 241 { 242 status_t error = B_OK; 243 for (int32 i = 0; PredicateNode *child = childAt(i); i++) { 244 error = child->push(query); 245 if (error != B_OK) 246 break; 247 } 248 return error; 249 } 250 251 virtual BString toString() const 252 { 253 return BString("INVALID"); 254 } 255 256 ListNode &addChild(PredicateNode *child) 257 { 258 if (child) 259 children.AddItem(child); 260 return *this; 261 } 262 263 PredicateNode *childAt(int32 index) const 264 { 265 return (PredicateNode*)children.ItemAt(index); 266 } 267 268 BList children; 269 }; 270 271 // OpNode 272 273 class OpNode : public ListNode { 274 public: 275 OpNode(query_op op, PredicateNode *left, PredicateNode *right = NULL) 276 : ListNode(left, right), op(op) {} 277 278 virtual ~OpNode() { } 279 280 virtual status_t push(Query &query) const 281 { 282 status_t error = ListNode::push(query); 283 if (error == B_OK) 284 error = query.PushOp(op); 285 return error; 286 } 287 288 virtual BString toString() const 289 { 290 PredicateNode *left = childAt(0); 291 PredicateNode *right = childAt(1); 292 if (!left) 293 return "INVALID ARGS"; 294 BString result; 295 BString leftString = left->toString(); 296 BString rightString; 297 if (right) 298 rightString = right->toString(); 299 switch (op) { 300 case B_INVALID_OP: 301 result = "INVALID"; 302 break; 303 case B_EQ: 304 result << "(" << leftString << "==" << rightString << ")"; 305 break; 306 case B_GT: 307 result << "(" << leftString << ">" << rightString << ")"; 308 break; 309 case B_GE: 310 result << "(" << leftString << ">=" << rightString << ")"; 311 break; 312 case B_LT: 313 result << "(" << leftString << "<" << rightString << ")"; 314 break; 315 case B_LE: 316 result << "(" << leftString << "<=" << rightString << ")"; 317 break; 318 case B_NE: 319 result << "(" << leftString << "!=" << rightString << ")"; 320 break; 321 case B_CONTAINS: 322 { 323 StringNode *strNode = dynamic_cast<StringNode*>(right); 324 if (strNode) { 325 rightString = StringNode(BString("*") << strNode->value 326 << "*").toString(); 327 } 328 result << "(" << leftString << "==" << rightString << ")"; 329 break; 330 } 331 case B_BEGINS_WITH: 332 { 333 StringNode *strNode = dynamic_cast<StringNode*>(right); 334 if (strNode) { 335 rightString = StringNode(BString(strNode->value) << "*") 336 .toString(); 337 } 338 result << "(" << leftString << "==" << rightString << ")"; 339 break; 340 } 341 case B_ENDS_WITH: 342 { 343 StringNode *strNode = dynamic_cast<StringNode*>(right); 344 if (strNode) { 345 rightString = StringNode(BString("*") << strNode->value) 346 .toString(); 347 } 348 result << "(" << leftString << "==" << rightString << ")"; 349 break; 350 } 351 case B_AND: 352 result << "(" << leftString << "&&" << rightString << ")"; 353 break; 354 case B_OR: 355 result << "(" << leftString << "||" << rightString << ")"; 356 break; 357 case B_NOT: 358 result << "(" << "!" << leftString << ")"; 359 break; 360 case _B_RESERVED_OP_: 361 result = "RESERVED"; 362 break; 363 } 364 return result; 365 } 366 367 query_op op; 368 }; 369 370 371 // QueryTestEntry 372 class QueryTestEntry { 373 public: 374 QueryTestEntry(string path, node_flavor kind, 375 const QueryTestEntry *linkTarget = NULL) 376 : path(path), 377 cpath(NULL), 378 kind(kind), 379 linkToPath(), 380 clinkToPath(NULL), 381 directory(-1), 382 node(-1), 383 name() 384 { 385 cpath = this->path.c_str(); 386 if (linkTarget) 387 linkToPath = linkTarget->path; 388 clinkToPath = this->linkToPath.c_str(); 389 } 390 391 string operator+(string leaf) const 392 { 393 return path + "/" + leaf; 394 } 395 396 string path; 397 const char *cpath; 398 node_flavor kind; 399 string linkToPath; 400 const char *clinkToPath; 401 ino_t directory; 402 ino_t node; 403 string name; 404 }; 405 406 static const char *testVolumeImage = "/tmp/query-test-image"; 407 static const char *testMountPoint = "/non-existing-mount-point"; 408 409 // the test entry hierarchy: 410 // mountPoint 411 // + dir1 412 // + subdir11 413 // + subdir12 414 // + file11 415 // + file12 416 // + link11 417 // + dir2 418 // + subdir21 419 // + subdir22 420 // + subdir23 421 // + file21 422 // + file22 423 // + link21 424 // + dir3 425 // + subdir31 426 // + subdir32 427 // + file31 428 // + file32 429 // + link31 430 // + file1 431 // + file2 432 // + file3 433 // + link1 434 // + link2 435 // + link3 436 static QueryTestEntry mountPoint(testMountPoint, B_DIRECTORY_NODE); 437 static QueryTestEntry dir1(mountPoint + "dir1", B_DIRECTORY_NODE); 438 static QueryTestEntry subdir11(dir1 + "subdir11", B_DIRECTORY_NODE); 439 static QueryTestEntry subdir12(dir1 + "subdir12", B_DIRECTORY_NODE); 440 static QueryTestEntry file11(dir1 + "file11", B_FILE_NODE); 441 static QueryTestEntry file12(dir1 + "file12", B_FILE_NODE); 442 static QueryTestEntry link11(dir1 + "link11", B_SYMLINK_NODE, &file11); 443 static QueryTestEntry dir2(mountPoint + "dir2", B_DIRECTORY_NODE); 444 static QueryTestEntry subdir21(dir2 + "subdir21", B_DIRECTORY_NODE); 445 static QueryTestEntry subdir22(dir2 + "subdir22", B_DIRECTORY_NODE); 446 static QueryTestEntry subdir23(dir2 + "subdir23", B_DIRECTORY_NODE); 447 static QueryTestEntry file21(dir2 + "file21", B_FILE_NODE); 448 static QueryTestEntry file22(dir2 + "file22", B_FILE_NODE); 449 static QueryTestEntry link21(dir2 + "link21", B_SYMLINK_NODE, &file12); 450 static QueryTestEntry dir3(mountPoint + "dir3", B_DIRECTORY_NODE); 451 static QueryTestEntry subdir31(dir3 + "subdir31", B_DIRECTORY_NODE); 452 static QueryTestEntry subdir32(dir3 + "subdir32", B_DIRECTORY_NODE); 453 static QueryTestEntry file31(dir3 + "file31", B_FILE_NODE); 454 static QueryTestEntry file32(dir3 + "file32", B_FILE_NODE); 455 static QueryTestEntry link31(dir3 + "link31", B_SYMLINK_NODE, &file22); 456 static QueryTestEntry file1(mountPoint + "file1", B_FILE_NODE); 457 static QueryTestEntry file2(mountPoint + "file2", B_FILE_NODE); 458 static QueryTestEntry file3(mountPoint + "file3", B_FILE_NODE); 459 static QueryTestEntry link1(mountPoint + "link1", B_SYMLINK_NODE, &file1); 460 static QueryTestEntry link2(mountPoint + "link2", B_SYMLINK_NODE, &file2); 461 static QueryTestEntry link3(mountPoint + "link3", B_SYMLINK_NODE, &file3); 462 463 static QueryTestEntry *allTestEntries[] = { 464 &dir1, &subdir11, &subdir12, &file11, &file12, &link11, 465 &dir2, &subdir21, &subdir22, &subdir23, &file21, &file22, &link21, 466 &dir3, &subdir31, &subdir32, &file31, &file32, &link31, 467 &file1, &file2, &file3, &link1, &link2, &link3 468 }; 469 static const int32 allTestEntryCount 470 = sizeof(allTestEntries) / sizeof(QueryTestEntry*); 471 472 // create_test_entries 473 void 474 create_test_entries(QueryTestEntry **testEntries, int32 count) 475 { 476 // create the command line 477 string cmdLine("true"); 478 for (int32 i = 0; i < count; i++) { 479 const QueryTestEntry *entry = testEntries[i]; 480 switch (entry->kind) { 481 case B_DIRECTORY_NODE: 482 cmdLine += " ; mkdir " + entry->path; 483 break; 484 case B_FILE_NODE: 485 cmdLine += " ; touch " + entry->path; 486 break; 487 case B_SYMLINK_NODE: 488 cmdLine += " ; ln -s " + entry->linkToPath + " " + entry->path; 489 break; 490 case B_ANY_NODE: 491 default: 492 printf("WARNING: invalid node kind\n"); 493 break; 494 } 495 } 496 BasicTest::execCommand(cmdLine); 497 } 498 499 // delete_test_entries 500 void 501 delete_test_entries(QueryTestEntry **testEntries, int32 count) 502 { 503 // create the command line 504 string cmdLine("true"); 505 for (int32 i = 0; i < count; i++) { 506 const QueryTestEntry *entry = testEntries[i]; 507 switch (entry->kind) { 508 case B_DIRECTORY_NODE: 509 case B_FILE_NODE: 510 case B_SYMLINK_NODE: 511 cmdLine += " ; rm -rf " + entry->path; 512 break; 513 case B_ANY_NODE: 514 default: 515 printf("WARNING: invalid node kind\n"); 516 break; 517 } 518 } 519 BasicTest::execCommand(cmdLine); 520 } 521 522 523 524 525 // QueryTest 526 527 // Suite 528 CppUnit::Test* 529 QueryTest::Suite() { 530 CppUnit::TestSuite *suite = new CppUnit::TestSuite(); 531 typedef CppUnit::TestCaller<QueryTest> TC; 532 533 suite->addTest( new TC("BQuery::Predicate Test", 534 &QueryTest::PredicateTest) ); 535 suite->addTest( new TC("BQuery::Parameter Test", 536 &QueryTest::ParameterTest) ); 537 suite->addTest( new TC("BQuery::Fetch Test", &QueryTest::FetchTest) ); 538 suite->addTest( new TC("BQuery::Live Test", &QueryTest::LiveTest) ); 539 540 return suite; 541 } 542 543 // setUp 544 void 545 QueryTest::setUp() 546 { 547 BasicTest::setUp(); 548 fApplication = new BTestApp("application/x-vnd.obos.query-test"); 549 if (fApplication->Init() != B_OK) { 550 fprintf(stderr, "Failed to initialize application.\n"); 551 delete fApplication; 552 fApplication = NULL; 553 } 554 fVolumeCreated = false; 555 } 556 557 // tearDown 558 void 559 QueryTest::tearDown() 560 { 561 BasicTest::tearDown(); 562 if (fApplication) { 563 fApplication->Terminate(); 564 delete fApplication; 565 fApplication = NULL; 566 } 567 if (fVolumeCreated) { 568 deleteVolume(testVolumeImage, testMountPoint); 569 fVolumeCreated = false; 570 } 571 } 572 573 // TestPredicate 574 static 575 void 576 TestPredicate(const PredicateNode &predicateNode, status_t pushResult = B_OK, 577 status_t getResult = B_OK) 578 { 579 BString predicateString = predicateNode.toString().String(); 580 //printf("predicate: `%s'\n", predicateString.String()); 581 // GetPredicate(BString *) 582 { 583 Query query; 584 // CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); 585 status_t error = predicateNode.push(query); 586 if (error != pushResult) { 587 printf("predicate: `%s'\n", predicateString.String()); 588 printf("error: %lx vs %lx\n", error, pushResult); 589 } 590 CPPUNIT_ASSERT( error == pushResult ); 591 if (pushResult == B_OK) { 592 BString predicate; 593 // CPPUNIT_ASSERT( query.GetPredicate(&predicate) == getResult ); 594 error = query.GetPredicate(&predicate); 595 if (error != getResult) { 596 printf("predicate: `%s'\n", predicateString.String()); 597 printf("error: %lx vs %lx\n", error, getResult); 598 } 599 CPPUNIT_ASSERT( error == getResult ); 600 if (getResult == B_OK) { 601 CPPUNIT_ASSERT( (int32)query.PredicateLength() 602 == predicateString.Length() + 1 ); 603 CPPUNIT_ASSERT( predicateString == predicate ); 604 } 605 } 606 } 607 // GetPredicate(char *, size_t) 608 { 609 Query query; 610 CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); 611 if (pushResult == B_OK) { 612 char buffer[1024]; 613 CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer)) 614 == getResult ); 615 if (getResult == B_OK) 616 CPPUNIT_ASSERT( predicateString == buffer ); 617 } 618 } 619 // PredicateLength() 620 { 621 Query query; 622 CPPUNIT_ASSERT( predicateNode.push(query) == pushResult ); 623 if (pushResult == B_OK) { 624 size_t expectedLength 625 = (getResult == B_OK ? predicateString.Length() + 1 : 0); 626 CPPUNIT_ASSERT( query.PredicateLength() == expectedLength ); 627 } 628 } 629 // SetPredicate() 630 { 631 Query query; 632 CPPUNIT_ASSERT( query.SetPredicate(predicateString.String()) == B_OK ); 633 CPPUNIT_ASSERT( (int32)query.PredicateLength() 634 == predicateString.Length() + 1 ); 635 BString predicate; 636 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); 637 CPPUNIT_ASSERT( predicateString == predicate ); 638 } 639 } 640 641 // TestOperator 642 static 643 void 644 TestOperator(query_op op) 645 { 646 // well formed 647 TestPredicate(OpNode(op, 648 new AttributeNode("attribute"), 649 new Int32Node(42) 650 )); 651 TestPredicate(OpNode(op, 652 new AttributeNode("attribute"), 653 new StringNode("some string") 654 )); 655 TestPredicate(OpNode(op, 656 new AttributeNode("attribute"), 657 new DateNode("22 May 2002") 658 )); 659 // ill formed 660 TestPredicate(OpNode(op, new AttributeNode("attribute"), NULL), B_OK, 661 B_NO_INIT); 662 // R5: crashs when pushing B_CONTAINS/B_BEGINS/ENDS_WITH on an empty stack 663 #if TEST_R5 664 if (op < B_CONTAINS || op > B_ENDS_WITH) 665 #endif 666 TestPredicate(OpNode(op, NULL, NULL), B_OK, B_NO_INIT); 667 TestPredicate(OpNode(op, 668 new AttributeNode("attribute"), 669 new DateNode("22 May 2002") 670 ).addChild(new Int32Node(42)), B_OK, B_NO_INIT); 671 } 672 673 // PredicateTest 674 void 675 QueryTest::PredicateTest() 676 { 677 // tests: 678 // * Push*() 679 // * Set/GetPredicate(), PredicateLength() 680 // empty predicate 681 NextSubTest(); 682 char buffer[1024]; 683 { 684 Query query; 685 BString predicate; 686 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_NO_INIT ); 687 } 688 { 689 Query query; 690 CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer)) 691 == B_NO_INIT ); 692 } 693 // one element predicates 694 NextSubTest(); 695 TestPredicate(Int32Node(42)); 696 TestPredicate(UInt32Node(42)); 697 TestPredicate(Int64Node(42)); 698 // R5: buggy PushUInt64() implementation. 699 #if !TEST_R5 700 TestPredicate(UInt64Node(42)); 701 #endif 702 TestPredicate(FloatNode(42)); 703 TestPredicate(DoubleNode(42)); 704 TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or " 705 "% not!")); 706 TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or " 707 "% not!", true)); 708 TestPredicate(DateNode("+15 min")); 709 TestPredicate(DateNode("22 May 2002")); 710 TestPredicate(DateNode("tomorrow")); 711 TestPredicate(DateNode("17:57")); 712 TestPredicate(DateNode("invalid date"), B_BAD_VALUE); 713 TestPredicate(AttributeNode("some attribute")); 714 // operators 715 NextSubTest(); 716 TestOperator(B_EQ); 717 TestOperator(B_GT); 718 TestOperator(B_GE); 719 TestOperator(B_LT); 720 TestOperator(B_LE); 721 TestOperator(B_NE); 722 TestOperator(B_CONTAINS); 723 TestOperator(B_BEGINS_WITH); 724 TestOperator(B_ENDS_WITH); 725 TestOperator(B_AND); 726 TestOperator(B_OR); 727 { 728 // B_NOT 729 TestPredicate(OpNode(B_NOT, new AttributeNode("attribute"))); 730 TestPredicate(OpNode(B_NOT, new Int32Node(42))); 731 TestPredicate(OpNode(B_NOT, new StringNode("some string"))); 732 TestPredicate(OpNode(B_NOT, new StringNode("some string", true))); 733 TestPredicate(OpNode(B_NOT, new DateNode("22 May 2002"))); 734 TestPredicate(OpNode(B_NOT, NULL), B_OK, B_NO_INIT); 735 } 736 // well formed, legal predicate 737 NextSubTest(); 738 TestPredicate(OpNode(B_AND, 739 new OpNode(B_CONTAINS, 740 new AttributeNode("attribute"), 741 new StringNode("hello") 742 ), 743 new OpNode(B_OR, 744 new OpNode(B_NOT, 745 new OpNode(B_EQ, 746 new AttributeNode("attribute2"), 747 new UInt32Node(7) 748 ), 749 NULL 750 ), 751 new OpNode(B_GE, 752 new AttributeNode("attribute3"), 753 new DateNode("20 May 2002") 754 ) 755 ) 756 )); 757 // well formed, illegal predicate 758 NextSubTest(); 759 TestPredicate(OpNode(B_EQ, 760 new StringNode("hello"), 761 new OpNode(B_LE, 762 new OpNode(B_NOT, 763 new Int32Node(17), 764 NULL 765 ), 766 new DateNode("20 May 2002") 767 ) 768 )); 769 // ill formed predicates 770 // Some have already been tested in TestOperator, so we only test a few 771 // special ones. 772 NextSubTest(); 773 TestPredicate(ListNode(new Int32Node(42), new StringNode("hello!")), 774 B_OK, B_NO_INIT); 775 TestPredicate(OpNode(B_EQ, 776 new StringNode("hello"), 777 new OpNode(B_NOT, NULL) 778 ), B_OK, B_NO_INIT); 779 // precedence Push*() over SetPredicate() 780 NextSubTest(); 781 { 782 Query query; 783 OpNode predicate1(B_CONTAINS, 784 new AttributeNode("attribute"), 785 new StringNode("hello") 786 ); 787 StringNode predicate2("I'm the loser. :´-("); 788 CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); 789 CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) 790 == B_OK ); 791 BString predicate; 792 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); 793 CPPUNIT_ASSERT( predicate == predicate1.toString() ); 794 } 795 // GetPredicate() clears the stack 796 NextSubTest(); 797 { 798 Query query; 799 OpNode predicate1(B_CONTAINS, 800 new AttributeNode("attribute"), 801 new StringNode("hello") 802 ); 803 StringNode predicate2("I'm the winner. :-)"); 804 CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); 805 BString predicate; 806 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); 807 CPPUNIT_ASSERT( predicate == predicate1.toString() ); 808 CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) 809 == B_OK ); 810 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); 811 CPPUNIT_ASSERT( predicate == predicate2.toString() ); 812 } 813 // PredicateLength() clears the stack 814 NextSubTest(); 815 { 816 Query query; 817 OpNode predicate1(B_CONTAINS, 818 new AttributeNode("attribute"), 819 new StringNode("hello") 820 ); 821 StringNode predicate2("I'm the winner. :-)"); 822 CPPUNIT_ASSERT( predicate1.push(query) == B_OK ); 823 CPPUNIT_ASSERT( (int32)query.PredicateLength() 824 == predicate1.toString().Length() + 1 ); 825 CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String()) 826 == B_OK ); 827 BString predicate; 828 CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK ); 829 CPPUNIT_ASSERT( predicate == predicate2.toString() ); 830 } 831 // SetPredicate(), Push*() fail after Fetch() 832 NextSubTest(); 833 { 834 Query query; 835 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 836 == B_OK ); 837 BVolume volume(dev_for_path("/boot")); 838 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 839 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 840 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 841 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExistEither\"") 842 == B_NOT_ALLOWED ); 843 // R5: Push*()ing a new predicate does work, though it doesn't make any sense 844 #if TEST_R5 845 CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_OK ); 846 CPPUNIT_ASSERT( query.PushValue((int32)42) == B_OK ); 847 CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_OK ); 848 CPPUNIT_ASSERT( query.PushValue((int64)42) == B_OK ); 849 CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_OK ); 850 CPPUNIT_ASSERT( query.PushValue((float)42) == B_OK ); 851 CPPUNIT_ASSERT( query.PushValue((double)42) == B_OK ); 852 CPPUNIT_ASSERT( query.PushValue("hello") == B_OK ); 853 CPPUNIT_ASSERT( query.PushAttr("attribute") == B_OK ); 854 CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_OK ); 855 #else 856 CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_NOT_ALLOWED ); 857 CPPUNIT_ASSERT( query.PushValue((int32)42) == B_NOT_ALLOWED ); 858 CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_NOT_ALLOWED ); 859 CPPUNIT_ASSERT( query.PushValue((int64)42) == B_NOT_ALLOWED ); 860 CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_NOT_ALLOWED ); 861 CPPUNIT_ASSERT( query.PushValue((float)42) == B_NOT_ALLOWED ); 862 CPPUNIT_ASSERT( query.PushValue((double)42) == B_NOT_ALLOWED ); 863 CPPUNIT_ASSERT( query.PushValue("hello") == B_NOT_ALLOWED ); 864 CPPUNIT_ASSERT( query.PushAttr("attribute") == B_NOT_ALLOWED ); 865 CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_NOT_ALLOWED ); 866 #endif 867 } 868 // SetPredicate(): bad args 869 // R5: crashes when passing NULL to Set/GetPredicate() 870 #if !TEST_R5 871 NextSubTest(); 872 { 873 Query query; 874 CPPUNIT_ASSERT( query.SetPredicate(NULL) == B_BAD_VALUE ); 875 CPPUNIT_ASSERT( query.SetPredicate("hello") == B_OK ); 876 CPPUNIT_ASSERT( query.GetPredicate(NULL) == B_BAD_VALUE ); 877 CPPUNIT_ASSERT( query.GetPredicate(NULL, 10) == B_BAD_VALUE ); 878 } 879 #endif 880 } 881 882 // ParameterTest 883 void 884 QueryTest::ParameterTest() 885 { 886 // tests: 887 // * SetVolume, TargetDevice() 888 // * SetTarget(), IsLive() 889 890 // SetVolume(), TargetDevice() 891 // uninitialized BQuery 892 NextSubTest(); 893 { 894 BQuery query; 895 CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); 896 } 897 // NULL volume 898 // R5: crashs when passing a NULL BVolume 899 #if !TEST_R5 900 NextSubTest(); 901 { 902 BQuery query; 903 CPPUNIT_ASSERT( query.SetVolume(NULL) == B_BAD_VALUE ); 904 CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); 905 } 906 #endif 907 // invalid volume 908 NextSubTest(); 909 { 910 BQuery query; 911 BVolume volume(-2); 912 CPPUNIT_ASSERT( volume.InitCheck() == B_BAD_VALUE ); 913 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 914 CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR ); 915 } 916 // valid volume 917 NextSubTest(); 918 { 919 BQuery query; 920 dev_t device = dev_for_path("/boot"); 921 BVolume volume(device); 922 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 923 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 924 CPPUNIT_ASSERT( query.TargetDevice() == device ); 925 } 926 927 // SetTarget(), IsLive() 928 // uninitialized BQuery 929 NextSubTest(); 930 { 931 BQuery query; 932 CPPUNIT_ASSERT( query.IsLive() == false ); 933 } 934 // uninitialized BMessenger 935 NextSubTest(); 936 { 937 BQuery query; 938 BMessenger messenger; 939 CPPUNIT_ASSERT( messenger.IsValid() == false ); 940 CPPUNIT_ASSERT( query.SetTarget(messenger) == B_BAD_VALUE ); 941 CPPUNIT_ASSERT( query.IsLive() == false ); 942 } 943 // valid BMessenger 944 NextSubTest(); 945 { 946 BQuery query; 947 BMessenger messenger(&fApplication->Handler()); 948 CPPUNIT_ASSERT( messenger.IsValid() == true ); 949 CPPUNIT_ASSERT( query.SetTarget(messenger) == B_OK ); 950 CPPUNIT_ASSERT( query.IsLive() == true ); 951 } 952 953 // SetVolume/Target() fail after Fetch() 954 NextSubTest(); 955 { 956 Query query; 957 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 958 == B_OK ); 959 BVolume volume(dev_for_path("/boot")); 960 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 961 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 962 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 963 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_NOT_ALLOWED ); 964 BMessenger messenger(&fApplication->Handler()); 965 CPPUNIT_ASSERT( messenger.IsValid() == true ); 966 CPPUNIT_ASSERT( query.SetTarget(messenger) == B_NOT_ALLOWED ); 967 } 968 969 // Fetch() fails without a valid volume set 970 NextSubTest(); 971 { 972 Query query; 973 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 974 == B_OK ); 975 CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); 976 } 977 } 978 979 // TestFetchPredicateInit 980 static 981 void 982 TestFetchPredicateInit(Query &query, TestSet &testSet, const char *mountPoint, 983 const char *predicate, QueryTestEntry **entries, 984 int32 entryCount) 985 { 986 // init the query 987 CPPUNIT_ASSERT( query.SetPredicate(predicate) == B_OK ); 988 BVolume volume(dev_for_path(mountPoint)); 989 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 990 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 991 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 992 // init the test set 993 testSet.clear(); 994 for (int32 i = 0; i < entryCount; i++) 995 testSet.add(entries[i]->path); 996 } 997 998 999 // TestFetchPredicate 1000 static 1001 void 1002 TestFetchPredicate(const char *mountPoint, const char *predicate, 1003 QueryTestEntry **entries, int32 entryCount) 1004 { 1005 // GetNextEntry() 1006 { 1007 Query query; 1008 TestSet testSet; 1009 TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, 1010 entryCount); 1011 BEntry entry; 1012 while (query.GetNextEntry(&entry) == B_OK) { 1013 // Haiku supports rewinding queries, R5 does not. 1014 #ifdef TEST_R5 1015 CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); 1016 #endif 1017 CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); 1018 BPath path; 1019 CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); 1020 CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); 1021 CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); 1022 } 1023 CPPUNIT_ASSERT( testSet.testDone() == true ); 1024 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); 1025 } 1026 // GetNextRef() 1027 { 1028 Query query; 1029 TestSet testSet; 1030 TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, 1031 entryCount); 1032 entry_ref ref; 1033 while (query.GetNextRef(&ref) == B_OK) { 1034 // Haiku supports rewinding queries, R5 does not. 1035 #ifdef TEST_R5 1036 CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); 1037 #endif 1038 CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); 1039 BPath path(&ref); 1040 CPPUNIT_ASSERT( path.InitCheck() == B_OK ); 1041 CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); 1042 } 1043 CPPUNIT_ASSERT( testSet.testDone() == true ); 1044 CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); 1045 } 1046 // GetNextDirents() 1047 { 1048 Query query; 1049 TestSet testSet; 1050 TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, 1051 entryCount); 1052 size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; 1053 char buffer[bufSize]; 1054 dirent *ents = (dirent *)buffer; 1055 while (query.GetNextDirents(ents, bufSize, 1) == 1) { 1056 // Haiku supports rewinding queries, R5 does not. 1057 #ifdef TEST_R5 1058 CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); 1059 #endif 1060 CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); 1061 entry_ref ref(ents->d_pdev, ents->d_pino, ents->d_name); 1062 BPath path(&ref); 1063 CPPUNIT_ASSERT( path.InitCheck() == B_OK ); 1064 CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); 1065 } 1066 CPPUNIT_ASSERT( testSet.testDone() == true ); 1067 CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); 1068 } 1069 // interleaving use of the different methods 1070 { 1071 Query query; 1072 TestSet testSet; 1073 TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries, 1074 entryCount); 1075 size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; 1076 char buffer[bufSize]; 1077 dirent *ents = (dirent *)buffer; 1078 entry_ref ref; 1079 BEntry entry; 1080 while (query.GetNextDirents(ents, bufSize, 1) == 1) { 1081 // Haiku supports rewinding queries, R5 does not. 1082 #ifdef TEST_R5 1083 CPPUNIT_ASSERT( query.Rewind() == B_ERROR ); 1084 #endif 1085 CPPUNIT_ASSERT( query.CountEntries() == B_ERROR ); 1086 entry_ref entref(ents->d_pdev, ents->d_pino, ents->d_name); 1087 BPath entpath(&entref); 1088 CPPUNIT_ASSERT( entpath.InitCheck() == B_OK ); 1089 CPPUNIT_ASSERT( testSet.test(entpath.Path()) == true ); 1090 if (query.GetNextRef(&ref) == B_OK) { 1091 BPath refpath(&ref); 1092 CPPUNIT_ASSERT( refpath.InitCheck() == B_OK ); 1093 CPPUNIT_ASSERT( testSet.test(refpath.Path()) == true ); 1094 } 1095 if (query.GetNextEntry(&entry) == B_OK) { 1096 BPath path; 1097 CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); 1098 CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); 1099 CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); 1100 } 1101 } 1102 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); 1103 CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); 1104 CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); 1105 } 1106 } 1107 1108 // FetchTest 1109 void 1110 QueryTest::FetchTest() 1111 { 1112 // tests: 1113 // * Clear()/Fetch() 1114 // * BEntryList interface 1115 1116 // Fetch() 1117 // uninitialized BQuery 1118 NextSubTest(); 1119 { 1120 Query query; 1121 CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); 1122 } 1123 // incompletely initialized BQuery (no predicate) 1124 NextSubTest(); 1125 { 1126 Query query; 1127 BVolume volume(dev_for_path("/boot")); 1128 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1129 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1130 CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); 1131 } 1132 // incompletely initialized BQuery (no volume) 1133 NextSubTest(); 1134 { 1135 Query query; 1136 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1137 == B_OK ); 1138 CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); 1139 } 1140 // incompletely initialized BQuery (invalid predicate) 1141 NextSubTest(); 1142 { 1143 Query query; 1144 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"&&") 1145 == B_OK ); 1146 BVolume volume(dev_for_path("/boot")); 1147 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1148 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1149 CPPUNIT_ASSERT( query.Fetch() == B_BAD_VALUE ); 1150 } 1151 // initialized BQuery, Fetch() twice 1152 NextSubTest(); 1153 { 1154 Query query; 1155 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1156 == B_OK ); 1157 BVolume volume(dev_for_path("/boot")); 1158 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1159 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1160 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1161 CPPUNIT_ASSERT( query.Fetch() == B_NOT_ALLOWED ); 1162 } 1163 // initialized BQuery, successful Fetch(), different predicates 1164 createVolume(testVolumeImage, testMountPoint, 2); 1165 fVolumeCreated = true; 1166 create_test_entries(allTestEntries, allTestEntryCount); 1167 // ... all files 1168 NextSubTest(); 1169 { 1170 QueryTestEntry *entries[] = { 1171 &file11, &file12, &file21, &file22, &file31, &file32, &file1, 1172 &file2, &file3 1173 }; 1174 const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); 1175 TestFetchPredicate(testMountPoint, "name=\"file*\"", entries, 1176 entryCount); 1177 } 1178 // ... all entries containing a "l" 1179 NextSubTest(); 1180 { 1181 QueryTestEntry *entries[] = { 1182 &file11, &file12, &link11, &file21, &file22, &link21, &file31, 1183 &file32, &link31, &file1, &file2, &file3, &link1, &link2, &link3 1184 }; 1185 const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); 1186 TestFetchPredicate(testMountPoint, "name=\"*l*\"", entries, 1187 entryCount); 1188 } 1189 // ... all entries ending on "2" 1190 NextSubTest(); 1191 { 1192 QueryTestEntry *entries[] = { 1193 &subdir12, &file12, &dir2, &subdir22, &file22, &subdir32, &file32, 1194 &file2, &link2 1195 }; 1196 const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); 1197 TestFetchPredicate(testMountPoint, "name=\"*2\"", entries, 1198 entryCount); 1199 } 1200 1201 // Clear() 1202 // uninitialized BQuery 1203 NextSubTest(); 1204 { 1205 Query query; 1206 CPPUNIT_ASSERT( query.Clear() == B_OK ); 1207 } 1208 // initialized BQuery, Fetch(), Clear(), Fetch() 1209 NextSubTest(); 1210 { 1211 Query query; 1212 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1213 == B_OK ); 1214 BVolume volume(dev_for_path("/boot")); 1215 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1216 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1217 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1218 CPPUNIT_ASSERT( query.Clear() == B_OK ); 1219 CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT ); 1220 } 1221 // initialized BQuery, Fetch(), Clear(), re-init, Fetch() 1222 NextSubTest(); 1223 { 1224 Query query; 1225 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1226 == B_OK ); 1227 BVolume volume(dev_for_path("/boot")); 1228 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1229 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1230 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1231 CPPUNIT_ASSERT( query.Clear() == B_OK ); 1232 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1233 == B_OK ); 1234 CPPUNIT_ASSERT( volume.SetTo(dev_for_path("/boot")) == B_OK ); 1235 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1236 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1237 } 1238 1239 // BEntryList interface: 1240 // empty queries 1241 NextSubTest(); 1242 { 1243 Query query; 1244 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1245 == B_OK ); 1246 BVolume volume(dev_for_path("/boot")); 1247 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1248 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1249 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1250 BEntry entry; 1251 entry_ref ref; 1252 size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; 1253 char buffer[bufSize]; 1254 dirent *ents = (dirent *)buffer; 1255 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); 1256 CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND ); 1257 CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 ); 1258 } 1259 // uninitialized queries 1260 NextSubTest(); 1261 { 1262 Query query; 1263 BEntry entry; 1264 entry_ref ref; 1265 size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; 1266 char buffer[bufSize]; 1267 dirent *ents = (dirent *)buffer; 1268 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_FILE_ERROR ); 1269 CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_FILE_ERROR ); 1270 CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) 1271 == B_FILE_ERROR ); 1272 } 1273 // bad args 1274 NextSubTest(); 1275 { 1276 Query query; 1277 CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"") 1278 == B_OK ); 1279 BVolume volume(dev_for_path("/boot")); 1280 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1281 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1282 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1283 size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10; 1284 // R5: crashs when passing a NULL BEntry or entry_ref 1285 #if !TEST_R5 1286 CPPUNIT_ASSERT( query.GetNextEntry(NULL) == B_BAD_VALUE ); 1287 CPPUNIT_ASSERT( query.GetNextRef(NULL) == B_BAD_VALUE ); 1288 #endif 1289 CPPUNIT_ASSERT( equals(query.GetNextDirents(NULL, bufSize, 1), 1290 B_BAD_ADDRESS, B_BAD_VALUE) ); 1291 } 1292 } 1293 1294 // AddLiveEntries 1295 void 1296 QueryTest::AddLiveEntries(QueryTestEntry **entries, int32 entryCount, 1297 QueryTestEntry **queryEntries, int32 queryEntryCount) 1298 { 1299 create_test_entries(entries, entryCount); 1300 for (int32 i = 0; i < entryCount; i++) { 1301 QueryTestEntry *entry = entries[i]; 1302 BNode node(entry->cpath); 1303 CPPUNIT_ASSERT( node.InitCheck() == B_OK ); 1304 node_ref nref; 1305 CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK ); 1306 entry->node = nref.node; 1307 entry_ref ref; 1308 CPPUNIT_ASSERT( get_ref_for_path(entry->cpath, &ref) == B_OK ); 1309 entry->directory = ref.directory; 1310 entry->name = ref.name; 1311 } 1312 CheckUpdateMessages(B_ENTRY_CREATED, queryEntries, queryEntryCount); 1313 } 1314 1315 // RemoveLiveEntries 1316 void 1317 QueryTest::RemoveLiveEntries(QueryTestEntry **entries, int32 entryCount, 1318 QueryTestEntry **queryEntries, 1319 int32 queryEntryCount) 1320 { 1321 delete_test_entries(entries, entryCount); 1322 CheckUpdateMessages(B_ENTRY_REMOVED, queryEntries, queryEntryCount); 1323 for (int32 i = 0; i < entryCount; i++) { 1324 QueryTestEntry *entry = entries[i]; 1325 entry->directory = -1; 1326 entry->node = -1; 1327 entry->name = ""; 1328 } 1329 } 1330 1331 // CheckUpdateMessages 1332 void 1333 QueryTest::CheckUpdateMessages(uint32 opcode, QueryTestEntry **entries, 1334 int32 entryCount) 1335 { 1336 1337 // wait for the messages 1338 snooze(100000); 1339 if (fApplication) { 1340 BMessageQueue &queue = fApplication->Handler().Queue(); 1341 CPPUNIT_ASSERT( queue.Lock() ); 1342 try { 1343 int32 entryNum = 0; 1344 while (BMessage *_message = queue.NextMessage()) { 1345 BMessage message(*_message); 1346 delete _message; 1347 CPPUNIT_ASSERT( entryNum < entryCount ); 1348 QueryTestEntry *entry = entries[entryNum]; 1349 CPPUNIT_ASSERT( message.what == B_QUERY_UPDATE ); 1350 uint32 msgOpcode; 1351 CPPUNIT_ASSERT( message.FindInt32("opcode", (int32*)&msgOpcode) 1352 == B_OK ); 1353 CPPUNIT_ASSERT( msgOpcode == opcode ); 1354 dev_t device; 1355 CPPUNIT_ASSERT( message.FindInt32("device", &device) 1356 == B_OK ); 1357 CPPUNIT_ASSERT( device == dev_for_path(testMountPoint) ); 1358 ino_t directory; 1359 CPPUNIT_ASSERT( message.FindInt64("directory", &directory) 1360 == B_OK ); 1361 CPPUNIT_ASSERT( directory == entry->directory ); 1362 ino_t node; 1363 CPPUNIT_ASSERT( message.FindInt64("node", &node) 1364 == B_OK ); 1365 CPPUNIT_ASSERT( node == entry->node ); 1366 if (opcode == B_ENTRY_CREATED) { 1367 const char *name; 1368 CPPUNIT_ASSERT( message.FindString("name", &name) 1369 == B_OK ); 1370 CPPUNIT_ASSERT( entry->name == name ); 1371 } 1372 entryNum++; 1373 } 1374 CPPUNIT_ASSERT( entryNum == entryCount ); 1375 } catch (CppUnit::Exception exception) { 1376 queue.Unlock(); 1377 throw exception; 1378 } 1379 queue.Unlock(); 1380 } 1381 } 1382 1383 // LiveTest 1384 void 1385 QueryTest::LiveTest() 1386 { 1387 // tests: 1388 // * live queries 1389 CPPUNIT_ASSERT( fApplication != NULL ); 1390 createVolume(testVolumeImage, testMountPoint, 2); 1391 fVolumeCreated = true; 1392 create_test_entries(allTestEntries, allTestEntryCount); 1393 BMessenger target(&fApplication->Handler()); 1394 1395 // empty query, add some files, remove some files 1396 NextSubTest(); 1397 { 1398 Query query; 1399 CPPUNIT_ASSERT( query.SetPredicate("name=\"*Argh\"") 1400 == B_OK ); 1401 BVolume volume(dev_for_path(testMountPoint)); 1402 CPPUNIT_ASSERT( volume.InitCheck() == B_OK ); 1403 CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK ); 1404 CPPUNIT_ASSERT( query.SetTarget(target) == B_OK ); 1405 CPPUNIT_ASSERT( query.Fetch() == B_OK ); 1406 BEntry entry; 1407 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); 1408 // the test entries 1409 QueryTestEntry testDir1(dir1 + "testDirArgh", B_DIRECTORY_NODE); 1410 QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE); 1411 QueryTestEntry testFile1(subdir21 + "testFileArgh", B_FILE_NODE); 1412 QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE); 1413 QueryTestEntry testLink1(subdir32 + "testLinkArgh", B_SYMLINK_NODE, 1414 &file11); 1415 QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE, 1416 &file11); 1417 QueryTestEntry *entries[] = { 1418 &testDir1, &testDir2, &testFile1, &testFile2, 1419 &testLink1, &testLink2 1420 }; 1421 int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); 1422 QueryTestEntry *queryEntries[] = { 1423 &testDir1, &testFile1, &testLink1 1424 }; 1425 int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*); 1426 AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount); 1427 RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount); 1428 } 1429 // non-empty query, add some files, remove some files 1430 NextSubTest(); 1431 { 1432 Query query; 1433 TestSet testSet; 1434 CPPUNIT_ASSERT( query.SetTarget(target) == B_OK ); 1435 QueryTestEntry *initialEntries[] = { 1436 &file11, &file12, &file21, &file22, &file31, &file32, &file1, 1437 &file2, &file3 1438 }; 1439 int32 initialEntryCount 1440 = sizeof(initialEntries) / sizeof(QueryTestEntry*); 1441 TestFetchPredicateInit(query, testSet, testMountPoint, 1442 "name=\"*ile*\"", initialEntries, 1443 initialEntryCount); 1444 BEntry entry; 1445 while (query.GetNextEntry(&entry) == B_OK) { 1446 BPath path; 1447 CPPUNIT_ASSERT( entry.InitCheck() == B_OK ); 1448 CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK ); 1449 CPPUNIT_ASSERT( testSet.test(path.Path()) == true ); 1450 } 1451 CPPUNIT_ASSERT( testSet.testDone() == true ); 1452 CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND ); 1453 // the test entries 1454 QueryTestEntry testDir1(dir1 + "testDir1", B_DIRECTORY_NODE); 1455 QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE); 1456 QueryTestEntry testFile1(subdir21 + "testFile1", B_FILE_NODE); 1457 QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE); 1458 QueryTestEntry testLink1(subdir32 + "testLink1", B_SYMLINK_NODE, 1459 &file11); 1460 QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE, 1461 &file11); 1462 QueryTestEntry testFile3(subdir32 + "testFile3", B_FILE_NODE); 1463 QueryTestEntry *entries[] = { 1464 &testDir1, &testDir2, &testFile1, &testFile2, 1465 &testLink1, &testLink2, &testFile3 1466 }; 1467 int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*); 1468 QueryTestEntry *queryEntries[] = { 1469 &testFile1, &testFile2, &testFile3 1470 }; 1471 int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*); 1472 AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount); 1473 RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount); 1474 } 1475 } 1476 1477 1478 1479 1480 1481