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