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