1// MimeTypeTest.cpp 2 3#include <ctype.h> // For tolower() 4#include <fcntl.h> // open() 5#include <map> 6#include <queue> 7#include <stdio.h> 8#include <string.h> // For memcmp() 9#include <string> 10#include <unistd.h> 11#include <vector> 12 13 14#include <fs_attr.h> // For struct attr_info 15#include <fs_info.h> 16#include <Application.h> 17#include <Bitmap.h> 18#include <DataIO.h> 19#include <Drivers.h> // B_GET_ICON, device_icon 20#include <Message.h> 21#include <Mime.h> 22#if !TEST_R5 23 #include <mime/database_support.h> 24#endif 25#include <Path.h> // Only needed for entry_ref dumps 26#include <StorageKit.h> 27#include <String.h> 28#include <storage_support.h> // for split_path() 29 30#include "TestShell.h" 31#include "TestApp.h" 32#include "TestUtils.h" 33 34#include "MimeTypeTest.h" 35 36// MIME database directories 37static const char *testDir = "/tmp/mimeTestDir"; 38static const char *R5DatabaseDir = "/boot/home/config/settings/beos_mime"; 39#if TEST_R5 40static std::string mimeDatabaseDir = R5DatabaseDir; 41#else 42static std::string mimeDatabaseDir = BPrivate::Storage::Mime::kDatabaseDir; 43#endif 44 45// MIME Test Types 46// testType and testTypeApp are Delete()d after each test. 47static const char *testType = "text/x-vnd.obos-Storage-Kit-Test"; 48static const char *testType1 = "text/x-vnd.obos-Storage-Kit-Test1"; 49static const char *testType2 = "text/x-vnd.obos-Storage-Kit-Test2"; 50static const char *testType3 = "text/x-vnd.obos-Storage-Kit-Test3"; 51static const char *testType4 = "text/x-vnd.obos-Storage-Kit-Test4"; 52static const char *testType5 = "text/x-vnd.obos-Storage-Kit-Test5"; 53static const char *testTypeApp = "application/StorageKit-Test"; 54static const char *testTypeApp1 = "application/" 55 "x-vnd.obos.mime.test.test1"; 56static const char *testTypeApp2 = "application/" 57 "x-vnd.obos.mime.test.test2"; 58static const char *testTypeApp3 = "application/" 59 "x-vnd.obos.mime.test.test3"; 60static const char *testTypeInvalid = "text/Are spaces valid?"; 61static const char *testTypeSuperValid = "valid-but-fake-supertype"; 62static const char *testTypeSuperInvalid = "?????"; 63 64// Real MIME types 65static const char *wildcardType = "application/octet-stream"; 66static const char *applicationSupertype = "application"; 67 68// Application Paths 69static const char *testApp = "/boot/beos/apps/SoundRecorder"; 70static const char *testApp2 = "/boot/beos/apps/CDPlayer"; 71static const char *fakeTestApp = "/__this_isn't_likely_to_exist__"; 72 73// BMessage field names 74static const char *applicationsField = "applications"; 75static const char *typeField = "type"; 76static const char *typesField = "types"; 77static const char *fileExtField = "extensions"; 78static const char *attrInfoField_Name = "attr:name"; 79static const char *attrInfoField_PublicName = "attr:public_name"; 80static const char *attrInfoField_Type = "attr:type"; 81static const char *attrInfoField_Viewable = "attr:viewable"; 82static const char *attrInfoField_Editable = "attr:editable"; 83 84// Descriptions 85static const char *testDescr = "Just a test, nothing more :-)"; 86static const char *testDescr2 = "Another amazing test string"; 87static const char *longDescr = 88"This description is longer than B_MIME_TYPE_LENGTH, which is quite useful for certain things... " 89"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 90"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 91"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" 92"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; 93// Signatures 94static const char *testSig = "application/x-vnd.obos.mime-type-test"; 95static const char *testSig2 = "application/x-vnd.obos.mime-type-test-2"; 96static const char *longSig = "application/x-vnd.obos.mime-type-test-long." 97"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 98"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 99"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" 100"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; 101 102// Declarations for handy dandy private functions 103static bool operator==(BBitmap &bmp1, BBitmap &bmp2); 104static bool operator!=(BBitmap &bmp1, BBitmap &bmp2); 105static bool operator==(BMessage &msg1, BMessage &msg2); 106static bool operator!=(BMessage &msg1, BMessage &msg2); 107static void fill_bitmap(BBitmap &bmp, char value); 108//static void dump_bitmap(BBitmap &bmp, char *name = "bmp"); 109#if !TEST_R5 110 static status_t reduce_color_depth(BBitmap &src32, BBitmap &dest8); 111#endif 112//static void dump_ref(entry_ref *ref, char* name = "ref"); 113static void to_lower(const char *str, std::string &result); 114static std::string to_lower(const char *str); 115static void remove_type(const char *type, const char *databaseDir = mimeDatabaseDir.c_str()); 116static bool type_exists(const char *type, const char *databaseDir = mimeDatabaseDir.c_str()); 117class ContainerAdapter; 118class SetAdapter; 119class QueueAdapter; 120void FillWithMimeTypes(ContainerAdapter &container, BMessage &typeMessage, const char* fieldName); 121 // Used to add all the types in a BMessage from GetInstalled*Types() to some 122 // sort of container object (via an adapter to support differing interfaces). 123 124// Custom TestSuite class to allow us to make a copy of the MIME database directory 125// before running all the BMimeType tests 126class MimeTypeTestSuite : public CppUnit::TestSuite { 127public: 128 MimeTypeTestSuite() : CppUnit::TestSuite(), fMimeDirExisted(false) {} 129 virtual void setUp() 130 { 131 // If we're using a directory other than the R5 MIME database directory, make 132 // sure that directory exists. If not, make a complete copy of the R5 database 133 // directory. 134 if (mimeDatabaseDir != R5DatabaseDir) { 135 BEntry dir(mimeDatabaseDir.c_str()); 136 if (dir.InitCheck() != B_OK || !dir.Exists()) { 137 if (BTestShell::GlobalBeVerbose()) 138 cout << "(Making a copy of your MIME database at '" + mimeDatabaseDir + "')" << endl; 139 std::string cmd = std::string("copyattr -d -r -- ") + R5DatabaseDir 140 + " " + mimeDatabaseDir; 141 ExecCommand(cmd.c_str()); 142 } else { 143 fMimeDirExisted = true; 144 if (BTestShell::GlobalBeVerbose()) 145 cout << "(Using existing copy of MIME database in '" + mimeDatabaseDir + "')" << endl; 146 } 147 } 148 } 149 150 virtual void tearDown() 151 { 152 if (mimeDatabaseDir != R5DatabaseDir && !fMimeDirExisted) { 153 if (BTestShell::GlobalBeVerbose()) 154 cout << "(Removing copy of MIME database in '" + mimeDatabaseDir + "')" << endl; 155 std::string cmd = std::string("rm -rf ") + mimeDatabaseDir; 156 ExecCommand(cmd.c_str()); 157 } 158 } 159 160 virtual void run( CppUnit::TestResult *result ) 161 { 162 setUp(); 163 CppUnit::TestSuite::run(result); 164 tearDown(); 165 } 166private: 167 bool fMimeDirExisted; 168}; 169 170// Suite 171CppUnit::Test* 172MimeTypeTest::Suite() { 173 MimeTypeTestSuite *suite = new MimeTypeTestSuite(); 174 typedef CppUnit::TestCaller<MimeTypeTest> TC; 175 176 // Tyler 177 suite->addTest( new TC("BMimeType::Install/Delete Test", 178 &MimeTypeTest::InstallDeleteTest) ); 179 suite->addTest( new TC("BMimeType::App Hint Test", 180 &MimeTypeTest::AppHintTest) ); 181 suite->addTest( new TC("BMimeType::Attribute Info Test", 182 &MimeTypeTest::AttrInfoTest) ); 183 suite->addTest( new TC("BMimeType::Long Description Test", 184 &MimeTypeTest::LongDescriptionTest) ); 185 suite->addTest( new TC("BMimeType::Short Description Test", 186 &MimeTypeTest::ShortDescriptionTest) ); 187 suite->addTest( new TC("BMimeType::File Extensions Test", 188 &MimeTypeTest::FileExtensionsTest) ); 189 suite->addTest( new TC("BMimeType::Icon Test (Large)", 190 &MimeTypeTest::LargeIconTest) ); 191 suite->addTest( new TC("BMimeType::Icon Test (Mini)", 192 &MimeTypeTest::MiniIconTest) ); 193 suite->addTest( new TC("BMimeType::Icon For Type Test (Large)", 194 &MimeTypeTest::LargeIconForTypeTest) ); 195 suite->addTest( new TC("BMimeType::Icon For Type Test (Mini)", 196 &MimeTypeTest::MiniIconForTypeTest) ); 197 suite->addTest( new TC("BMimeType::Installed Types Test", 198 &MimeTypeTest::InstalledTypesTest) ); 199 suite->addTest( new TC("BMimeType::Preferred App Test", 200 &MimeTypeTest::PreferredAppTest) ); 201 suite->addTest( new TC("BMimeType::Supporting Apps Test", 202 &MimeTypeTest::SupportingAppsTest) ); 203 suite->addTest( new TC("BMimeType::Supported Types Test", 204 &MimeTypeTest::SupportedTypesTest) ); 205 suite->addTest( new TC("BMimeType::Wildcard Apps Test", 206 &MimeTypeTest::WildcardAppsTest) ); 207 208 // Ingo 209 suite->addTest( new TC("BMimeType::Initialization Test", 210 &MimeTypeTest::InitTest) ); 211 suite->addTest( new TC("BMimeType::MIME String Test", 212 &MimeTypeTest::StringTest) ); 213 suite->addTest( new TC("BMimeType::MIME Monitoring Test", 214 &MimeTypeTest::MonitoringTest) ); 215 suite->addTest( new TC("BMimeType::update_mime_info() Test", 216 &MimeTypeTest::UpdateMimeInfoTest) ); 217 suite->addTest( new TC("BMimeType::create_app_meta_mime() Test", 218 &MimeTypeTest::CreateAppMetaMimeTest) ); 219 suite->addTest( new TC("BMimeType::get_device_icon() Test", 220 &MimeTypeTest::GetDeviceIconTest) ); 221 suite->addTest( new TC("BMimeType::Sniffer Rule Test", 222 &MimeTypeTest::SnifferRuleTest) ); 223 suite->addTest( new TC("BMimeType::Sniffing Test", 224 &MimeTypeTest::SniffingTest) ); 225 226 227 return suite; 228} 229 230// Handy comparison operators for BBitmaps. The size and color depth 231// are compared first, followed by the bitmap data. 232bool 233operator==(BBitmap &bmp1, BBitmap &bmp2) { 234 if (bmp1.Bounds() == bmp2.Bounds()) { 235// printf("bmp== 1\n"); 236 if (bmp1.ColorSpace() == bmp2.ColorSpace()) { 237// printf("bmp== 2\n"); 238 char *data1 = (char*)bmp1.Bits(); 239 char *data2 = (char*)bmp2.Bits(); 240 // NOTE! It's possible that padding bits might not get copied verbatim, 241 // which could lead to unexpected failures. If things are acting weird, 242 // you might try the commented out code below (keeping in mind that it 243 // currently only works for 8-bit color depths). 244 for (int i = 0; i < bmp1.BitsLength(); data1++, data2++, i++) { 245 if (*data1 != *data2) { 246// printf("i == %d\n", i); 247 return false; 248 } 249 } 250/* for (int i = 0; i < bmp1.Bounds().IntegerHeight(); i++) { 251 for (int j = 0; j < bmp1.Bounds().IntegerWidth(); j++) { 252// printf("(%d, %d)", data1[(i * bmp1.BytesPerRow()) + j], data2[(i * bmp2.BytesPerRow()) + j]); 253 if (data1[(i * bmp1.BytesPerRow()) + j] != data2[(i * bmp2.BytesPerRow()) + j]) { 254 printf("fail at (%d, %d)\n", j, i); 255 return false; 256 } 257 } 258 }*/ 259 return true; 260 } else 261 return false; 262 } else 263 return false; 264} 265 266bool 267operator!=(BBitmap &bmp1, BBitmap &bmp2) { 268 return !(bmp1 == bmp2); 269} 270 271// Handy comparison operators for BMessages. The BMessages are checked field 272// by field, each of which is verified to be identical with respect to: type, 273// count, and data (all items). 274bool 275operator==(BMessage &msg1, BMessage &msg2) { 276 status_t err = B_OK; 277 278 // For now I'm ignoring the what fields...I shall deal with that later :-) 279 if (msg1.what != msg2.what) 280 return false; 281 282/* 283 printf("----------------------------------------------------------------------\n"); 284 msg1.PrintToStream(); 285 msg2.PrintToStream(); 286 printf("----------------------------------------------------------------------\n"); 287*/ 288 289 // Check the counts of field names 290 int count1, count2; 291 count1 = msg1.CountNames(B_ANY_TYPE); 292 count2 = msg2.CountNames(B_ANY_TYPE); 293 if (count1 != count2 && (count1 == 0 || count2 == 0)) 294 return false; 295 296 // Iterate over all the names in msg1 and check that the field 297 // with the same name exists in msg2, is of the same type, and 298 // contains identical data. 299 for (int i = 0; i < count1 && !err; i++) { 300 char *name; 301 type_code typeFound1, typeFound2; 302 int32 countFound1, countFound2; 303 304 // Check type and count info 305 err = msg1.GetInfo(B_ANY_TYPE, i, &name, &typeFound1, &countFound1); 306 if (!err) 307 err = msg2.GetInfo(name, &typeFound2, &countFound2); 308 if (!err) 309 err = (typeFound1 == typeFound2 && countFound1 == countFound2 ? B_OK : B_ERROR); 310 if (!err) { 311 // Check all the data items 312 for (int j = 0; j < countFound1; j++) { 313 void *data1, *data2; 314 ssize_t bytes1, bytes2; 315 316 err = msg1.FindData(name, typeFound1, j, (const void**)&data1, &bytes1); 317 if (!err) 318 err = msg2.FindData(name, typeFound2, j, (const void**)&data2, &bytes2); 319 if (!err) 320 err = (bytes1 == bytes2 && memcmp(data1, data2, bytes1) == 0 ? B_OK : B_ERROR); 321 } 322 } 323 } 324 325 return !err; 326} 327 328bool 329operator!=(BMessage &msg1, BMessage &msg2) { 330 return !(msg1 == msg2); 331} 332 333// Fills the bitmap data with the given character 334void 335fill_bitmap(BBitmap &bmp, char value) { 336 char *data = (char*)bmp.Bits(); 337 for (int i = 0; i < bmp.BitsLength(); data++, i++) { 338// printf("(%d -> ", *data); 339 *data = value; 340// printf("%d)", *data); 341 } 342// printf("\n"); 343} 344 345// Fills the bitmap data with the given character 346void 347fill_bitmap32(BBitmap &bmp, char r, char g, char b, char a) { 348 if (bmp.ColorSpace() == B_RGB32 || bmp.ColorSpace() == B_RGBA32) { 349 char *data = (char*)bmp.Bits(); 350 for (int i = 0; i+3 < bmp.BitsLength(); data += 4, i+= 4) { 351 data[0] = b; 352 data[1] = g; 353 data[2] = r; 354 data[3] = a; 355// printf("(%d,%d,%d,%d)", data[2], data[1], data[0], data[3]); 356 } 357// printf("\n"); 358 } 359} 360 361// Dumps the size, colorspace, and first data byte 362// of the bitmap to stdout 363/*void 364dump_bitmap(BBitmap &bmp, char *name = "bmp") { 365 printf("%s == (%ldx%ld, ", name, bmp.Bounds().IntegerWidth()+1, 366 bmp.Bounds().IntegerHeight()+1); 367 switch (bmp.ColorSpace()) { 368 case B_CMAP8: 369 printf("B_CMAP8"); 370 break; 371 372 case B_RGB32: 373 printf("B_RGB32"); 374 break; 375 376 case B_RGBA32: 377 printf("B_RGBA32"); 378 break; 379 380 default: 381 printf("%x", bmp.ColorSpace()); 382 break; 383 } 384 printf(", %d, [", *(char*)bmp.Bits()); 385 char *data = (char*)bmp.Bits(); 386 for (int i = 0; i < bmp.BitsLength() && i < 20; data++, i++) 387 printf("%d,", *data); 388 printf("]\n"); 389}*/ 390 391// Uses BBitmap::SetBits() to convert the B_RGB32 bitmap in src32 392// to a B_CMAP8 bitmap in dest8 393#if !TEST_R5 394status_t 395reduce_color_depth(BBitmap &src32, BBitmap &dest8) 396{ 397 status_t err = (src32.ColorSpace() == B_RGB32 398 && dest8.ColorSpace() == B_CMAP8 399 && src32.InitCheck() == B_OK 400 && dest8.InitCheck() == B_OK 401 && src32.Bounds() == dest8.Bounds()) 402 ? B_OK 403 : B_BAD_VALUE; 404 if (!err) { 405 // Set each pixel individually, since SetBits() for B_RGB32 takes 406 // 24-bit rgb pixel data... 407 char *data = (char*)src32.Bits(); 408 for (int32 i = 0; i*4+3 < src32.BitsLength(); data += 4, i++) { 409 char rgb[3]; 410 rgb[0] = data[2]; // red 411 rgb[1] = data[1]; // green 412 rgb[2] = data[0]; // blue 413 dest8.SetBits(rgb, 3, i, B_RGB32); 414 } 415 } 416 return err; 417} 418#endif 419 420// IconHelper and IconForTypeHelper: 421// Adapter(?) classes needed to reuse icon tests among {Get,Set}Icon() and {Get,Set}IconForType() 422// What originally were meant to encapsulate the variations among calls to the various BMimeType 423// icon functions have now exploded into beefy helper classes with a bunch of BBitmap related 424// functionality as well. A lot of this stuff doesn't necessarily belong 425 426class IconHelper { 427public: 428 IconHelper(icon_size which) 429 : bmp1(BitmapBounds(which), B_CMAP8), 430 bmp2(BitmapBounds(which), B_CMAP8), 431 bmpTemp(BitmapBounds(which), B_CMAP8), 432 size(which) 433 { 434 // Initialize our three bitmaps to different "colors" 435 fill_bitmap(bmp1, 1); 436 fill_bitmap(bmp2, 2); 437 fill_bitmap(bmpTemp, 3); 438 } 439 440 virtual ~IconHelper() {} 441 442 // Returns the proper bitmap bounds for the given icon size 443 BRect BitmapBounds(icon_size isize) { 444 return isize == B_LARGE_ICON ? BRect(0,0,31,31) : BRect(0,0,15,15); 445 } 446 447 // Returns the proper bitmap bounds for this helper's icon size 448 BRect BitmapBounds() { 449 return BitmapBounds(size); 450 } 451 452 // Used to call the appropriate GetIcon[ForType] function 453 virtual status_t GetIcon(BMimeType &mime, BBitmap *icon) { 454 return mime.GetIcon(icon, size); 455 } 456 457 // Used to call the appropriate SetIcon[ForType] function 458 virtual status_t SetIcon(BMimeType &mime, BBitmap *icon) { 459 return mime.SetIcon(icon, size); 460 } 461 462 // Used to call the appropriate DeleteIcon[ForType] function 463 virtual status_t DeleteIcon(BMimeType &mime) { 464#if TEST_R5 465 return B_BAD_VALUE; 466#else 467 return mime.DeleteIcon(size); 468#endif 469 } 470 471 BBitmap* TempBitmap() { 472 return &bmpTemp; 473 } 474 475 BBitmap* Bitmap1() { 476 return &bmp1; 477 } 478 479 BBitmap* Bitmap2() { 480 return &bmp2; 481 } 482 483 icon_size Size() { 484 return size; 485 } 486 487protected: 488 BBitmap bmp1; 489 BBitmap bmp2; 490 BBitmap bmpTemp; 491 icon_size size; 492}; 493 494class IconForTypeHelper : public IconHelper { 495public: 496 IconForTypeHelper(const char *fileType, icon_size which) 497 : IconHelper(which), fileType(fileType) {} 498 virtual ~IconForTypeHelper() {} 499 virtual status_t GetIcon(BMimeType &mime, BBitmap *icon) { 500 return mime.GetIconForType(fileType.c_str(), icon, size); 501 } 502 virtual status_t SetIcon(BMimeType &mime, BBitmap *icon) { 503 return mime.SetIconForType(fileType.c_str(), icon, size); 504 } 505 virtual status_t DeleteIcon(BMimeType &mime) { 506#if TEST_R5 507 return B_BAD_VALUE; 508#else 509 return mime.DeleteIconForType(fileType.c_str(), size); 510#endif 511 } 512protected: 513 std::string fileType; 514}; 515 516// Adapter classes used by FillWithMimeTypes() to facilitate 517// addition of strings to containers with varying interfaces 518class ContainerAdapter { 519public: 520 virtual void Add(std::string value) = 0; 521}; 522 523class SetAdapter : public ContainerAdapter { 524public: 525 SetAdapter(std::set<std::string> &set) 526 : fSet(set) { } 527 virtual void Add(std::string value) { 528 fSet.insert(value); 529 } 530protected: 531 std::set<std::string> &fSet; 532}; 533 534class QueueAdapter : public ContainerAdapter { 535public: 536 QueueAdapter(std::queue<std::string> &queue) 537 : fQueue(queue) { } 538 virtual void Add(std::string value) { 539 fQueue.push(value); 540 } 541protected: 542 std::queue<std::string> &fQueue; 543}; 544 545 546// setUp 547void 548MimeTypeTest::setUp() 549{ 550 BasicTest::setUp(); 551 execCommand(string("mkdir ") + testDir); 552/* // Better not to play with fire, so we'll make a copy of the 553 // local mime database which we'll use for certain Haiku tests 554 execCommand(string("mkdir ") + testDir 555 + " ; copyattr -d -r -- " + mimeDatabaseDir + "/\* " + testDir 556 ); */ 557 // Setup our application 558 fApplication = new BTestApp(testSig); 559 if (fApplication->Init() != B_OK) { 560 fprintf(stderr, "Failed to initialize application.\n"); 561 delete fApplication; 562 fApplication = NULL; 563 } 564 565} 566 567// tearDown 568void 569MimeTypeTest::tearDown() 570{ 571 execCommand(string("rm -rf ") + testDir); 572 573 // Uninistall our test type 574 //! /todo Uncomment the following uninstall code when all is said and done. 575/* BMimeType mime(testType); 576 status_t err = mime.InitCheck(); 577 if (!err && mime.IsInstalled()) 578 err = mime.Delete(); 579 if (err) 580 fprintf(stderr, "Failed to unistall test type \"%s\"\n", testType); */ 581 // Terminate the Application 582 if (fApplication) { 583 fApplication->Terminate(); 584 delete fApplication; 585 fApplication = NULL; 586 } 587 // remove the types we've added 588 const char * const testTypes[] = { 589 testType, testType1, testType2, testType3, testType4, testType5, 590 testTypeApp, testTypeApp1, testTypeApp2, testTypeApp3, 591 }; 592 for (uint32 i = 0; i < sizeof(testTypes) / sizeof(const char*); i++) { 593 BMimeType type(testTypes[i]); 594 type.Delete(); 595 } 596 BasicTest::tearDown(); 597} 598 599// entry_ref dumping function ; this may be removed at any time 600 601/*void 602dump_ref(entry_ref *ref, char* name = "ref") { 603 if (ref) { 604 BPath path(ref); 605 status_t err = path.InitCheck(); 606 if (!err) { 607 printf("%s == '%s'", name, path.Path()); 608 } else 609 printf("%s == ERROR", name); 610 printf(" == (%ld, %lld, '%s')\n", ref->device, ref->directory, ref->name); 611 612 } else 613 printf("%s == (NULL)\n", name); 614}*/ 615 616// App Hint 617 618void 619MimeTypeTest::AppHintTest() { 620 // init a couple of entry_refs to applications 621 BEntry entry(testApp); 622 entry_ref appRef; 623 CHK(entry.InitCheck() == B_OK); 624 CHK(entry.GetRef(&appRef) == B_OK); 625 BEntry entry2(testApp2); 626 entry_ref appRef2; 627 CHK(entry2.InitCheck() == B_OK); 628 CHK(entry2.GetRef(&appRef2) == B_OK); 629 // Uninitialized 630 NextSubTest(); 631 { 632 BMimeType mime; 633 entry_ref ref; 634 CHK(mime.InitCheck() == B_NO_INIT); 635 CHK(mime.GetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE 636 CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE 637 } 638 // NULL params 639 NextSubTest(); 640 { 641 entry_ref ref; 642 BMimeType mime(testType); 643 CHK(mime.InitCheck() == B_OK); 644 // Make sure the type isn't installed 645 if (mime.IsInstalled()) 646 CHK(mime.Delete() == B_OK); 647#if TEST_R5 648 CHK(!mime.IsInstalled()); 649 CHK(mime.GetAppHint(NULL) != B_OK); // R5 == B_BAD_VALUE 650 CHK(!mime.IsInstalled()); 651 CHK(mime.SetAppHint(NULL) != B_OK); // Installs, R5 == B_ENTRY_NOT_FOUND 652 CHK(mime.IsInstalled()); 653 CHK(mime.GetAppHint(NULL) != B_OK); // R5 == B_BAD_VALUE 654 CHK(mime.SetAppHint(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND 655#else 656 CHK(!mime.IsInstalled()); 657 CHK(mime.GetAppHint(NULL) != B_OK); // B_BAD_VALUE 658 CHK(!mime.IsInstalled()); 659 CHK(mime.SetAppHint(NULL) != B_OK); // B_ENTRY_NOT_FOUND 660 CHK(!mime.IsInstalled()); 661 CHK(mime.SetAppHint(&appRef) == B_OK); 662 CHK(mime.IsInstalled()); 663 CHK(mime.GetAppHint(&ref) == B_OK); 664 CHK(ref == appRef); 665 CHK(mime.SetAppHint(NULL) == B_OK); 666 CHK(mime.IsInstalled()); 667 CHK(mime.GetAppHint(&ref) != B_OK); // B_ENTRY_NOT_FOUND 668#endif 669 } 670 // Delete test 671 NextSubTest(); 672 { 673#if !TEST_R5 674 entry_ref ref; 675 BMimeType mime(testType); 676 CHK(mime.InitCheck() == B_OK); 677 // Make sure the type isn't installed 678 if (mime.IsInstalled()) 679 CHK(mime.Delete() == B_OK); 680 CHK(!mime.IsInstalled()); 681 CHK(mime.DeleteAppHint() != B_OK); 682 CHK(!mime.IsInstalled()); 683 CHK(mime.SetAppHint(&appRef) == B_OK); 684 CHK(mime.IsInstalled()); 685 CHK(mime.GetAppHint(&ref) == B_OK); 686 CHK(ref == appRef); 687 CHK(mime.DeleteAppHint() == B_OK); 688 CHK(mime.IsInstalled()); 689 CHK(mime.GetAppHint(&ref) != B_OK); 690#endif 691 } 692 // Non-installed type 693 NextSubTest(); 694 { 695 entry_ref ref; 696 BMimeType mime(testType); 697 CHK(mime.InitCheck() == B_OK); 698 // Make sure the type isn't installed 699 if (mime.IsInstalled()) 700 CHK(mime.Delete() == B_OK); 701 CHK(!mime.IsInstalled()); 702 CHK(mime.GetAppHint(&ref) != B_OK); // R5 == B_ENTRY_NOT_FOUND 703 CHK(!mime.IsInstalled()); 704 CHK(mime.SetAppHint(&appRef) == B_OK); 705 CHK(mime.IsInstalled()); 706 CHK(mime.GetAppHint(&ref) == B_OK); 707 CHK(ref == appRef); 708 } 709 // Installed Type 710 NextSubTest(); 711 { 712 entry_ref ref; 713 BMimeType mime(testType); 714 CHK(mime.InitCheck() == B_OK); 715 // Uninstall then reinstall to clear attributes 716 if (mime.IsInstalled()) 717 CHK(mime.Delete() == B_OK); 718 if (!mime.IsInstalled()) 719 CHK(mime.Install() == B_OK); 720 CHK(mime.IsInstalled()); 721 // Get() with no apphint installed 722 CHK(mime.GetAppHint(&ref) == B_ENTRY_NOT_FOUND); 723 // Initial Set()/Get() 724 CHK(mime.SetAppHint(&appRef) == B_OK); 725 CHK(mime.GetAppHint(&ref) == B_OK); 726 CHK(ref == appRef); 727 // Followup Set()/Get() 728 CHK(mime.SetAppHint(&appRef2) == B_OK); 729 CHK(mime.GetAppHint(&ref) == B_OK); 730 CHK(ref == appRef2); 731 CHK(ref != appRef); 732 } 733 // Installed Type, invalid entry_ref 734 NextSubTest(); 735 { 736 entry_ref ref(-1, -1, NULL); 737 BMimeType mime(testType); 738 CHK(mime.InitCheck() == B_OK); 739 // Uninstall then reinstall to clear attributes 740 if (mime.IsInstalled()) 741 CHK(mime.Delete() == B_OK); 742 if (!mime.IsInstalled()) 743 CHK(mime.Install() == B_OK); 744 CHK(mime.IsInstalled()); 745 CHK(mime.SetAppHint(&appRef) == B_OK); 746 CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_BAD_VALUE 747 } 748 // Installed Type, fake/invalid entry_ref 749 NextSubTest(); 750 { 751 entry_ref ref(0, 0, "__this_ought_not_exist__"); 752 BMimeType mime(testType); 753 CHK(mime.InitCheck() == B_OK); 754 // Uninstall then reinstall to clear attributes 755 if (mime.IsInstalled()) 756 CHK(mime.Delete() == B_OK); 757 if (!mime.IsInstalled()) 758 CHK(mime.Install() == B_OK); 759 CHK(mime.IsInstalled()); 760 CHK(mime.SetAppHint(&appRef) == B_OK); 761 CHK(mime.SetAppHint(&ref) != B_OK); // R5 == B_ENTRY_NOT_FOUND 762 } 763 // Installed Type, abstract entry_ref 764 NextSubTest(); 765 { 766 entry_ref fakeRef; 767 entry_ref ref; 768 BEntry entry(fakeTestApp); 769 CHK(entry.InitCheck() == B_OK); 770 CHK(!entry.Exists()); 771 CHK(entry.GetRef(&fakeRef) == B_OK); 772 BMimeType mime(testType); 773 CHK(mime.InitCheck() == B_OK); 774 // Uninstall then reinstall to clear attributes 775 if (mime.IsInstalled()) 776 CHK(mime.Delete() == B_OK); 777 if (!mime.IsInstalled()) 778 CHK(mime.Install() == B_OK); 779 CHK(mime.IsInstalled()); 780 CHK(mime.SetAppHint(&appRef) == B_OK); 781 CHK(mime.SetAppHint(&fakeRef) == B_OK); 782 CHK(mime.GetAppHint(&ref) == B_OK); 783 CHK(ref == fakeRef); 784 CHK(ref != appRef); 785 } 786} 787 788// Attr Info 789 790void 791MimeTypeTest::AttrInfoTest() { 792 // Create some messages to sling around 793 const int32 WHAT = 233; // This is the what value that GAI() returns...not sure if it has a name yet 794 BMessage msg1(WHAT), msg2(WHAT), msg3(WHAT), msgIncomplete1(WHAT), msgIncomplete2(WHAT); 795 796 CHK(msg1.AddString(attrInfoField_Name, "Color") == B_OK); 797 CHK(msg1.AddString(attrInfoField_PublicName, "The Color") == B_OK); 798 CHK(msg1.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); 799 CHK(msg1.AddBool(attrInfoField_Viewable, true) == B_OK); 800 CHK(msg1.AddBool(attrInfoField_Editable, true) == B_OK); 801 802 CHK(msg1.AddString(attrInfoField_Name, "High Score") == B_OK); 803 CHK(msg1.AddString(attrInfoField_PublicName, "The Highest Score Ever") == B_OK); 804 CHK(msg1.AddInt32(attrInfoField_Type, B_INT32_TYPE) == B_OK); 805 CHK(msg1.AddBool(attrInfoField_Viewable, false) == B_OK); 806 CHK(msg1.AddBool(attrInfoField_Editable, false) == B_OK); 807 808 CHK(msg2.AddString(attrInfoField_Name, "Volume") == B_OK); 809 CHK(msg2.AddString(attrInfoField_PublicName, "Loudness") == B_OK); 810 CHK(msg2.AddInt32(attrInfoField_Type, B_DOUBLE_TYPE) == B_OK); 811 CHK(msg2.AddBool(attrInfoField_Viewable, true) == B_OK); 812 CHK(msg2.AddBool(attrInfoField_Editable, true) == B_OK); 813 814 CHK(msg3.AddString(attrInfoField_Name, "Volume") == B_OK); 815 CHK(msg3.AddString(attrInfoField_PublicName, "Loudness") == B_OK); 816 CHK(msg3.AddInt32(attrInfoField_Type, B_DOUBLE_TYPE) == B_OK); 817 CHK(msg3.AddBool(attrInfoField_Viewable, true) == B_OK); 818 CHK(msg3.AddBool(attrInfoField_Editable, true) == B_OK); 819 820 CHK(msgIncomplete1.AddString(attrInfoField_Name, "Color") == B_OK); 821 CHK(msgIncomplete1.AddString(attrInfoField_PublicName, "The Color") == B_OK); 822 CHK(msgIncomplete1.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); 823 CHK(msgIncomplete1.AddBool(attrInfoField_Viewable, true) == B_OK); 824 CHK(msgIncomplete1.AddBool(attrInfoField_Editable, true) == B_OK); 825 826 CHK(msgIncomplete1.AddString(attrInfoField_Name, "High Score") == B_OK); 827// CHK(msgIncomplete1.AddString(attrInfoField_PublicName, "The Highest Score Ever") == B_OK); 828 CHK(msgIncomplete1.AddInt32(attrInfoField_Type, B_INT32_TYPE) == B_OK); 829// CHK(msgIncomplete1.AddBool(attrInfoField_Viewable, false) == B_OK); 830 CHK(msgIncomplete1.AddBool(attrInfoField_Editable, false) == B_OK); 831 832 CHK(msgIncomplete2.AddString(attrInfoField_Name, "Color") == B_OK); 833// CHK(msgIncomplete2.AddString(attrInfoField_PublicName, "The Color") == B_OK); 834// CHK(msgIncomplete2.AddInt32(attrInfoField_Type, B_STRING_TYPE) == B_OK); 835// CHK(msgIncomplete2.AddBool(attrInfoField_Viewable, true) == B_OK); 836 CHK(msgIncomplete2.AddBool(attrInfoField_Editable, true) == B_OK); 837 838 CHK(msg1 == msg1); 839 CHK(msg2 == msg2); 840 CHK(msg3 == msg3); 841 CHK(msg1 != msg2); 842 CHK(msg1 != msg3); 843 CHK(msg2 == msg3); 844 845 // Uninitialized 846 NextSubTest(); 847 { 848 BMimeType mime; 849 BMessage msg; 850 851 CHK(mime.InitCheck() == B_NO_INIT); 852 CHK(mime.GetAttrInfo(&msg) != B_OK); // R5 == B_BAD_VALUE 853 CHK(mime.SetAttrInfo(&msg) != B_OK); // R5 == B_BAD_VALUE 854 } 855 856 // NULL params 857 NextSubTest(); 858 { 859#if !TEST_R5 860 BMessage msg; 861 BMimeType mime(testType); 862 CHK(mime.InitCheck() == B_OK); 863 // Make sure the type isn't installed 864 if (mime.IsInstalled()) 865 CHK(mime.Delete() == B_OK); 866 CHK(!mime.IsInstalled()); 867 CHK(mime.DeleteAttrInfo() != B_OK); 868 CHK(!mime.IsInstalled()); 869 msg1.RemoveName(typeField); // Clear "type" field, since SAI() just adds another 870 CHK(mime.SetAttrInfo(&msg1) == B_OK); 871 CHK(mime.IsInstalled()); 872 CHK(msg != msg1); 873 CHK(mime.GetAttrInfo(&msg) == B_OK); 874 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" field as GAI() does 875 CHK(msg == msg1); 876 CHK(mime.SetAttrInfo(NULL) == B_OK); 877 CHK(mime.IsInstalled()); 878 CHK(mime.GetAttrInfo(&msg) != B_OK); 879#endif 880 } 881 // Delete test 882 NextSubTest(); 883 { 884#if !TEST_R5 885 BMessage msg; 886 BMimeType mime(testType); 887 CHK(mime.InitCheck() == B_OK); 888 // Make sure the type isn't installed 889 if (mime.IsInstalled()) 890 CHK(mime.Delete() == B_OK); 891 CHK(!mime.IsInstalled()); 892 CHK(mime.DeleteAttrInfo() != B_OK); 893 CHK(!mime.IsInstalled()); 894 msg1.RemoveName(typeField); // Clear "type" field, since SAI() just adds another 895 CHK(mime.SetAttrInfo(&msg1) == B_OK); 896 CHK(mime.IsInstalled()); 897 CHK(msg != msg1); 898 CHK(mime.GetAttrInfo(&msg) == B_OK); 899 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" field as GAI() does 900 CHK(msg == msg1); 901 CHK(mime.DeleteAttrInfo() == B_OK); 902 CHK(mime.IsInstalled()); 903 CHK(mime.GetAttrInfo(&msg) != B_OK); 904#endif 905 } 906 907 // Improperly formatted BMessages 908 NextSubTest(); 909 { 910 BMessage msg(WHAT); 911 BMimeType mime(testType); 912 CHK(mime.InitCheck() == B_OK); 913 914 // Uninstall then reinstall to clear attributes 915 if (mime.IsInstalled()) 916 CHK(mime.Delete() == B_OK); 917 if (!mime.IsInstalled()) 918 CHK(mime.Install() == B_OK); 919 CHK(mime.IsInstalled()); 920 921 // Initial Set()/Get() 922 msgIncomplete1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another 923 msgIncomplete2.RemoveName(typeField); 924 CHK(msg != msgIncomplete1); 925 CHK(msg != msgIncomplete2); 926 CHK(mime.SetAttrInfo(&msgIncomplete1) == B_OK); 927 CHK(mime.GetAttrInfo(&msg) == B_OK); 928 CHK(msgIncomplete1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 929 CHK(msgIncomplete2.AddString(typeField, testType) == B_OK); 930 CHK(msg == msgIncomplete1); 931 CHK(msg != msgIncomplete2); 932 } 933 934 // Set() with improperly formatted message 935 NextSubTest(); 936 { 937 BMessage msg(WHAT); 938 BMimeType mime(testType); 939 CHK(mime.InitCheck() == B_OK); 940 941 // Uninstall then reinstall to clear attributes 942 if (mime.IsInstalled()) 943 CHK(mime.Delete() == B_OK); 944 if (!mime.IsInstalled()) 945 CHK(mime.Install() == B_OK); 946 CHK(mime.IsInstalled()); 947 948 // Initial Set()/Get() 949 msgIncomplete1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another 950 msgIncomplete2.RemoveName(typeField); 951 CHK(msg != msgIncomplete1); 952 CHK(msg != msgIncomplete2); 953 CHK(mime.SetAttrInfo(&msgIncomplete1) == B_OK); 954 CHK(mime.GetAttrInfo(&msg) == B_OK); 955 CHK(msgIncomplete1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 956 CHK(msgIncomplete2.AddString(typeField, testType) == B_OK); 957 CHK(msg == msgIncomplete1); 958 CHK(msg != msgIncomplete2); 959 } 960 961 // Set() with empty message 962 NextSubTest(); 963 { 964 BMimeType mime(testType); 965 BMessage msgEmpty(WHAT); 966 BMessage msg(WHAT); 967 CHK(msg.AddInt32("stuff", 1234) == B_OK); // Add an extra attribute to give us something to compare with 968 969 // Uninstall then reinstall to clear attributes 970 if (mime.IsInstalled()) 971 CHK(mime.Delete() == B_OK); 972 if (!mime.IsInstalled()) 973 CHK(mime.Install() == B_OK); 974 CHK(mime.IsInstalled()); 975 976 // Set(empty) 977 CHK(msg != msgEmpty); 978 CHK(mime.SetAttrInfo(&msgEmpty) == B_OK); 979 CHK(mime.GetAttrInfo(&msg) == B_OK); 980 CHK(msgEmpty.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 981 CHK(msg == msgEmpty); 982 } 983 984 // Set() with extra attributes in message 985 NextSubTest(); 986 { 987 BMimeType mime(testType); 988 BMessage msg(WHAT); 989 BMessage msgExtraSet(msg1); 990 CHK(msgExtraSet.AddString("extra", ".extra") == B_OK); 991 CHK(msgExtraSet.AddInt32("more_extras", 123) == B_OK); 992 CHK(msgExtraSet.AddInt32("more_extras", 456) == B_OK); 993 CHK(msgExtraSet.AddInt32("more_extras", 789) == B_OK); 994 BMessage msgExtraGet(msgExtraSet); 995 996 // Uninstall then reinstall to clear attributes 997 if (mime.IsInstalled()) 998 CHK(mime.Delete() == B_OK); 999 if (!mime.IsInstalled()) 1000 CHK(mime.Install() == B_OK); 1001 CHK(mime.IsInstalled()); 1002 1003 // Set(extra)/Get(empty) 1004 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1005 msg2.RemoveName(typeField); 1006 CHK(msg != msg1); 1007 CHK(msg != msgExtraSet); 1008 CHK(mime.SetAttrInfo(&msgExtraSet) == B_OK); 1009 CHK(mime.GetAttrInfo(&msg) == B_OK); 1010 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1011 CHK(msgExtraSet.AddString(typeField, testType) == B_OK); 1012 CHK(msg == msgExtraSet); 1013 CHK(msg != msg1); 1014 1015 // Get(extra) 1016 NextSubTest(); 1017 CHK(mime.GetAttrInfo(&msgExtraGet) == B_OK); 1018 CHK(msgExtraGet == msgExtraSet); 1019 CHK(msgExtraGet != msg1); 1020 1021 // Get(extra and then some) 1022 NextSubTest(); 1023 CHK(msgExtraGet.AddInt32("more_extras", 101112) == B_OK); 1024 msgExtraGet.RemoveName(typeField); // Clear "type" fields to be fair, since SFE() just adds another 1025 CHK(mime.GetAttrInfo(&msgExtraGet) == B_OK); // Reinitializes result (clearing extra fields) 1026 CHK(msgExtraGet == msgExtraSet); 1027 CHK(msgExtraGet != msg1); 1028 1029 } 1030 // Normal Function (Non-installed type) 1031 NextSubTest(); 1032 { 1033 BMimeType mime(testType); 1034 BMessage msg(WHAT); 1035 BMessage msg2(WHAT); 1036 1037 CHK(mime.InitCheck() == B_OK); 1038 // Make sure the type isn't installed 1039 if (mime.IsInstalled()) 1040 CHK(mime.Delete() == B_OK); 1041 1042 CHK(!mime.IsInstalled()); 1043 CHK(mime.GetAttrInfo(&msg) != B_OK); // R5 == B_ENTRY_NOT_FOUND 1044 CHK(!mime.IsInstalled()); 1045 CHK(mime.SetAttrInfo(&msg) == B_OK); 1046 CHK(mime.IsInstalled()); 1047 CHK(mime.GetAttrInfo(&msg2) == B_OK); 1048 CHK(msg.AddString(typeField, testType) == B_OK); // Add in "type" fields as GAI() does 1049 CHK(msg == msg2); 1050 } 1051 1052 // Normal Function 1053 NextSubTest(); 1054 { 1055 BMessage msg(WHAT); 1056 BMimeType mime(testType); 1057 CHK(mime.InitCheck() == B_OK); 1058 1059 // Uninstall then reinstall to clear attributes 1060 if (mime.IsInstalled()) 1061 CHK(mime.Delete() == B_OK); 1062 if (!mime.IsInstalled()) 1063 CHK(mime.Install() == B_OK); 1064 CHK(mime.IsInstalled()); 1065 1066 // Initial Set()/Get() 1067 msg1.RemoveName(typeField); // Clear "type" fields, since SAI() just adds another 1068 msg2.RemoveName(typeField); 1069 CHK(msg != msg1); 1070 CHK(msg != msg2); 1071 CHK(mime.SetAttrInfo(&msg1) == B_OK); 1072 CHK(mime.GetAttrInfo(&msg) == B_OK); 1073 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1074 CHK(msg2.AddString(typeField, testType) == B_OK); 1075 CHK(msg == msg1); 1076 CHK(msg != msg2); 1077 1078 // Followup Set()/Get() 1079 NextSubTest(); 1080 CHK(msg.MakeEmpty() == B_OK); 1081 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1082 msg2.RemoveName(typeField); 1083 CHK(msg != msg1); 1084 CHK(msg != msg2); 1085 CHK(mime.SetAttrInfo(&msg2) == B_OK); 1086 CHK(mime.GetAttrInfo(&msg) == B_OK); 1087 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1088 CHK(msg2.AddString(typeField, testType) == B_OK); 1089 CHK(msg != msg1); 1090 CHK(msg == msg2); 1091 1092 // Clear 1093 NextSubTest(); 1094 CHK(msg.MakeEmpty() == B_OK); 1095 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1096 msg2.RemoveName(typeField); 1097 CHK(msg != msg1); 1098 CHK(msg != msg2); 1099#if !TEST_R5 1100 CHK(mime.SetAttrInfo(NULL) == B_OK); // R5 == CRASH! despite what one might think should happen 1101 CHK(mime.GetAttrInfo(&msg) != B_OK); 1102 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1103 CHK(msg2.AddString(typeField, testType) == B_OK); 1104 CHK(msg != msg1); 1105 CHK(msg != msg2); 1106#endif 1107 } 1108} 1109 1110// File Extensions 1111 1112void 1113MimeTypeTest::FileExtensionsTest() { 1114 // Create some messages to sling around 1115 const int32 WHAT = 234; // This is the what value that GFE returns...not sure if it has a name yet 1116 BMessage msg1(WHAT), msg2(WHAT), msg3(WHAT); 1117 1118 CHK(msg1.AddString(fileExtField, ".data") == B_OK); 1119 CHK(msg1.AddString(fileExtField, ".txt") == B_OK); 1120 CHK(msg1.AddString(fileExtField, ".png") == B_OK); 1121 CHK(msg1.AddString(fileExtField, ".html") == B_OK); 1122 1123 CHK(msg2.AddString(fileExtField, ".data") == B_OK); 1124 CHK(msg2.AddString(fileExtField, ".txt") == B_OK); 1125 1126 CHK(msg3.AddString(fileExtField, ".data") == B_OK); 1127 CHK(msg3.AddString(fileExtField, ".txt") == B_OK); 1128 1129 CHK(msg1 == msg1); 1130 CHK(msg2 == msg2); 1131 CHK(msg3 == msg3); 1132 CHK(msg1 != msg2); 1133 CHK(msg1 != msg3); 1134 CHK(msg2 == msg3); 1135 1136 // Uninitialized 1137 NextSubTest(); 1138 { 1139 BMessage msg(WHAT); 1140 BMimeType mime; 1141 1142 CHK(mime.InitCheck() == B_NO_INIT); 1143 CHK(mime.GetFileExtensions(&msg) != B_OK); // R5 == B_BAD_VALUE 1144 CHK(mime.SetFileExtensions(&msg) != B_OK); // R5 == B_BAD_VALUE 1145 } 1146 // NULL params 1147 NextSubTest(); 1148 { 1149#if !TEST_R5 1150 BMessage msg; 1151 BMimeType mime(testType); 1152 CHK(mime.InitCheck() == B_OK); 1153 // Make sure the type isn't installed 1154 if (mime.IsInstalled()) 1155 CHK(mime.Delete() == B_OK); 1156 CHK(!mime.IsInstalled()); 1157 CHK(mime.DeleteFileExtensions() != B_OK); 1158 CHK(!mime.IsInstalled()); 1159 msg1.RemoveName(typeField); // Clear "type" field, since SAI() just adds another 1160 CHK(mime.SetFileExtensions(&msg1) == B_OK); 1161 CHK(mime.IsInstalled()); 1162 CHK(msg != msg1); 1163 CHK(mime.GetFileExtensions(&msg) == B_OK); 1164 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" field as GAI() does 1165 CHK(msg == msg1); 1166 CHK(mime.SetFileExtensions(NULL) == B_OK); 1167 CHK(mime.IsInstalled()); 1168 CHK(mime.GetFileExtensions(&msg) != B_OK); 1169#endif 1170 } 1171 // Delete test 1172 NextSubTest(); 1173 { 1174#if !TEST_R5 1175 BMessage msg; 1176 BMimeType mime(testType); 1177 CHK(mime.InitCheck() == B_OK); 1178 // Make sure the type isn't installed 1179 if (mime.IsInstalled()) 1180 CHK(mime.Delete() == B_OK); 1181 CHK(!mime.IsInstalled()); 1182 CHK(mime.DeleteFileExtensions() != B_OK); 1183 CHK(!mime.IsInstalled()); 1184 msg1.RemoveName(typeField); // Clear "type" field, since SAI() just adds another 1185 CHK(mime.SetFileExtensions(&msg1) == B_OK); 1186 CHK(mime.IsInstalled()); 1187 CHK(msg != msg1); 1188 CHK(mime.GetFileExtensions(&msg) == B_OK); 1189 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" field as GAI() does 1190 CHK(msg == msg1); 1191 CHK(mime.DeleteFileExtensions() == B_OK); 1192 CHK(mime.IsInstalled()); 1193 CHK(mime.GetFileExtensions(&msg) != B_OK); 1194#endif 1195 } 1196 // Set() with empty message 1197 NextSubTest(); 1198 { 1199 BMimeType mime(testType); 1200 BMessage msgEmpty(WHAT); 1201 BMessage msg(WHAT); 1202 CHK(msg.AddInt32("stuff", 1234) == B_OK); // Add an extra attribute to give us something to compare with 1203 1204 // Uninstall then reinstall to clear attributes 1205 if (mime.IsInstalled()) 1206 CHK(mime.Delete() == B_OK); 1207 if (!mime.IsInstalled()) 1208 CHK(mime.Install() == B_OK); 1209 CHK(mime.IsInstalled()); 1210 1211 // Set(empty) 1212 CHK(msg != msgEmpty); 1213 CHK(mime.SetFileExtensions(&msgEmpty) == B_OK); 1214 CHK(mime.GetFileExtensions(&msg) == B_OK); 1215 CHK(msgEmpty.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1216 CHK(msg == msgEmpty); 1217 } 1218 // Set() with extra attributes in message 1219 NextSubTest(); 1220 { 1221 BMimeType mime(testType); 1222 BMessage msg(WHAT); 1223 BMessage msgExtraSet(msg1); 1224 CHK(msgExtraSet.AddString("extra", ".extra") == B_OK); 1225 CHK(msgExtraSet.AddInt32("more_extras", 123) == B_OK); 1226 CHK(msgExtraSet.AddInt32("more_extras", 456) == B_OK); 1227 CHK(msgExtraSet.AddInt32("more_extras", 789) == B_OK); 1228 BMessage msgExtraGet(msgExtraSet); 1229 1230 // Uninstall then reinstall to clear attributes 1231 if (mime.IsInstalled()) 1232 CHK(mime.Delete() == B_OK); 1233 if (!mime.IsInstalled()) 1234 CHK(mime.Install() == B_OK); 1235 CHK(mime.IsInstalled()); 1236 1237 // Set(extra)/Get(empty) 1238 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1239 msg2.RemoveName(typeField); 1240 CHK(msg != msg1); 1241 CHK(msg != msgExtraSet); 1242 CHK(mime.SetFileExtensions(&msgExtraSet) == B_OK); 1243 CHK(mime.GetFileExtensions(&msg) == B_OK); 1244 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1245 CHK(msgExtraSet.AddString(typeField, testType) == B_OK); 1246 CHK(msg == msgExtraSet); 1247 CHK(msg != msg1); 1248 1249 // Get(extra) 1250 NextSubTest(); 1251 CHK(mime.GetFileExtensions(&msgExtraGet) == B_OK); 1252 CHK(msgExtraGet == msgExtraSet); 1253 CHK(msgExtraGet != msg1); 1254 1255 // Get(extra and then some) 1256 NextSubTest(); 1257 CHK(msgExtraGet.AddInt32("more_extras", 101112) == B_OK); 1258 msgExtraGet.RemoveName(typeField); // Clear "type" fields to be fair, since SFE() just adds another 1259 CHK(mime.GetFileExtensions(&msgExtraGet) == B_OK); // Reinitializes result (clearing extra fields) 1260 CHK(msgExtraGet == msgExtraSet); 1261 CHK(msgExtraGet != msg1); 1262 1263 } 1264 // Normal function 1265 NextSubTest(); 1266 { 1267 BMessage msg(WHAT); 1268 BMimeType mime(testType); 1269 1270 // Uninstall then reinstall to clear attributes 1271 if (mime.IsInstalled()) 1272 CHK(mime.Delete() == B_OK); 1273 if (!mime.IsInstalled()) 1274 CHK(mime.Install() == B_OK); 1275 CHK(mime.IsInstalled()); 1276 1277 // Initial Set()/Get() 1278 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1279 msg2.RemoveName(typeField); 1280 CHK(msg != msg1); 1281 CHK(msg != msg2); 1282 CHK(mime.SetFileExtensions(&msg1) == B_OK); 1283 CHK(mime.GetFileExtensions(&msg) == B_OK); 1284 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1285 CHK(msg2.AddString(typeField, testType) == B_OK); 1286 CHK(msg == msg1); 1287 CHK(msg != msg2); 1288 1289 // Followup Set()/Get() 1290 NextSubTest(); 1291 CHK(msg.MakeEmpty() == B_OK); 1292 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1293 msg2.RemoveName(typeField); 1294 CHK(msg != msg1); 1295 CHK(msg != msg2); 1296 CHK(mime.SetFileExtensions(&msg2) == B_OK); 1297 CHK(mime.GetFileExtensions(&msg) == B_OK); 1298 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1299 CHK(msg2.AddString(typeField, testType) == B_OK); 1300 CHK(msg != msg1); 1301 CHK(msg == msg2); 1302 1303 // Clear 1304 NextSubTest(); 1305 CHK(msg.MakeEmpty() == B_OK); 1306 msg1.RemoveName(typeField); // Clear "type" fields, since SFE() just adds another 1307 msg2.RemoveName(typeField); 1308 CHK(msg != msg1); 1309 CHK(msg != msg2); 1310#if !TEST_R5 1311 CHK(mime.SetFileExtensions(NULL) == B_OK); // R5 == CRASH! despite what the BeBook says 1312 CHK(mime.GetFileExtensions(&msg) != B_OK); 1313 CHK(msg1.AddString(typeField, testType) == B_OK); // Add in "type" fields as GFE() does 1314 CHK(msg2.AddString(typeField, testType) == B_OK); 1315 CHK(msg != msg1); 1316 CHK(msg != msg2); 1317#endif 1318 } 1319} 1320 1321 1322// Icon Test Helper Function 1323 1324void 1325MimeTypeTest::IconTest(IconHelper &helper) { 1326 BBitmap *bmp = helper.TempBitmap(); 1327 // Unitialized 1328 NextSubTest(); 1329 { 1330 BMimeType mime; 1331 CHK(mime.InitCheck() == B_NO_INIT); 1332 CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_BAD_VALUE 1333 CHK(helper.SetIcon(mime, bmp) != B_OK); // R5 == B_BAD_VALUE 1334 } 1335 // Non-installed type 1336 NextSubTest(); 1337 { 1338 BMimeType mime(testType); 1339 CHK(mime.InitCheck() == B_OK); 1340 // Make sure the type isn't installed 1341 if (mime.IsInstalled()) 1342 CHK(mime.Delete() == B_OK); 1343 CHK(!mime.IsInstalled()); 1344 // Test 1345 CHK(helper.GetIcon(mime, bmp) != B_OK); // R5 == B_ENTRY_NOT_FOUND 1346 CHK(!mime.IsInstalled()); 1347 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1348 CHK(mime.IsInstalled()); 1349 CHK(helper.GetIcon(mime, bmp) == B_OK); 1350 CHK(*bmp == *helper.Bitmap1()); 1351 } 1352 // NULL params 1353 NextSubTest(); 1354 { 1355 BMimeType mime(testType); 1356 CHK(mime.InitCheck() == B_OK); 1357 // Make sure the type isn't installed 1358 if (mime.IsInstalled()) 1359 CHK(mime.Delete() == B_OK); 1360 CHK(!mime.IsInstalled()); 1361 // Uninstalled 1362 CHK(helper.GetIcon(mime, NULL) != B_OK); // B_BAD_VALUE 1363 CHK(!mime.IsInstalled()); 1364 CHK(helper.SetIcon(mime, NULL) != B_OK); // R5 == Installs, B_ENTRY_NOT_FOUND 1365 // Haiku == Doesn't install, B_ENTRY_NOT_FOUND 1366#if TEST_R5 1367 CHK(mime.IsInstalled()); 1368#else 1369 CHK(!mime.IsInstalled()); 1370 CHK(mime.Install() == B_OK); 1371#endif 1372 CHK(helper.GetIcon(mime, bmp) != B_OK); // B_ENTRY_NOT_FOUND 1373 // Installed 1374 CHK(helper.GetIcon(mime, NULL) != B_OK); // B_BAD_VALUE 1375 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1376 CHK(helper.GetIcon(mime, bmp) == B_OK); 1377 CHK(*bmp == *helper.Bitmap1()); 1378 CHK(helper.SetIcon(mime, NULL) == B_OK); 1379 CHK(helper.GetIcon(mime, bmp) != B_OK); // B_ENTRY_NOT_FOUND 1380 } 1381 // Delete test 1382 NextSubTest(); 1383 { 1384#if !TEST_R5 1385 BMimeType mime(testType); 1386 CHK(mime.InitCheck() == B_OK); 1387 // Make sure the type isn't installed 1388 if (mime.IsInstalled()) 1389 CHK(mime.Delete() == B_OK); 1390 CHK(!mime.IsInstalled()); 1391 CHK(helper.DeleteIcon(mime) != B_OK); 1392 CHK(!mime.IsInstalled()); 1393 CHK(helper.SetIcon(mime, helper.Bitmap2()) == B_OK); 1394 CHK(mime.IsInstalled()); 1395 fill_bitmap(*bmp, 100); 1396 CHK(*bmp != *helper.Bitmap2()); 1397 CHK(helper.GetIcon(mime, bmp) == B_OK); 1398 CHK(*bmp == *helper.Bitmap2()); 1399 CHK(helper.DeleteIcon(mime) == B_OK); 1400 CHK(mime.IsInstalled()); 1401 CHK(helper.GetIcon(mime, bmp) != B_OK); 1402#endif 1403 } 1404 // Invalid Bitmap Size (small -- 10x10) 1405 NextSubTest(); 1406 { 1407 BMimeType mime(testType); 1408 CHK(mime.InitCheck() == B_OK); 1409 // Uninstall then reinstall to clear attributes 1410 if (mime.IsInstalled()) 1411 CHK(mime.Delete() == B_OK); 1412 if (!mime.IsInstalled()) 1413 CHK(mime.Install() == B_OK); 1414 CHK(mime.IsInstalled()); 1415 // Init Test Bitmap 1416 BBitmap testBmp(BRect(0,0,9,9), B_CMAP8); 1417 fill_bitmap(testBmp, 3); 1418 // Test Set() 1419 CHK(testBmp != *helper.Bitmap1()); 1420 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1421 CHK(helper.GetIcon(mime, bmp) == B_OK); 1422 CHK(*bmp == *helper.Bitmap1()); 1423 CHK(helper.SetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE 1424 CHK(helper.GetIcon(mime, bmp) == B_OK); 1425 CHK(*bmp == *helper.Bitmap1()); 1426 CHK(*bmp != testBmp); 1427 // Test Get() 1428 fill_bitmap(testBmp, 3); 1429 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1430 CHK(helper.GetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE 1431 } 1432 // Invalid Bitmap Size (large -- 100x100) 1433 NextSubTest(); 1434 { 1435 BMimeType mime(testType); 1436 CHK(mime.InitCheck() == B_OK); 1437 // Uninstall then reinstall to clear attributes 1438 if (mime.IsInstalled()) 1439 CHK(mime.Delete() == B_OK); 1440 if (!mime.IsInstalled()) 1441 CHK(mime.Install() == B_OK); 1442 CHK(mime.IsInstalled()); 1443 // Init Test Bitmap 1444 BBitmap testBmp(BRect(0,0,99,99), B_CMAP8); 1445 // Test Set() 1446 fill_bitmap(testBmp, 3); 1447 CHK(testBmp != *helper.Bitmap1()); 1448 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1449 CHK(helper.GetIcon(mime, bmp) == B_OK); 1450 CHK(*bmp == *helper.Bitmap1()); 1451 CHK(helper.SetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE 1452 CHK(helper.GetIcon(mime, bmp) == B_OK); 1453 CHK(*bmp == *helper.Bitmap1()); 1454 CHK(*bmp != testBmp); 1455 // Test Get() 1456 fill_bitmap(testBmp, 3); 1457 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1458 CHK(helper.GetIcon(mime, &testBmp) != B_OK); // R5 == B_BAD_VALUE 1459 } 1460 // Non-B_CMAP8 Color Depth (not really supported under R5) 1461 NextSubTest(); 1462 { 1463#if !TEST_R5 1464 BMimeType mime(testType); 1465 CHK(mime.InitCheck() == B_OK); 1466 // Uninstall then reinstall to clear attributes 1467 if (mime.IsInstalled()) 1468 CHK(mime.Delete() == B_OK); 1469 if (!mime.IsInstalled()) 1470 CHK(mime.Install() == B_OK); 1471 CHK(mime.IsInstalled()); 1472 // Init Test Bitmap 1473 BBitmap testBmp(helper.BitmapBounds(), B_RGB32); 1474 // Test Set() 1475// fill_bitmap(testBmp, 4); 1476 fill_bitmap32(testBmp, 10, 20, 30, 40); // Fill our 32-bit bitmap 1477 BBitmap testBmp8(helper.BitmapBounds(), B_CMAP8); // Create an 8-bit bitmap the same size 1478// dump_bitmap(testBmp8); 1479 reduce_color_depth(testBmp, testBmp8); // Make it an 8-bit version of the 32-bit bitmap 1480// dump_bitmap(testBmp8); 1481 CHK(testBmp != *helper.Bitmap1()); 1482 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1483 CHK(helper.GetIcon(mime, bmp) == B_OK); 1484 CHK(*bmp == *helper.Bitmap1()); 1485 CHK(helper.SetIcon(mime, &testBmp) == B_OK); 1486 // R5 == B_OK, despite being invalid color depth; however, icon is not actually set, 1487 // and any subsequent call to GetIcon() will cause the application to crash... 1488 CHK(helper.GetIcon(mime, bmp) == B_OK); // R5 == CRASH!, Haiku == Damn right I can handle that shit 1489 CHK(*bmp != *helper.Bitmap1()); 1490 CHK(*bmp != testBmp); // Shouldn't match, since SetIcon() reduces to B_CMAP8 1491 CHK(*bmp == testBmp8); // *Should* match, since it's the result of a similar reduction 1492#endif 1493 } 1494 // Normal Function 1495 NextSubTest(); 1496 { 1497 BMimeType mime(testType); 1498 CHK(mime.InitCheck() == B_OK); 1499 // Uninstall then reinstall to clear attributes 1500 if (mime.IsInstalled()) 1501 CHK(mime.Delete() == B_OK); 1502 if (!mime.IsInstalled()) 1503 CHK(mime.Install() == B_OK); 1504 CHK(mime.IsInstalled()); 1505 // Set() then Get() 1506 fill_bitmap(*bmp, 3); 1507 CHK(*bmp != *helper.Bitmap1()); 1508 CHK(helper.SetIcon(mime, helper.Bitmap1()) == B_OK); 1509 CHK(helper.GetIcon(mime, bmp) == B_OK); 1510 CHK(*bmp == *helper.Bitmap1()); 1511 // Set() then Get() again 1512 fill_bitmap(*bmp, 3); 1513 CHK(helper.SetIcon(mime, helper.Bitmap2()) == B_OK); 1514 CHK(helper.GetIcon(mime, bmp) == B_OK); 1515 CHK(*bmp == *helper.Bitmap2()); 1516 CHK(*bmp != *helper.Bitmap1()); 1517 } 1518} 1519 1520// Icon For Type Helper Functions 1521 1522void 1523MimeTypeTest::IconForTypeTest(IconForTypeHelper &helper) { 1524 IconTest(helper); // First run all the icon tests 1525 // Then do some IconForType() specific tests 1526 1527 BBitmap *bmp = helper.TempBitmap(); 1528 1529 // Invalid MIME string 1530 NextSubTest(); 1531 { 1532 BMimeType mime(testType); 1533 CHK(mime.InitCheck() == B_OK); 1534 // Uninstall then reinstall to clear attributes 1535 if (mime.IsInstalled()) 1536 CHK(mime.Delete() == B_OK); 1537 if (!mime.IsInstalled()) 1538 CHK(mime.Install() == B_OK); 1539 CHK(mime.IsInstalled()); 1540 // Set() then Get() 1541 fill_bitmap(*bmp, 3); 1542 CHK(*bmp != *helper.Bitmap1()); 1543 CHK(mime.SetIconForType(testTypeInvalid, helper.Bitmap1(), helper.Size()) != B_OK); // R5 == B_BAD_VALUE 1544 CHK(mime.GetIconForType(testTypeInvalid, bmp, helper.Size()) != B_OK); // R5 == B_BAD_VALUE 1545 CHK(*bmp != *helper.Bitmap1()); 1546 } 1547 // NULL MIME string (just like calling respective {Get,Set}Icon() function) 1548 NextSubTest(); 1549 { 1550 BMimeType mime(testType); 1551 CHK(mime.InitCheck() == B_OK); 1552 // Uninstall then reinstall to clear attributes 1553 if (mime.IsInstalled()) 1554 CHK(mime.Delete() == B_OK); 1555 if (!mime.IsInstalled()) 1556 CHK(mime.Install() == B_OK); 1557 CHK(mime.IsInstalled()); 1558 // Set() then Get() 1559 fill_bitmap(*bmp, 3); 1560 CHK(*bmp != *helper.Bitmap1()); 1561 CHK(mime.SetIconForType(NULL, helper.Bitmap1(), helper.Size()) == B_OK); 1562 CHK(mime.GetIconForType(NULL, bmp, helper.Size()) == B_OK); 1563 CHK(*bmp == *helper.Bitmap1()); 1564 // Verify GetIcon() does the same thing 1565 fill_bitmap(*bmp, 3); 1566 CHK(*bmp != *helper.Bitmap1()); 1567 CHK(mime.GetIcon(bmp, helper.Size()) == B_OK); 1568 CHK(*bmp == *helper.Bitmap1()); 1569 // Delete with dual NULL calls 1570 CHK(mime.SetIconForType(NULL, NULL, helper.Size()) == B_OK); 1571 CHK(mime.GetIconForType(NULL, bmp, helper.Size()) != B_OK); // B_ENTRY_NOT_FOUND 1572 CHK(mime.GetIcon(bmp, helper.Size()) != B_OK); // B_ENTRY_NOT_FOUND 1573 } 1574} 1575 1576void 1577MimeTypeTest::LargeIconTest() { 1578 IconHelper helper(B_LARGE_ICON); 1579 IconTest(helper); 1580} 1581 1582void 1583MimeTypeTest::MiniIconTest() { 1584 IconHelper helper(B_MINI_ICON); 1585 IconTest(helper); 1586} 1587 1588void 1589MimeTypeTest::LargeIconForTypeTest() { 1590 IconForTypeHelper helper(testType, B_LARGE_ICON); 1591 IconForTypeTest(helper); 1592} 1593 1594void 1595MimeTypeTest::MiniIconForTypeTest() { 1596 IconForTypeHelper helper(testType, B_MINI_ICON); 1597 IconForTypeTest(helper); 1598} 1599 1600bool isMIMESupertype(const char *type) { 1601 BMimeType sub, super; 1602 status_t err; 1603 err = !type || !BMimeType::IsValid(type); 1604 1605 // See if the type is the same as it's supertype 1606 if (!err) 1607 err = sub.SetTo(type); 1608 if (!err) 1609 return sub.GetSupertype(&super) == B_BAD_VALUE; 1610 // This is what R5::GetSupertype() returns when called on a supertype; 1611 1612 return false; 1613} 1614 1615void 1616MimeTypeTest::VerifyInstalledTypes() { 1617 // Check GetInstalledTypes(1) 1618 NextSubTest(); 1619 { 1620 BMessage msg; 1621 1622 // Get the list of installed types 1623 CHK(BMimeType::GetInstalledTypes(&msg) == B_OK); 1624 1625 // Add all the type strings to a std::set 1626 std::set<std::string> typeSet; 1627 SetAdapter typeAdapter(typeSet); 1628 FillWithMimeTypes(typeAdapter, msg, "types"); 1629 1630 // Manually verify that the set of types returned by GetInstalledTypes() 1631 // and the types present in the database are exactly the same (ignoring 1632 // any files with names made of invalid characters, in case some bozo 1633 // manually added such a file :-) 1634 BDirectory rootDir(mimeDatabaseDir.c_str()); 1635 BEntry superEntry; 1636 CHK(rootDir.InitCheck() == B_OK); 1637 rootDir.Rewind(); 1638 while (true) { 1639 status_t err = rootDir.GetNextEntry(&superEntry); 1640 if (err == B_ENTRY_NOT_FOUND) 1641 break; // End of directory listing 1642 1643 CHK(!err); // Any other error is unacceptable :-) 1644 1645 // Get the leaf name 1646 char superLeafMixed[B_PATH_NAME_LENGTH+1]; 1647 CHK(superEntry.GetName(superLeafMixed) == B_OK); 1648 std::string superLeaf; 1649 to_lower(superLeafMixed, superLeaf); 1650 1651 // We're only interested in directories, as they map to 1652 // supertypes (and since they map thusly, they must also 1653 // be valid MIME strings) 1654 if (superEntry.IsDirectory() && BMimeType::IsValid(superLeaf.c_str())) { 1655 // First, find and remove the supertype from our set 1656 CHK(typeSet.find(superLeaf.c_str()) != typeSet.end()); 1657 typeSet.erase(superLeaf.c_str()); 1658 1659 // Second, iterate through all the entries in the directory. 1660 // If the entry designates a valid MIME string, find it 1661 // in the set and remove it. 1662 BDirectory superDir(&superEntry); 1663 BEntry subEntry; 1664 CHK(superDir.InitCheck() == B_OK); 1665 superDir.Rewind(); 1666 while (true) { 1667 status_t err = superDir.GetNextEntry(&subEntry); 1668 if (err == B_ENTRY_NOT_FOUND) 1669 break; // End of directory listing 1670 1671 CHK(!err); // Any other error is unacceptable :-) 1672 1673 // Get the leaf name 1674 char subLeafMixed[B_PATH_NAME_LENGTH+1]; 1675 CHK(subEntry.GetName(subLeafMixed) == B_OK); 1676 std::string subLeaf; 1677 to_lower(subLeafMixed, subLeaf); 1678 1679 // Verify it's a valid mime string. If so, find and remove from our set 1680 std::string subType = superLeaf + "/" + subLeaf; 1681 if (BMimeType::IsValid(subType.c_str())) { 1682 if (typeSet.find(subType.c_str()) == typeSet.end()) 1683 cout << "Fuckup == '" << subType << "'" << endl; 1684 CHK(typeSet.find(subType.c_str()) != typeSet.end()); 1685 typeSet.erase(subType.c_str()); 1686 } 1687 } 1688 } 1689 } 1690 1691 // At this point our set should be empty :-) If it's not, you might check 1692 // that you haven't added any superfluous files to your MIME database (like 1693 // a __mime_table backup, for instance). 1694 CHK(typeSet.size() == 0); 1695 } 1696 NextSubTest(); 1697 // Check GetInstalledTypes(2) and GetInstalledSupertypes() 1698 { 1699 BMessage msg; 1700 1701 // Get the list of installed types 1702 CHK(BMimeType::GetInstalledSupertypes(&msg) == B_OK); 1703// msg.PrintToStream(); 1704 1705 // Add all the type strings to a std::set 1706 std::set<std::string> typeSet; 1707 SetAdapter typeAdapter(typeSet); 1708 FillWithMimeTypes(typeAdapter, msg, "super_types"); 1709 1710 // Manually verify that the set of types returned by GetInstalledSupertypes() 1711 // and the types present in the database are exactly the same (ignoring 1712 // any files with names made of invalid characters, in case some bozo 1713 // manually added such a file :-) 1714 BDirectory rootDir(mimeDatabaseDir.c_str()); 1715 BEntry superEntry; 1716 CHK(rootDir.InitCheck() == B_OK); 1717 rootDir.Rewind(); 1718 while (true) { 1719 status_t err = rootDir.GetNextEntry(&superEntry); 1720 if (err == B_ENTRY_NOT_FOUND) 1721 break; // End of directory listing 1722 1723 CHK(!err); // Any other error is unacceptable :-) 1724 1725 // Get the leaf name 1726 char superLeafMixed[B_PATH_NAME_LENGTH+1]; 1727 CHK(superEntry.GetName(superLeafMixed) == B_OK); 1728 std::string superLeaf; 1729 to_lower(superLeafMixed, superLeaf); 1730 1731 // We're only interested in directories, as they map to 1732 // supertypes (and since they map thusly, they must also 1733 // be valid MIME strings) 1734 if (superEntry.IsDirectory() && BMimeType::IsValid(superLeaf.c_str())) { 1735 // First, find and remove the supertype from our set 1736 CHK(typeSet.find(superLeaf.c_str()) != typeSet.end()); 1737 typeSet.erase(superLeaf.c_str()); 1738 1739 // Second, get the list of corresponding subtypes and add them 1740 // to a std::set to be used for verification 1741 BMessage msg; 1742 CHK(BMimeType::GetInstalledTypes(superLeaf.c_str(), &msg) == B_OK); 1743// msg.PrintToStream(); 1744 1745 std::set<std::string> subtypeSet; 1746 SetAdapter subtypeAdapter(subtypeSet); 1747 FillWithMimeTypes(subtypeAdapter, msg, "types"); 1748 1749 // Third, iterate through all the entries in the directory. 1750 // If the entry designates a valid MIME string, find it 1751 // in the subtype set and remove it. 1752 BDirectory superDir(&superEntry); 1753 BEntry subEntry; 1754 CHK(superDir.InitCheck() == B_OK); 1755 superDir.Rewind(); 1756 while (true) { 1757 status_t err = superDir.GetNextEntry(&subEntry); 1758 if (err == B_ENTRY_NOT_FOUND) 1759 break; // End of directory listing 1760 1761 CHK(!err); // Any other error is unacceptable :-) 1762 1763 // Get the leaf name 1764 char subLeafMixed[B_PATH_NAME_LENGTH+1]; 1765 CHK(subEntry.GetName(subLeafMixed) == B_OK); 1766 std::string subLeaf; 1767 to_lower(subLeafMixed, subLeaf); 1768 1769 // Verify it's a valid mime string. If so, find and remove from our set 1770 std::string subType = superLeaf + "/" + subLeaf; 1771 if (BMimeType::IsValid(subType.c_str())) { 1772 CHK(subtypeSet.find(subType.c_str()) != subtypeSet.end()); 1773 subtypeSet.erase(subType.c_str()); 1774 } 1775 } 1776 1777 // At this point our subtype set should be empty :-) 1778 CHK(subtypeSet.size() == 0); 1779 1780 } 1781 } 1782 1783 // At this point our set should be empty :-) 1784 CHK(typeSet.size() == 0); 1785 } 1786 1787} 1788 1789void 1790MimeTypeTest::InstalledTypesTest() { 1791 // NULL params 1792 { 1793 BMessage msg; 1794 NextSubTest(); 1795 1796#if !TEST_R5 1797 CHK(BMimeType::GetInstalledTypes(NULL) != B_OK); // R5 == CRASH!!!, Haiku == B_BAD_VALUE 1798#endif 1799 NextSubTest(); 1800#if !TEST_R5 1801 CHK(BMimeType::GetInstalledTypes("text", NULL) != B_OK); // R5 == CRASH!!!, Haiku == B_BAD_VALUE 1802#endif 1803 NextSubTest(); 1804 CHK(BMimeType::GetInstalledTypes(NULL, &msg) == B_OK); // Same as GetInstalledTypes(&msg) 1805// msg.PrintToStream(); 1806 NextSubTest(); 1807#if !TEST_R5 1808 CHK(BMimeType::GetInstalledTypes(NULL, NULL) != B_OK); // R5 == CRASH!!!, Haiku == B_BAD_VALUE 1809#endif 1810 NextSubTest(); 1811#if !TEST_R5 1812 CHK(BMimeType::GetInstalledSupertypes(NULL) != B_OK); // R5 == CRASH!!!, Haiku == B_BAD_VALUE 1813#endif 1814 } 1815 // Invalid supertype param to GetInstalledTypes(char *super, BMessage*) 1816 { 1817 BMessage msg; 1818 NextSubTest(); 1819 CHK(!BMimeType::IsValid(testTypeSuperInvalid)); 1820 CHK(BMimeType::GetInstalledTypes(testTypeSuperInvalid, &msg) != B_OK); // R5 == B_BAD_VALUE 1821 NextSubTest(); 1822 CHK(BMimeType::IsValid(testTypeSuperValid)); 1823 CHK(BMimeType::GetInstalledTypes(testTypeSuperValid, &msg) != B_OK); // R5 == B_ENTRY_NOT_FOUND 1824 } 1825 // Normal Function -- GetInstalledTypes(BMessage*) 1826 // This test gets the list of installed types, then iterates through 1827 // the actual database directory listings and verifies they're identical. 1828 { 1829 VerifyInstalledTypes(); 1830 BMimeType mime(testTypeApp1); 1831 CHK(mime.InitCheck() == B_OK); 1832 if (mime.IsInstalled()) { 1833 CHK(mime.Delete() == B_OK); 1834 VerifyInstalledTypes(); 1835 CHK(mime.Install() == B_OK); 1836 VerifyInstalledTypes(); 1837 } else { 1838 CHK(mime.Install() == B_OK); 1839 VerifyInstalledTypes(); 1840 CHK(mime.Delete() == B_OK); 1841 VerifyInstalledTypes(); 1842 } 1843 } 1844 // Normal Function -- GetInstalledSupertypes()/GetInstalledTypes(char*,BMessage*) 1845 // This test gets the list of installed super types, then iterates through 1846 // the actual database directory listings and verifies they're identical. 1847 1848} 1849 1850// Short Description 1851 1852void 1853MimeTypeTest::ShortDescriptionTest() { 1854 DescriptionTest(&BMimeType::GetShortDescription, &BMimeType::SetShortDescription, 1855#if TEST_R5 1856 NULL 1857#else 1858 &BMimeType::DeleteShortDescription 1859#endif 1860 ); 1861} 1862 1863// Long Description 1864 1865void 1866MimeTypeTest::LongDescriptionTest() { 1867 DescriptionTest(&BMimeType::GetLongDescription, &BMimeType::SetLongDescription, 1868#if TEST_R5 1869 NULL 1870#else 1871 &BMimeType::DeleteLongDescription 1872#endif 1873 ); 1874} 1875 1876// DescriptionTest Helper Function 1877void 1878MimeTypeTest::DescriptionTest(GetDescriptionFunc getDescr, SetDescriptionFunc setDescr, 1879 DeleteDescriptionFunc deleteDescr) 1880{ 1881 char str[B_MIME_TYPE_LENGTH+1]; 1882 1883 // Uninitialized 1884 NextSubTest(); 1885 { 1886 str[0] = 0; 1887 BMimeType mime; 1888 CPPUNIT_ASSERT(mime.InitCheck() == B_NO_INIT); 1889 CPPUNIT_ASSERT((mime.*getDescr)(str) != B_OK); // R5 == B_BAD_VALUE 1890 CPPUNIT_ASSERT((mime.*setDescr)(str) != B_OK); // R5 == B_BAD_VALUE 1891 } 1892 // Non-installed type 1893 NextSubTest(); 1894 { 1895 str[0] = 0; 1896 BMimeType mime(testType); 1897 CHK(mime.InitCheck() == B_OK); 1898 // Make sure the type isn't installed 1899 if (mime.IsInstalled()) 1900 CHK(mime.Delete() == B_OK); 1901 CHK(!mime.IsInstalled()); 1902 CHK((mime.*getDescr)(str) != B_OK); // R5 == B_ENTRY_NOT_FOUND 1903 CHK(!mime.IsInstalled()); 1904 CHK((mime.*setDescr)(testDescr) == B_OK); // R5 == Installs (but doesn't set), B_OK 1905 CHK(mime.IsInstalled()); 1906 CHK((mime.*getDescr)(str) == B_OK); 1907 CHK(strcmp(str, testDescr) == 0); 1908 } 1909 // Non-installed type, NULL params 1910 NextSubTest(); 1911 { 1912#if !TEST_R5 // NOTE: These tests crash for R5::LongDescription calls but not for R5::ShortDescription 1913 // calls. Considering the general instability exihibited by most R5 calls when passed 1914 // NULL pointers, however, I wouldn't suggest it, and thus they aren't even tested here. 1915 BMimeType mime(testType); 1916 CHK(mime.InitCheck() == B_OK); 1917 // Make sure the type isn't installed 1918 if (mime.IsInstalled()) 1919 CHK(mime.Delete() == B_OK); 1920 CHK(!mime.IsInstalled()); 1921 CHK((mime.*getDescr)(NULL) == B_BAD_VALUE); 1922 CHK(!mime.IsInstalled()); 1923 CHK((mime.*setDescr)(NULL) == B_ENTRY_NOT_FOUND); // Trying to delete non-existent attribute 1924 CHK(!mime.IsInstalled()); 1925 CHK((mime.*setDescr)(testDescr) == B_OK); 1926 CHK(mime.IsInstalled()); 1927 str[0] = 0; 1928 CHK((mime.*getDescr)(str) == B_OK); 1929 CHK(strcmp(str, testDescr) == 0); 1930 CHK((mime.*setDescr)(NULL) == B_OK); // Delete the attribute 1931 CHK(mime.IsInstalled()); 1932 CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); 1933#endif 1934 } 1935 // Delete test 1936 NextSubTest(); 1937 { 1938#if !TEST_R5 1939 entry_ref ref; 1940 BMimeType mime(testType); 1941 CHK(mime.InitCheck() == B_OK); 1942 // Make sure the type isn't installed 1943 if (mime.IsInstalled()) 1944 CHK(mime.Delete() == B_OK); 1945 CHK(!mime.IsInstalled()); 1946 CHK((mime.*deleteDescr)() != B_OK); 1947 CHK(!mime.IsInstalled()); 1948 CHK((mime.*setDescr)(testDescr) == B_OK); 1949 CHK(mime.IsInstalled()); 1950 str[0] = 0; 1951 CHK((mime.*getDescr)(str) == B_OK); 1952 CHK(strcmp(str, testDescr) == 0); 1953 CHK((mime.*deleteDescr)() == B_OK); 1954 CHK(mime.IsInstalled()); 1955 CHK((mime.*getDescr)(str) != B_OK); 1956#endif 1957 } 1958 // Installed type 1959 NextSubTest(); 1960 { 1961 str[0] = 0; 1962 BMimeType mime(testType); 1963 CHK(mime.InitCheck() == B_OK); 1964 // Uninstall then reinstall to clear attributes 1965 if (mime.IsInstalled()) 1966 CHK(mime.Delete() == B_OK); 1967 if (!mime.IsInstalled()) 1968 CHK(mime.Install() == B_OK); 1969 // Get() with no description installed 1970 CHK(mime.IsInstalled()); 1971 CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); // R5 == B_ENTRY_NOT_FOUND 1972 // Initial Set()/Get() 1973 CHK((mime.*setDescr)(testDescr) == B_OK); 1974 CHK((mime.*getDescr)(str) == B_OK); 1975 CHK(strcmp(str, testDescr) == 0); 1976 // Followup Set()/Get() 1977 CHK((mime.*setDescr)(testDescr2) == B_OK); 1978 CHK((mime.*getDescr)(str) == B_OK); 1979 CHK(strcmp(str, testDescr2) == 0); 1980 } 1981 // Installed Type, Description Too Long 1982 NextSubTest(); 1983 { 1984 str[0] = 0; 1985 CHK(strlen(longDescr) > (B_MIME_TYPE_LENGTH+1)); 1986 BMimeType mime(testType); 1987 CHK(mime.InitCheck() == B_OK); 1988 // Uninstall then reinstall to clear attributes 1989 if (mime.IsInstalled()) 1990 CHK(mime.Delete() == B_OK); 1991 if (!mime.IsInstalled()) 1992 CHK(mime.Install() == B_OK); 1993 // Initial Set()/Get() 1994 CHK((mime.*setDescr)(longDescr) != B_OK); // R5 == B_BAD_VALUE 1995 CHK((mime.*getDescr)(str) == B_ENTRY_NOT_FOUND); 1996 // Followup Set()/Get() 1997 CHK((mime.*setDescr)(testDescr) == B_OK); 1998 CHK((mime.*setDescr)(longDescr) != B_OK); // R5 == B_BAD_VALUE 1999 CHK((mime.*getDescr)(str) == B_OK); 2000 CHK(strcmp(str, testDescr) == 0); 2001 } 2002 2003} 2004 2005 2006// Preferred App 2007 2008void 2009MimeTypeTest::PreferredAppTest() { 2010 char str[B_MIME_TYPE_LENGTH+1]; 2011 sprintf(str, "%s", testSig); 2012 2013 // Uninitialized 2014 NextSubTest(); 2015 { 2016 BMimeType mime; 2017 CPPUNIT_ASSERT(mime.InitCheck() == B_NO_INIT); 2018 CPPUNIT_ASSERT(mime.GetPreferredApp(str) != B_OK); // R5 == B_BAD_VALUE 2019 CPPUNIT_ASSERT(mime.SetPreferredApp(str) != B_OK); // R5 == B_BAD_VALUE 2020 } 2021 // Non-installed type 2022 NextSubTest(); 2023 { 2024 BMimeType mime(testType); 2025 CHK(mime.InitCheck() == B_OK); 2026 // Make sure the type isn't installed 2027 if (mime.IsInstalled()) 2028 CHK(mime.Delete() == B_OK); 2029 CHK(!mime.IsInstalled()); 2030 CHK(mime.GetPreferredApp(str) != B_OK); // R5 == B_ENTRY_NOT_FOUND 2031 CHK(!mime.IsInstalled()); 2032 CHK(mime.SetPreferredApp(testSig) == B_OK); // R5 == Installs (but doesn't set), B_OK 2033 CHK(mime.IsInstalled()); 2034 CHK(mime.GetPreferredApp(str) == B_OK); 2035 CHK(strcmp(str, testSig) == 0); 2036 } 2037 // Non-installed type, NULL params 2038 NextSubTest(); 2039 { 2040 BMimeType mime(testType); 2041 CHK(mime.InitCheck() == B_OK); 2042 // Make sure the type isn't installed 2043 if (mime.IsInstalled()) 2044 CHK(mime.Delete() == B_OK); 2045#if TEST_R5 2046 CHK(!mime.IsInstalled()); 2047 CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND 2048 CHK(!mime.IsInstalled()); 2049 CHK(mime.SetPreferredApp(NULL) != B_OK); // R5 == Installs (but doesn't set), B_ENTRY_NOT_FOUND 2050 CHK(mime.IsInstalled()); 2051 CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); 2052#else 2053 CHK(!mime.IsInstalled()); 2054 CHK(mime.GetPreferredApp(NULL) != B_OK); // Haiku == B_BAD_VALUE 2055 CHK(!mime.IsInstalled()); 2056 CHK(mime.SetPreferredApp(NULL) != B_OK); // Haiku == B_ENTRY_NOT_FOUND 2057 CHK(!mime.IsInstalled()); 2058 CHK(mime.SetPreferredApp(testSig) == B_OK); 2059 CHK(mime.IsInstalled()); 2060 str[0] = 0; 2061 CHK(mime.GetPreferredApp(str) == B_OK); 2062 CHK(strcmp(str, testSig) == 0); 2063 CHK(mime.SetPreferredApp(NULL) == B_OK); 2064 CHK(mime.IsInstalled()); 2065 str[0] = 0; 2066 CHK(mime.GetPreferredApp(str) != B_OK); // Haiku == B_ENTRY_NOT_FOUND 2067#endif // !TEST_R5 2068 } 2069 // Installed type, NULL params 2070 NextSubTest(); 2071 { 2072 BMimeType mime(testType); 2073 CHK(mime.InitCheck() == B_OK); 2074 // Uninstall then reinstall to clear attributes 2075 if (mime.IsInstalled()) 2076 CHK(mime.Delete() == B_OK); 2077 if (!mime.IsInstalled()) 2078 CHK(mime.Install() == B_OK); 2079 CHK(mime.IsInstalled()); 2080 CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_BAD_ADDRESS 2081 CHK(mime.SetPreferredApp(NULL) != B_OK); // R5 == B_ENTRY_NOT_FOUND 2082 CHK(mime.GetPreferredApp(NULL) != B_OK); // R5 == B_BAD_ADDRESS 2083 } 2084 // Delete test 2085 NextSubTest(); 2086 { 2087#if !TEST_R5 2088 entry_ref ref; 2089 BMimeType mime(testType); 2090 CHK(mime.InitCheck() == B_OK); 2091 // Make sure the type isn't installed 2092 if (mime.IsInstalled()) 2093 CHK(mime.Delete() == B_OK); 2094 CHK(!mime.IsInstalled()); 2095 CHK(mime.DeletePreferredApp() != B_OK); 2096 CHK(!mime.IsInstalled()); 2097 CHK(mime.SetPreferredApp(testSig) == B_OK); 2098 CHK(mime.IsInstalled()); 2099 str[0] = 0; 2100 CHK(mime.GetPreferredApp(str) == B_OK); 2101 CHK(strcmp(str, testSig) == 0); 2102 CHK(mime.DeletePreferredApp() == B_OK); 2103 CHK(mime.IsInstalled()); 2104 CHK(mime.GetPreferredApp(str) != B_OK); 2105#endif 2106 } 2107 // Installed type 2108 NextSubTest(); 2109 { 2110 BMimeType mime(testType); 2111 CHK(mime.InitCheck() == B_OK); 2112 // Uninstall then reinstall to clear attributes 2113 if (mime.IsInstalled()) 2114 CHK(mime.Delete() == B_OK); 2115 if (!mime.IsInstalled()) 2116 CHK(mime.Install() == B_OK); 2117 // Get() with no description installed 2118 CHK(mime.IsInstalled()); 2119 CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); // R5 == B_ENTRY_NOT_FOUND 2120 // Initial Set()/Get() 2121 CHK(mime.SetPreferredApp(testSig) == B_OK); 2122 CHK(mime.GetPreferredApp(str) == B_OK); 2123 CHK(strcmp(str, testSig) == 0); 2124 // Followup Set()/Get() 2125 CHK(mime.SetPreferredApp(testSig2) == B_OK); 2126 CHK(mime.GetPreferredApp(str) == B_OK); 2127 CHK(strcmp(str, testSig2) == 0); 2128 } 2129 // Installed Type, Signature Too Long 2130 NextSubTest(); 2131 { 2132 CHK(strlen(longDescr) > (B_MIME_TYPE_LENGTH+1)); 2133 BMimeType mime(testType); 2134 CHK(mime.InitCheck() == B_OK); 2135 // Uninstall then reinstall to clear attributes 2136 if (mime.IsInstalled()) 2137 CHK(mime.Delete() == B_OK); 2138 if (!mime.IsInstalled()) 2139 CHK(mime.Install() == B_OK); 2140 // Initial Set()/Get() 2141 CHK(mime.SetPreferredApp(longSig) != B_OK); // R5 == B_BAD_VALUE 2142 CHK(mime.GetPreferredApp(str) == B_ENTRY_NOT_FOUND); 2143 // Followup Set()/Get() 2144 CHK(mime.SetPreferredApp(testSig) == B_OK); 2145 CHK(mime.SetPreferredApp(longSig) != B_OK); // R5 == B_BAD_VALUE 2146 CHK(mime.GetPreferredApp(str) == B_OK); 2147 CHK(strcmp(str, testSig) == 0); 2148 } 2149 2150} 2151 2152// Converts every character in str to lowercase and places 2153// the result in result. 2154void 2155to_lower(const char *str, std::string &result) { 2156 CHK(str != NULL); 2157 result = ""; 2158 for (uint i = 0; i < strlen(str); i++) 2159 result += tolower(str[i]); 2160} 2161 2162std::string 2163to_lower(const char *str) { 2164 std::string result; 2165 to_lower(str, result); 2166 return result; 2167} 2168 2169 2170// Manually removes the file in the MIME database corresponding to 2171// the given MIME type 2172void 2173remove_type(const char *type, const char *databaseDir) { 2174 CHK(type != NULL); 2175 2176 // Since the MIME types are converted to lower case before their 2177 // corresponding file is created in the database, we need to do 2178 // the same 2179 std::string typeLower; 2180 to_lower(type, typeLower); 2181 2182 BEntry entry((std::string(mimeDatabaseDir) + "/" + typeLower).c_str()); 2183 CHK(entry.InitCheck() == B_OK); 2184 if (entry.Exists()) 2185 CHK(entry.Remove() == B_OK); 2186 CHK(!entry.Exists()); 2187} 2188 2189// Manually verifies that the file in the MIME database corresponding to 2190// the given MIME type exists 2191bool 2192type_exists(const char *type, const char *databaseDir) { 2193 CHK(type != NULL); 2194 2195 // Since the MIME types are converted to lower case before their 2196 // corresponding file is created in the database, we need to do 2197 // the same 2198 std::string typeLower; 2199 to_lower(type, typeLower); 2200 2201 BEntry entry((std::string(databaseDir) + "/" + typeLower).c_str()); 2202 CHK(entry.InitCheck() == B_OK); 2203 return entry.Exists(); 2204} 2205 2206void 2207MimeTypeTest::InstallDeleteTest() { 2208 // Uninitialzized 2209 NextSubTest(); 2210 { 2211 BMimeType mime; 2212 CHK(mime.InitCheck() == B_NO_INIT); 2213 CHK(!mime.IsInstalled()); 2214 CHK(mime.Install() != B_OK); // R5 == B_BAD_VALUE 2215 CHK(mime.Delete() != B_OK); // R5 == B_BAD_VALUE 2216 } 2217 // Invalid Type String 2218 NextSubTest(); 2219 { 2220 BMimeType mime(testTypeInvalid); 2221 CHK(mime.InitCheck() != B_OK); // R5 == B_BAD_VALUE 2222 CHK(!mime.IsInstalled()); 2223 CHK(mime.Install() != B_OK); // R5 == B_BAD_VALUE 2224 CHK(mime.Delete() != B_OK); // R5 == B_BAD_VALUE 2225 } 2226 // Normal function 2227 NextSubTest(); 2228 { 2229 remove_type(testType); 2230 BMimeType mime(testType); 2231 CHK(mime.InitCheck() == B_OK); 2232 CHK(!mime.IsInstalled()); 2233 CHK(mime.Delete() != B_OK); // R5 == B_ENTRY_NOT_FOUND, Haiku == B_ENTRY_NOT_FOUND 2234 CHK(!type_exists(testType)); 2235 CHK(mime.Install() == B_OK); 2236 CHK(type_exists(testType)); 2237 CHK(mime.IsInstalled()); 2238#if !TEST_R5 2239 CHK(mime.Install() != B_OK); // We ought to return something standard and logical here, as R5 is random 2240#endif 2241 CHK(mime.Delete() == B_OK); 2242 CHK(!type_exists(testType)); 2243 CHK(!mime.IsInstalled()); 2244 } 2245 2246} 2247 2248void FillWithMimeTypes(ContainerAdapter &container, BMessage &typeMessage, const char* fieldName) { 2249 type_code type; 2250 int32 count; 2251 status_t err; 2252 2253// typeMessage.PrintToStream(); 2254 2255 // Get a count of types in the message 2256 err = typeMessage.GetInfo(fieldName, &type, &count); 2257 if (err == B_NAME_NOT_FOUND) 2258 count = 0; // No such types installed in the database! :-) 2259 else 2260 CHK(err == B_OK); // Any other error is unacceptable 2261 2262 // Add them all to the container, after converting to lowercase and 2263 // checking validity 2264 for (int i = 0; i < count; i++) { 2265 char *str; 2266 CHK(typeMessage.FindString(fieldName, i, (const char**)&str) == B_OK); 2267 std::string strLower; 2268 to_lower(str, strLower); 2269 // Make sure it's a valid type string, since the R5::GetInstalled*Types() 2270 // functions do no such verification, and we ignore invalid type files 2271 // in the database. 2272 if (BMimeType::IsValid(strLower.c_str())) 2273 container.Add(strLower); 2274 } 2275} 2276 2277bool 2278types_fields_are_identical(const BMessage &msg1, const BMessage &msg2) 2279{ 2280 const char *str1; 2281 const char *str2; 2282 int i = 0; 2283 bool result = true; 2284 while (true) { 2285 status_t err1 = msg1.FindString(typesField, i, &str1); 2286 status_t err2 = msg2.FindString(typesField, i, &str2); 2287 if (err1 != err2) { 2288 result = false; 2289 break; 2290 } 2291 if (err1 != B_OK) 2292 break; 2293 result &= to_lower(str1) == to_lower(str2); 2294 i++; 2295 } 2296 return result; 2297} 2298 2299bool 2300is_supporting_app_for_all_types_in_message(const char *app, const BMessage &msg) 2301{ 2302 const char *str; 2303 bool result = true; 2304 for (int i = 0; msg.FindString(typesField, i, &str) == B_OK; i++) { 2305 BMimeType supportedType(str); 2306 BMessage appMsg; 2307 2308 // Get a list of supporting apps 2309 CHK(supportedType.InitCheck() == B_OK); 2310 CHK(supportedType.GetSupportingApps(&appMsg) == B_OK); 2311// cout << "-----------------------------------------------------------" << endl; 2312// cout << str << endl; 2313// cout << "-----------------------------------------------------------" << endl; 2314// appMsg.PrintToStream(); 2315 2316 // Look for our supporting app 2317 int32 directlySupportingAppsCount; 2318 CHK(appMsg.FindInt32("be:sub", &directlySupportingAppsCount) == B_OK); 2319 bool foundType = false; 2320 const char *supportingApp; 2321 for (int j = 0; 2322 j < directlySupportingAppsCount 2323 && appMsg.FindString(applicationsField, &supportingApp) == B_OK; 2324 j++) 2325 { 2326 foundType |= to_lower(app) == to_lower(supportingApp); 2327 } 2328 result &= foundType; 2329 } 2330 return result; 2331} 2332 2333void 2334MimeTypeTest::SupportedTypesTest() { 2335#if TEST_R5 2336 Outputf("(no tests actually performed for R5 version)\n"); 2337#else 2338 // Create some messages to sling around 2339 const int32 WHAT = 0; 2340 BMessage msg1a(WHAT), msg1b(WHAT), msg2(WHAT), msg3(WHAT), msgEmpty(WHAT); 2341 2342 CHK(msg3.AddString(typesField, testType1) == B_OK); 2343 CHK(msg3.AddString(typesField, testType2) == B_OK); 2344 CHK(msg3.AddString(typesField, testType3) == B_OK); 2345 2346 CHK(msg2.AddString(typesField, testType2) == B_OK); 2347 CHK(msg2.AddString(typesField, testType3) == B_OK); 2348 2349 CHK(msg1a.AddString(typesField, testType5) == B_OK); 2350 2351 CHK(msg1b.AddString(typesField, testType2) == B_OK); 2352 2353 CHK(msg1a == msg1a); 2354 CHK(msg1b == msg1b); 2355 CHK(msg2 == msg2); 2356 CHK(msg3 == msg3); 2357 CHK(msg1a != msg2); 2358 CHK(msg1a != msg3); 2359 CHK(msg1a != msgEmpty); 2360 2361 // Uninitialized 2362 NextSubTest(); 2363 { 2364 BMimeType mime; 2365 BMessage msg; 2366 2367 CHK(mime.InitCheck() == B_NO_INIT); 2368 CHK(mime.SetSupportedTypes(&msg, true) != B_OK); 2369 CHK(mime.SetSupportedTypes(&msg, false) != B_OK); 2370 CHK(mime.GetSupportedTypes(&msg) != B_OK); 2371 CHK(mime.DeleteSupportedTypes() != B_OK); 2372 } 2373 2374 // Test that deleting a type from the database also removes 2375 // the app as a supporting app for all types it previously 2376 // supported 2377 NextSubTest(); 2378 { 2379 BMessage msg; 2380 BMimeType mime(testType); 2381 CHK(mime.InitCheck() == B_OK); 2382 if (!mime.IsInstalled()) 2383 CHK(mime.Install() == B_OK); 2384 2385 // Set a list of supported types 2386 CHK(mime.SetSupportedTypes(&msg3, true) == B_OK); 2387 2388 // Verify that each of those types now lists the 2389 // type as a directly supporting app 2390 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true); 2391 2392 // Delete the type 2393 CHK(mime.Delete() == B_OK); 2394 2395 // Verify that each of those types no longer lists the 2396 // type as a directly supporting app 2397 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false); 2398 } 2399 2400 // Test that SetSupportedTypes(..., false) does not remove the app as a supporting 2401 // app for newly unsupported types, while SetSupportedTypes(..., true) does. Also 2402 // test that supported types stranded by multiple sequential calls to 2403 // SetSupportedTypes(..., false) are properly updated so as to no longer list the 2404 // app as a supporting app once SetSupportedTypes(..., true) is finally called. 2405 NextSubTest(); 2406 { 2407 BMessage msg; 2408 BMimeType mime(testType); 2409 CHK(mime.InitCheck() == B_OK); 2410 2411 // Uninstall then reinstall to clear attributes, etc 2412 if (mime.IsInstalled()) 2413 CHK(mime.Delete() == B_OK); 2414 if (!mime.IsInstalled()) 2415 CHK(mime.Install() == B_OK); 2416 CHK(mime.IsInstalled()); 2417 2418 // Set a list of supported types 2419 CHK(mime.SetSupportedTypes(&msg3, true) == B_OK); 2420 CHK(mime.GetSupportedTypes(&msg) == B_OK); 2421 CHK(types_fields_are_identical(msg3, msg) == true); 2422 CHK(types_fields_are_identical(msg2, msg) == false); 2423 CHK(types_fields_are_identical(msg1a, msg) == false); 2424 CHK(types_fields_are_identical(msg1b, msg) == false); 2425 CHK(types_fields_are_identical(msgEmpty, msg) == false); 2426 2427 // Verify that each of those types now lists the 2428 // type as a directly supporting app 2429 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true); 2430 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true); 2431 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false); 2432 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2433 2434 // Set (no sync) to a new list of supported types containing one 2435 // fewer type than the original list 2436 CHK(mime.SetSupportedTypes(&msg2, false) == B_OK); 2437 CHK(mime.GetSupportedTypes(&msg) == B_OK); 2438 CHK(types_fields_are_identical(msg3, msg) == false); 2439 CHK(types_fields_are_identical(msg2, msg) == true); 2440 CHK(types_fields_are_identical(msg1a, msg) == false); 2441 CHK(types_fields_are_identical(msg1b, msg) == false); 2442 CHK(types_fields_are_identical(msgEmpty, msg) == false); 2443 2444 // Verify that the app is still listed as a supporting app for 2445 // *all* of the originally supported types (even the one no longer 2446 // listed as being supported) 2447 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true); 2448 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true); 2449 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false); 2450 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2451 2452 // Set (no sync) to a new list of supported types containing an 2453 // entirely new, never supported type 2454 CHK(mime.SetSupportedTypes(&msg1a, false) == B_OK); 2455 CHK(mime.GetSupportedTypes(&msg) == B_OK); 2456 CHK(types_fields_are_identical(msg3, msg) == false); 2457 CHK(types_fields_are_identical(msg2, msg) == false); 2458 CHK(types_fields_are_identical(msg1a, msg) == true); 2459 CHK(types_fields_are_identical(msg1b, msg) == false); 2460 CHK(types_fields_are_identical(msgEmpty, msg) == false); 2461 2462 // Verify that the app is still listed as a supporting app for 2463 // *all* of the originally supported types (none of which are 2464 // supported any longer) as well as the newly supported type. 2465 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true); 2466 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true); 2467 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == true); 2468 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2469 2470 // Set (no sync) to a new list of supported types containing only 2471 // one of the originally supported types that had been previously 2472 // removed. 2473 CHK(mime.SetSupportedTypes(&msg1b, false) == B_OK); 2474 CHK(mime.GetSupportedTypes(&msg) == B_OK); 2475 CHK(types_fields_are_identical(msg3, msg) == false); 2476 CHK(types_fields_are_identical(msg2, msg) == false); 2477 CHK(types_fields_are_identical(msg1a, msg) == false); 2478 CHK(types_fields_are_identical(msg1b, msg) == true); 2479 CHK(types_fields_are_identical(msgEmpty, msg) == false); 2480 2481 // Verify that the app is still listed as a supporting app for 2482 // *all* of the originally supported types (only one of which is 2483 // supported any longer) as well as the previous supported type. 2484 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == true); 2485 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == true); 2486 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == true); 2487 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2488 2489 // Set (with sync) to the same list as last time (containing the 2490 // one type from the original list of supported types) 2491 CHK(mime.SetSupportedTypes(&msg1b, true) == B_OK); 2492 CHK(mime.GetSupportedTypes(&msg) == B_OK); 2493 CHK(types_fields_are_identical(msg3, msg) == false); 2494 CHK(types_fields_are_identical(msg2, msg) == false); 2495 CHK(types_fields_are_identical(msg1a, msg) == false); 2496 CHK(types_fields_are_identical(msg1b, msg) == true); 2497 CHK(types_fields_are_identical(msgEmpty, msg) == false); 2498 2499 // Verify that the app is now only listed as a supporting app for the 2500 // most recently supported type. 2501 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false); 2502 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false); 2503 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false); 2504 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2505 2506 // Test SetSupportedTypes(NULL, false) for shits and giggles 2507 CHK(mime.SetSupportedTypes(NULL, false) == B_OK); 2508 CHK(mime.GetSupportedTypes(&msg) == B_ENTRY_NOT_FOUND); 2509 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false); 2510 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false); 2511 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false); 2512 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == true); 2513 2514 // Now test that SetSupportedTypes(NULL, true) updates the supporting 2515 // apps mappings, even if the supported types attribute has already 2516 // been removed. 2517 CHK(mime.SetSupportedTypes(NULL, true) == B_ENTRY_NOT_FOUND); 2518 CHK(mime.GetSupportedTypes(&msg) == B_ENTRY_NOT_FOUND); 2519 CHK(is_supporting_app_for_all_types_in_message(testType, msg3) == false); 2520 CHK(is_supporting_app_for_all_types_in_message(testType, msg2) == false); 2521 CHK(is_supporting_app_for_all_types_in_message(testType, msg1a) == false); 2522 CHK(is_supporting_app_for_all_types_in_message(testType, msg1b) == false); 2523 } 2524#endif // #if TEST_R5 else 2525} 2526 2527void 2528MimeTypeTest::SupportingAppsTest() { 2529/* { 2530 BMessage msg; 2531 BMimeType::GetInstalledTypes(&msg); 2532 msg.PrintToStream(); 2533 } 2534 { 2535 BMessage msg; 2536 BMimeType mime("application/octet-stream"); 2537 CHK(mime.InitCheck() == B_OK); 2538 CHK(mime.GetSupportingApps(&msg) == B_OK); 2539 msg.PrintToStream(); 2540 } 2541 { 2542 BMessage msg; 2543 BMimeType mime("text"); 2544 CHK(mime.InitCheck() == B_OK); 2545 CHK(mime.GetSupportingApps(&msg) == B_OK); 2546 msg.PrintToStream(); 2547 } 2548 { 2549 BMessage msg; 2550 BMimeType mime("text/html"); 2551 CHK(mime.InitCheck() == B_OK); 2552 CHK(mime.GetSupportingApps(&msg) == B_OK); 2553 msg.PrintToStream(); 2554 } */ 2555 NextSubTest(); 2556 if (true) 2557 { 2558 std::set<std::string> typeList; // Stores all installed MIME types 2559 std::set<std::string> appList; // Stores all installed application subtypes 2560 std::map< std::string, std::set<std::string> > typeAppMap; // Stores mapping of types to apps that support them 2561 std::map< std::string, std::set<std::string> > fakeTypeAppMap; // Used to keep timing info for R5 and Haiku tests orthogonal 2562 2563 // Get a list of all the types in the database 2564 { 2565 BMessage msg; 2566 CHK(BMimeType::GetInstalledTypes(&msg) == B_OK); 2567 SetAdapter typeAdapter(typeList); 2568 FillWithMimeTypes(typeAdapter, msg, "types"); 2569 } 2570 2571 // Get a list of all the apps in the database 2572 { 2573 BMessage msg; 2574 CHK(BMimeType::GetInstalledTypes(applicationSupertype, &msg) == B_OK); 2575 SetAdapter appAdapter(appList); 2576 FillWithMimeTypes(appAdapter, msg, "types"); 2577 } 2578 2579 // For each app in the database, manually get a list of the MIME types 2580 // it supports by reading its META:FILE_TYPES attribute from the database, 2581 // and add the app to the type->app map for each such type 2582 { 2583 std::set<std::string>::iterator i; 2584 for (i = appList.begin(); i != appList.end(); i++) { 2585 // Grab the next application 2586 std::string app = *i; 2587 2588 // The leaf is all we're interested in -- it's the subtype 2589// CHK(StorageKit::split_path(app.c_str(), dir, leaf) == B_OK); 2590 std::string appFile = std::string(mimeDatabaseDir) + "/" + app; 2591// printf("'%s'\n", appFile.c_str()); 2592 BNode node(appFile.c_str()); 2593 CHK(node.InitCheck() == B_OK); 2594 2595 // Find out how much data there is in the META:FILE_TYPES attribute 2596 // (assuming it even exists, which it may not...) 2597 attr_info info; 2598 if (node.GetAttrInfo("META:FILE_TYPES", &info) == B_OK) { 2599// printf("attr_info: type == %lx, size == %lld\n", info.type, info.size); 2600 // Attribute exists, so alloc a buffer and read it 2601 char *buffer = new char[info.size+1]; 2602 CHK(node.ReadAttr("META:FILE_TYPES", B_MESSAGE_TYPE, 0, buffer, info.size) == info.size); 2603 BMessage msg; 2604 if (msg.Unflatten(buffer) == B_OK) { 2605// msg.PrintToStream(); 2606 2607 // Fill up a list with all the supported types 2608 std::set<std::string> supportList; 2609 SetAdapter supportAdapter(supportList); 2610 FillWithMimeTypes(supportAdapter, msg, "types"); 2611 2612 // For each type, add the current application as a supporting 2613 // app in our type->apps map 2614 for (std::set<std::string>::iterator type = supportList.begin(); 2615 type != supportList.end(); 2616 type++) 2617 { 2618 NextSubTest(); 2619 typeAppMap[*type].insert(app); 2620 fakeTypeAppMap[*type].insert(app); 2621 } 2622 } else { 2623 // Just in case some bozo writes something other than a flattened 2624 // BMessage to the META:FILE_TYPES attribute, we'll only issue a 2625 // warning when the BMessage can't unflatten itself 2626 printf("Warning: Unable to unflatten META:FILE_TYPES attribute for '%s' type.\n", 2627 app.c_str()); 2628 } 2629 2630 delete buffer; 2631 2632 } 2633 } 2634 } 2635 2636//#if !TEST_R5 2637 // Now, add in all the types listed in MIME_DB_DIR/__mime_table 2638 { 2639 BEntry entry((std::string(mimeDatabaseDir) + "/__mime_table").c_str()); 2640 CHK(entry.InitCheck() == B_OK); 2641 if (entry.Exists()) { 2642 BFile file(&entry, B_READ_ONLY); 2643 CHK(file.InitCheck() == B_OK); 2644 BMessage msg; 2645 CHK(msg.Unflatten(&file) == B_OK); 2646 2647// msg.PrintToStream(); 2648 2649 char *type; 2650 uint32 typeVal; 2651 int32 count; 2652 for (int i = 0; msg.GetInfo(B_STRING_TYPE, i, &type, &typeVal, &count) == B_OK; i++ ) { 2653 // Add all the associated applications. Interestingly (or maybe not), 2654 // any types appearing ONLY in the __mime_table and not in the mime 2655 // database fail when GetSupportingApps is called on them. Thus, we 2656 // add them to the type->app map, but not to the list of types. 2657 const char *app; 2658 for (int j = 0; j < count; j++) { 2659 CHK(msg.FindString(type, j, &app) == B_OK); 2660#if TEST_R5 2661 typeAppMap[type].insert(to_lower(app)); 2662#else 2663 fakeTypeAppMap[type].insert(to_lower(app)); 2664#endif 2665 } 2666 } 2667 } 2668 } 2669//#endif 2670 2671 // For each installed type, get a list of the supported apps, and 2672 // verify that the list matches the list we generated. Also check 2673 // that the list of apps for the type's supertype (if it exists) 2674 // is a subset of the list we generated for said supertype. 2675 for (std::set<std::string>::iterator i = typeList.begin(); i != typeList.end(); i++) { 2676 // Get the current type 2677 std::string type = *i; 2678 BMimeType mime(type.c_str()); 2679 CHK(mime.InitCheck() == B_OK); 2680// printf("------------------------------------------------------------\n"); 2681// printf("%s\n", type.c_str()); 2682 2683 // Get the set of supporting apps for this type (and its supertype, if 2684 // it's not a supertype itself) that we discovered by manually culling 2685 // the database 2686 std::set<std::string> appSetSuper; 2687 BMimeType superType; 2688 if (mime.GetSupertype(&superType) == B_OK) 2689 appSetSuper = typeAppMap[superType.Type()]; // Copy the supertype 2690/* 2691 printf("sub.size == %ld\n", appSet.size()); 2692 std::set<std::string>::iterator i; 2693 for (i = appSet.begin(); i != appSet.end(); i++) { 2694 printf(" %s\n", (*i).c_str()); 2695 } 2696 printf("super.size == %ld\n", appSetSuper.size()); 2697 for (i = appSetSuper.begin(); i != appSetSuper.end(); i++) { 2698 printf(" %s\n", (*i).c_str()); 2699 } 2700 char* str; 2701 if (mime.GetPreferredApp(str) == B_OK) { 2702 printf("preferred app:\n"); 2703 printf(" %s\n", str); 2704 } 2705*/ 2706 // Get the set of supporting apps via GetSupportingApps(), then 2707 // add them to a list. 2708 BMessage msg; 2709 CHK(mime.GetSupportingApps(&msg) == B_OK); 2710 std::queue<std::string> appList; 2711 QueueAdapter appAdapter(appList); 2712 FillWithMimeTypes(appAdapter, msg, "applications"); 2713 2714// msg.PrintToStream(); 2715 2716 2717 } 2718 } 2719} 2720 2721void 2722MimeTypeTest::WildcardAppsTest() { 2723 // NULL param 2724 NextSubTest(); 2725 { 2726#if TEST_R5 2727 CHK(BMimeType::GetWildcardApps(NULL) == B_OK); // R5 == B_OK (???) 2728#else 2729 CHK(BMimeType::GetWildcardApps(NULL) == B_BAD_VALUE); 2730#endif 2731 } 2732 // Normal function (compare to BMimeType("application/octet-stream").GetSupportingApps()) 2733 NextSubTest(); 2734 { 2735 BMessage msg1, msg2; 2736 CHK(BMimeType::GetWildcardApps(&msg1) == B_OK); 2737 BMimeType mime(wildcardType); 2738 CHK(mime.InitCheck() == B_OK); 2739 CHK(mime.GetSupportingApps(&msg2) == B_OK); 2740 CHK(msg1 == msg2); 2741 } 2742} 2743 2744 2745// init_long_types 2746static 2747void 2748init_long_types(char *notTooLongType, char *tooLongType) 2749{ 2750// R5: Allows buffer sizes up to `B_MIME_TYPE_LENGTH + 1' 2751// Haiku: We stay consistent: `*_LENGTH' defines the buffer size. 2752#ifdef TEST_R5 2753 const int notTooLongLength = B_MIME_TYPE_LENGTH; 2754#else 2755 const int notTooLongLength = B_MIME_TYPE_LENGTH - 1; 2756#endif 2757 const int tooLongLength = notTooLongLength + 1; 2758 strcpy(notTooLongType, "image/"); 2759 memset(notTooLongType + strlen(notTooLongType), 'a', 2760 notTooLongLength - strlen(notTooLongType)); 2761 notTooLongType[notTooLongLength] = '\0'; 2762 strcpy(tooLongType, "image/"); 2763 memset(tooLongType + strlen(tooLongType), 'a', 2764 tooLongLength - strlen(tooLongType)); 2765 tooLongType[tooLongLength] = '\0'; 2766} 2767 2768// InitTest 2769void 2770MimeTypeTest::InitTest() 2771{ 2772 // tests: 2773 // * constructors 2774 // * SetTo(), SetType() 2775 // * Unset() 2776 // * InitCheck() 2777 // (* Type()) 2778 2779 // We test only a few types here. Exhausting testing is done in 2780 // ValidityTest(). 2781 const char *validType = "image/gif"; 2782 const char *validType2 = "application/octet-stream"; 2783 const char *invalidType = "invalid type"; 2784 char notTooLongType[B_MIME_TYPE_LENGTH + 3]; 2785 char tooLongType[B_MIME_TYPE_LENGTH + 3]; 2786 init_long_types(notTooLongType, tooLongType); 2787 2788 // default constructor 2789 NextSubTest(); 2790 { 2791 BMimeType type; 2792 CHK(type.InitCheck() == B_NO_INIT); 2793 CHK(type.Type() == NULL); 2794 type.Unset(); 2795 CHK(type.InitCheck() == B_NO_INIT); 2796 CHK(type.Type() == NULL); 2797 } 2798 2799 // BMimeType(const char *) 2800 // valid type 2801 NextSubTest(); 2802 { 2803 BMimeType type(validType); 2804 CHK(type.InitCheck() == B_OK); 2805 CHK(string(type.Type()) == validType); 2806 type.Unset(); 2807 CHK(type.InitCheck() == B_NO_INIT); 2808 CHK(type.Type() == NULL); 2809 } 2810 // invalid type 2811 NextSubTest(); 2812 { 2813 BMimeType type(invalidType); 2814 CHK(type.InitCheck() == B_BAD_VALUE); 2815 CHK(type.Type() == NULL); 2816 type.Unset(); 2817 CHK(type.InitCheck() == B_NO_INIT); 2818 CHK(type.Type() == NULL); 2819 } 2820 // long, but not too long type 2821 NextSubTest(); 2822 { 2823 BMimeType type(notTooLongType); 2824 CHK(type.InitCheck() == B_OK); 2825 CHK(string(type.Type()) == notTooLongType); 2826 type.Unset(); 2827 CHK(type.InitCheck() == B_NO_INIT); 2828 CHK(type.Type() == NULL); 2829 } 2830 // too long type 2831 NextSubTest(); 2832 { 2833 BMimeType type(tooLongType); 2834 CHK(type.InitCheck() == B_BAD_VALUE); 2835 CHK(type.Type() == NULL); 2836 type.Unset(); 2837 CHK(type.InitCheck() == B_NO_INIT); 2838 CHK(type.Type() == NULL); 2839 } 2840 2841 // SetTo() 2842 // valid type 2843 NextSubTest(); 2844 { 2845 BMimeType type; 2846 CHK(type.SetTo(validType) == B_OK); 2847 CHK(type.InitCheck() == B_OK); 2848 CHK(string(type.Type()) == validType); 2849 type.Unset(); 2850 CHK(type.InitCheck() == B_NO_INIT); 2851 CHK(type.Type() == NULL); 2852 } 2853 // invalid type 2854 NextSubTest(); 2855 { 2856 BMimeType type; 2857 CHK(type.SetTo(invalidType) == B_BAD_VALUE); 2858 CHK(type.InitCheck() == B_BAD_VALUE); 2859 CHK(type.Type() == NULL); 2860 type.Unset(); 2861 CHK(type.InitCheck() == B_NO_INIT); 2862 CHK(type.Type() == NULL); 2863 } 2864 // long, but not too long type 2865 NextSubTest(); 2866 { 2867 BMimeType type; 2868 CHK(type.SetTo(notTooLongType) == B_OK); 2869 CHK(type.InitCheck() == B_OK); 2870 CHK(string(type.Type()) == notTooLongType); 2871 type.Unset(); 2872 CHK(type.InitCheck() == B_NO_INIT); 2873 CHK(type.Type() == NULL); 2874 } 2875 // too long type 2876 NextSubTest(); 2877 { 2878 BMimeType type; 2879 CHK(type.SetTo(tooLongType) == B_BAD_VALUE); 2880 CHK(type.InitCheck() == B_BAD_VALUE); 2881 CHK(type.Type() == NULL); 2882 type.Unset(); 2883 CHK(type.InitCheck() == B_NO_INIT); 2884 CHK(type.Type() == NULL); 2885 } 2886 2887 // SetType() 2888 // valid type 2889 NextSubTest(); 2890 { 2891 BMimeType type; 2892 CHK(type.SetType(validType) == B_OK); 2893 CHK(type.InitCheck() == B_OK); 2894 CHK(string(type.Type()) == validType); 2895 type.Unset(); 2896 CHK(type.InitCheck() == B_NO_INIT); 2897 CHK(type.Type() == NULL); 2898 } 2899 // invalid type 2900 NextSubTest(); 2901 { 2902 BMimeType type; 2903 CHK(type.SetType(invalidType) == B_BAD_VALUE); 2904 CHK(type.InitCheck() == B_BAD_VALUE); 2905 CHK(type.Type() == NULL); 2906 type.Unset(); 2907 CHK(type.InitCheck() == B_NO_INIT); 2908 CHK(type.Type() == NULL); 2909 } 2910 // long, but not too long type 2911 NextSubTest(); 2912 { 2913 BMimeType type; 2914 CHK(type.SetType(notTooLongType) == B_OK); 2915 CHK(type.InitCheck() == B_OK); 2916 CHK(string(type.Type()) == notTooLongType); 2917 type.Unset(); 2918 CHK(type.InitCheck() == B_NO_INIT); 2919 CHK(type.Type() == NULL); 2920 } 2921 // too long type 2922 NextSubTest(); 2923 { 2924 BMimeType type; 2925 CHK(type.SetType(tooLongType) == B_BAD_VALUE); 2926 CHK(type.InitCheck() == B_BAD_VALUE); 2927 CHK(type.Type() == NULL); 2928 type.Unset(); 2929 CHK(type.InitCheck() == B_NO_INIT); 2930 CHK(type.Type() == NULL); 2931 } 2932 2933 // reinitialization 2934 NextSubTest(); 2935 { 2936 BMimeType type(validType); 2937 CHK(type.InitCheck() == B_OK); 2938 CHK(string(type.Type()) == validType); 2939 CHK(type.SetTo(validType2) == B_OK); 2940 CHK(type.InitCheck() == B_OK); 2941 CHK(string(type.Type()) == validType2); 2942 } 2943 // bad args 2944 NextSubTest(); 2945 { 2946 BMimeType type(NULL); 2947 CHK(type.Type() == NULL); 2948 CHK(type.InitCheck() != B_OK); // R5 == B_NO_INIT, Haiku == B_BAD_VALUE 2949 CHK(type.Type() == NULL); 2950 CHK(type.SetTo(NULL) != B_OK); // R5 == B_NO_INIT, Haiku == B_BAD_VALUE 2951 CHK(type.Type() == NULL); 2952 CHK(type.SetType(NULL) != B_OK); // R5 == B_NO_INIT, Haiku == B_BAD_VALUE 2953 CHK(type.Type() == NULL); 2954 } 2955} 2956 2957// StringTest 2958void 2959MimeTypeTest::StringTest() 2960{ 2961 // tests: 2962 // * IsValid() (static/non static) 2963 // * Type() 2964 // * IsSupertypeOnly() 2965 // * GetSupertype() 2966 // * Contains() 2967 // * operator==() 2968 2969 char notTooLongType[B_MIME_TYPE_LENGTH + 3]; 2970 char tooLongType[B_MIME_TYPE_LENGTH + 3]; 2971 init_long_types(notTooLongType, tooLongType); 2972 struct mime_type_test { 2973 const char *type; 2974 bool super_type; 2975 status_t error; 2976 }; 2977 mime_type_test tests[] = { 2978 // valid types 2979 { "application", true, B_OK, }, 2980 { "application/octet-stream", false, B_OK, }, 2981 { "audio", true, B_OK, }, 2982 { "audio/x-aiff", false, B_OK, }, 2983 { "image", true, B_OK, }, 2984 { "image/gif", false, B_OK, }, 2985 { "message", true, B_OK, }, 2986 { "message/rfc822", false, B_OK, }, 2987 { "multipart", true, B_OK, }, 2988 { "multipart/mixed", false, B_OK, }, 2989 { "text", true, B_OK, }, 2990 { "text/plain", false, B_OK, }, 2991 { "video", true, B_OK, }, 2992 { "video/x-msvideo", false, B_OK, }, 2993 { "unknown", true, B_OK, }, 2994 { "unknown/mime-type", false, B_OK, }, 2995 { "$%&./`'~*+#|!^", false, B_OK, }, 2996 // invalid types 2997 { "", false, B_BAD_VALUE, }, 2998 { "application/", false, B_BAD_VALUE, }, 2999 { "audio/", false, B_BAD_VALUE, }, 3000 { "image/", false, B_BAD_VALUE, }, 3001 { "message/", false, B_BAD_VALUE, }, 3002 { "multipart/", false, B_BAD_VALUE, }, 3003 { "text/", false, B_BAD_VALUE, }, 3004 { "video/", false, B_BAD_VALUE, }, 3005 { "unknown/", false, B_BAD_VALUE, }, 3006 { "/gif", false, B_BAD_VALUE, }, 3007 { "image/very/nice", false, B_BAD_VALUE, }, 3008 { "tex t/plain", false, B_BAD_VALUE, }, 3009 { "text/pla in", false, B_BAD_VALUE, }, 3010 { "tex\tt/plain", false, B_BAD_VALUE, }, 3011 { "text/pla\tin", false, B_BAD_VALUE, }, 3012 { "tex\nt/plain", false, B_BAD_VALUE, }, 3013 { "text/pla\nin", false, B_BAD_VALUE, }, 3014 { "tex<t/plain", false, B_BAD_VALUE, }, 3015 { "text/pla<in", false, B_BAD_VALUE, }, 3016 { "tex>t/plain", false, B_BAD_VALUE, }, 3017 { "text/pla>in", false, B_BAD_VALUE, }, 3018 { "tex@t/plain", false, B_BAD_VALUE, }, 3019 { "text/pla@in", false, B_BAD_VALUE, }, 3020 { "tex,t/plain", false, B_BAD_VALUE, }, 3021 { "text/pla,in", false, B_BAD_VALUE, }, 3022 { "tex;t/plain", false, B_BAD_VALUE, }, 3023 { "text/pla;in", false, B_BAD_VALUE, }, 3024 { "tex:t/plain", false, B_BAD_VALUE, }, 3025 { "text/pla:in", false, B_BAD_VALUE, }, 3026 { "tex\"t/plain", false, B_BAD_VALUE, }, 3027 { "text/pla\"in", false, B_BAD_VALUE, }, 3028 { "tex(t/plain", false, B_BAD_VALUE, }, 3029 { "text/pla(in", false, B_BAD_VALUE, }, 3030 { "tex)t/plain", false, B_BAD_VALUE, }, 3031 { "text/pla)in", false, B_BAD_VALUE, }, 3032 { "tex[t/plain", false, B_BAD_VALUE, }, 3033 { "text/pla[in", false, B_BAD_VALUE, }, 3034 { "tex]t/pla]in", false, B_BAD_VALUE, }, 3035 { "tex?t/plain", false, B_BAD_VALUE, }, 3036 { "text/pla?in", false, B_BAD_VALUE, }, 3037 { "tex=t/plain", false, B_BAD_VALUE, }, 3038 { "text/pla=in", false, B_BAD_VALUE, }, 3039 { "tex\\t/plain", false, B_BAD_VALUE, }, 3040 { "text/pla\\in", false, B_BAD_VALUE, }, 3041 // (not) too long types 3042 { notTooLongType, false, B_OK, }, 3043 { tooLongType, false, B_BAD_VALUE, }, 3044 }; 3045 int32 testCount = sizeof(tests) / sizeof(mime_type_test); 3046 // test loop 3047 for (int32 i = 0; i < testCount; i++) { 3048 NextSubTest(); 3049 mime_type_test &test = tests[i]; 3050 BMimeType type(test.type); 3051 CHK(type.InitCheck() == test.error); 3052 bool valid = (test.error == B_OK); 3053 bool validSuper = (valid && test.super_type); 3054 // Type() 3055 if (valid) 3056 CHK(string(type.Type()) == test.type); 3057 else 3058 CHK(type.Type() == NULL); 3059 // IsValid(), IsSuperTypeOnly() 3060 CHK(type.IsValid() == valid); 3061 CHK(type.IsSupertypeOnly() == validSuper); 3062 CHK(BMimeType::IsValid(test.type) == valid); 3063 // GetSupertype() 3064 if (valid && !validSuper) { 3065 BMimeType super; 3066 CHK(type.GetSupertype(&super) == B_OK); 3067 CHK(super.InitCheck() == B_OK); 3068 CHK(super.Contains(&type) == true); 3069 BString typeString(test.type); 3070 BString superString(typeString.String(), 3071 typeString.FindFirst('/')); 3072 CHK(superString == super.Type()); 3073 } else { 3074 BMimeType super; 3075 CHK(type.GetSupertype(&super) == B_BAD_VALUE); 3076 } 3077 // Contains(), == 3078 for (int32 k = 0; k < testCount; k++) { 3079 mime_type_test &test2 = tests[k]; 3080 BMimeType type2(test2.type); 3081 CHK(type2.InitCheck() == test2.error); 3082 bool valid2 = (test2.error == B_OK); 3083 bool validSuper2 = (valid && test2.super_type); 3084 bool equal = (!strcmp(test.type, test2.type)); 3085 // == 3086 if (valid || valid2) { 3087 CHK((type == type2) == equal); 3088 CHK((type == test2.type) == equal); 3089 } else { 3090 CHK((type == type2) == false); 3091 CHK((type == test2.type) == false); 3092 } 3093 // Contains() 3094 if (valid || valid2) { 3095 if (equal) 3096 CHK(type.Contains(&type2) == true); 3097 else if (validSuper && valid2 && !validSuper2) { 3098 BMimeType super2; 3099 CHK(type2.GetSupertype(&super2) == B_OK); 3100 bool contains = string(super2.Type()) == type.Type(); 3101 CHK(type.Contains(&type2) == contains); 3102 } else 3103 CHK(type.Contains(&type2) == false); 3104 } else 3105 CHK(type.Contains(&type2) == false); 3106 } 3107 } 3108 // bad args 3109 NextSubTest(); 3110 { 3111 BMimeType type("image/gif"); 3112// R5: crashes when passing NULL 3113#if !TEST_R5 3114 CHK(BMimeType::IsValid(NULL) == false); 3115 CHK(type.GetSupertype(NULL) == B_BAD_VALUE); 3116 CHK(type.Contains(NULL) == false); 3117#endif 3118 CHK((type == NULL) == false); 3119 } 3120} 3121 3122// an easy to construct equivalent of a notification message 3123class NotificationMessage { 3124public: 3125 NotificationMessage(int32 which, string type, string extraType, 3126 bool largeIcon) 3127 : which(which), type(type), hasExtraType(true), extraType(extraType), 3128 hasLargeIcon(true), largeIcon(largeIcon) 3129 { 3130 } 3131 3132 NotificationMessage(int32 which, string type, string extraType) 3133 : which(which), type(type), hasExtraType(true), extraType(extraType), 3134 hasLargeIcon(false), largeIcon(false) 3135 { 3136 } 3137 3138 NotificationMessage(int32 which, string type, bool largeIcon) 3139 : which(which), type(type), hasExtraType(false), extraType(), 3140 hasLargeIcon(true), largeIcon(largeIcon) 3141 { 3142 } 3143 3144 NotificationMessage(int32 which, string type) 3145 : which(which), type(type), hasExtraType(false), extraType(), 3146 hasLargeIcon(false), largeIcon(false) 3147 { 3148 } 3149 3150public: 3151 int32 which; 3152 string type; 3153 bool hasExtraType; 3154 string extraType; 3155 bool hasLargeIcon; 3156 bool largeIcon; 3157}; 3158 3159// FillAttrInfo 3160static 3161void 3162FillAttrInfo(BMessage &info, int32 variation = 0) 3163{ 3164 switch (variation) { 3165 case 0: 3166 default: 3167 CHK(info.AddString("attr:name", "attribute1") == B_OK); 3168 CHK(info.AddString("attr:public_name", "Nice Attribute1") == B_OK); 3169 CHK(info.AddInt32("attr:type", B_STRING_TYPE) == B_OK); 3170 CHK(info.AddBool("attr:public", true) == B_OK); 3171 CHK(info.AddBool("attr:editable", true) == B_OK); 3172 break; 3173 case 1: 3174 CHK(info.AddString("attr:name", "attribute2") == B_OK); 3175 CHK(info.AddString("attr:public_name", "Nice Attribute2") == B_OK); 3176 CHK(info.AddInt32("attr:type", B_BOOL_TYPE) == B_OK); 3177 CHK(info.AddBool("attr:public", false) == B_OK); 3178 CHK(info.AddBool("attr:editable", false) == B_OK); 3179 break; 3180 } 3181} 3182 3183// MonitoringTest 3184void 3185MimeTypeTest::MonitoringTest() 3186{ 3187 // tests: 3188 // * Start/StopWatching() 3189 // * updates 3190 3191 // test: 3192 // * StartWatching() 3193 // * change something, check message queue (not empty) 3194 // - add type 3195 // - set icon, preferred app, attr info, file ext., short/long desc., 3196 // icon for, app hint, sniffer rule 3197 // - remove type 3198 // * StopWatching(anotherTarget) 3199 // * change something, check message queue (not empty) 3200 // * StopWatching() 3201 // * change something, check message queue (empty) 3202 3203 CHK(fApplication != NULL); 3204 NextSubTest(); 3205 // StartWatching() 3206 BMessenger target(&fApplication->Handler(), fApplication); 3207 CHK(BMimeType::StartWatching(target) == B_OK); 3208 // install 3209 BMimeType type(testType); 3210 CHK(type.InitCheck() == B_OK); 3211 CHK(type.IsInstalled() == false); 3212 CHK(type.Install() == B_OK); 3213 // icon 3214 IconHelper iconHelperLarge(B_LARGE_ICON); 3215 IconHelper iconHelperMini(B_MINI_ICON); 3216 CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); 3217 CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); 3218 // preferred app 3219 CHK(type.SetPreferredApp(testTypeApp) == B_OK); 3220 // attr info 3221 BMessage attrInfo; 3222 FillAttrInfo(attrInfo); 3223 CHK(type.SetAttrInfo(&attrInfo) == B_OK); 3224 // file extensions 3225 BMessage extensions; 3226 CHK(extensions.AddString("extensions", "arg") == B_OK); 3227 CHK(extensions.AddString("extensions", "ugh") == B_OK); 3228 CHK(type.SetFileExtensions(&extensions) == B_OK); 3229 // long/short description 3230 CHK(type.SetLongDescription("quite short for a long description") == B_OK); 3231 CHK(type.SetShortDescription("short description") == B_OK); 3232 // icon for type 3233 CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), 3234 B_LARGE_ICON) == B_OK); 3235 CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), 3236 B_MINI_ICON) == B_OK); 3237 // app hint 3238 entry_ref appHintRef; 3239 CHK(get_ref_for_path("/boot/beos/apps/StyledEdit", &appHintRef) == B_OK); 3240 CHK(type.SetAppHint(&appHintRef) == B_OK); 3241 // sniffer rule 3242 const char *snifferRule = "0.5 [0:0] ('ARGH')"; 3243 CHK(type.SetSnifferRule(snifferRule) == B_OK); 3244 { 3245 // - set icon, preferred app, attr info, file ext., short/long desc., 3246 // icon for, app hint, sniffer rule 3247 typedef NotificationMessage NM; 3248 NotificationMessage messages[] = { 3249 NM(B_MIME_TYPE_CREATED, testType), 3250 NM(B_ICON_CHANGED, testType, true), 3251 NM(B_ICON_CHANGED, testType, false), 3252 NM(B_PREFERRED_APP_CHANGED, testType), 3253 NM(B_ATTR_INFO_CHANGED, testType), 3254 NM(B_FILE_EXTENSIONS_CHANGED, testType), 3255 NM(B_LONG_DESCRIPTION_CHANGED, testType), 3256 NM(B_SHORT_DESCRIPTION_CHANGED, testType), 3257 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), 3258 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), 3259 NM(B_APP_HINT_CHANGED, testType), 3260 NM(B_SNIFFER_RULE_CHANGED, testType), 3261 }; 3262 CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); 3263 } 3264 3265 // set the same values once again 3266 NextSubTest(); 3267 // icon 3268 CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); 3269 CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); 3270 // preferred app 3271 CHK(type.SetPreferredApp(testTypeApp) == B_OK); 3272 // attr info 3273 CHK(type.SetAttrInfo(&attrInfo) == B_OK); 3274// file extensions 3275 CHK(extensions.AddString("extensions", "arg") == B_OK); 3276 CHK(extensions.AddString("extensions", "ugh") == B_OK); 3277 CHK(type.SetFileExtensions(&extensions) == B_OK); 3278 // long/short description 3279 CHK(type.SetLongDescription("quite short for a long description") == B_OK); 3280 CHK(type.SetShortDescription("short description") == B_OK); 3281 // icon for type 3282 CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), 3283 B_LARGE_ICON) == B_OK); 3284 CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), 3285 B_MINI_ICON) == B_OK); 3286 // app hint 3287 CHK(type.SetAppHint(&appHintRef) == B_OK); 3288 // sniffer rule 3289 CHK(type.SetSnifferRule(snifferRule) == B_OK); 3290 { 3291 // - set icon, preferred app, attr info, file ext., short/long desc., 3292 // icon for, app hint, sniffer rule 3293 typedef NotificationMessage NM; 3294 NotificationMessage messages[] = { 3295 NM(B_ICON_CHANGED, testType, true), 3296 NM(B_ICON_CHANGED, testType, false), 3297 NM(B_PREFERRED_APP_CHANGED, testType), 3298 NM(B_ATTR_INFO_CHANGED, testType), 3299 NM(B_FILE_EXTENSIONS_CHANGED, testType), 3300 NM(B_LONG_DESCRIPTION_CHANGED, testType), 3301 NM(B_SHORT_DESCRIPTION_CHANGED, testType), 3302 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), 3303 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), 3304 NM(B_APP_HINT_CHANGED, testType), 3305 NM(B_SNIFFER_RULE_CHANGED, testType), 3306 }; 3307 CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); 3308 } 3309 3310 // set different values 3311 NextSubTest(); 3312 // icon 3313 CHK(type.SetIcon(iconHelperLarge.Bitmap2(), B_LARGE_ICON) == B_OK); 3314 CHK(type.SetIcon(iconHelperMini.Bitmap2(), B_MINI_ICON) == B_OK); 3315 // preferred app 3316 CHK(type.SetPreferredApp("application/x-vnd.Be-STEE") == B_OK); 3317 // attr info 3318 BMessage attrInfo2; 3319 FillAttrInfo(attrInfo2, 1); 3320 CHK(type.SetAttrInfo(&attrInfo2) == B_OK); 3321 // file extensions 3322 CHK(extensions.AddString("extensions", "uff") == B_OK); 3323 CHK(extensions.AddString("extensions", "err") == B_OK); 3324 CHK(type.SetFileExtensions(&extensions) == B_OK); 3325 // long/short description 3326 CHK(type.SetLongDescription("not that short description") == B_OK); 3327 CHK(type.SetShortDescription("pretty short description") == B_OK); 3328 // icon for type 3329 CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap2(), 3330 B_LARGE_ICON) == B_OK); 3331 CHK(type.SetIconForType("text/plain", NULL, 3332 B_LARGE_ICON) == B_OK); 3333 CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap2(), 3334 B_MINI_ICON) == B_OK); 3335 // app hint 3336 entry_ref appHintRef2; 3337 CHK(get_ref_for_path("/boot/beos/apps/NetPositive", &appHintRef2) == B_OK); 3338 CHK(type.SetAppHint(&appHintRef2) == B_OK); 3339 // sniffer rule 3340 const char *snifferRule2 = "0.7 [0:5] ('YEAH!')"; 3341 CHK(type.SetSnifferRule(snifferRule2) == B_OK); 3342 // delete 3343 CHK(type.Delete() == B_OK); 3344 { 3345 // - set icon, preferred app, attr info, file ext., short/long desc., 3346 // icon for, app hint, sniffer rule 3347 typedef NotificationMessage NM; 3348 NotificationMessage messages[] = { 3349 NM(B_ICON_CHANGED, testType, true), 3350 NM(B_ICON_CHANGED, testType, false), 3351 NM(B_PREFERRED_APP_CHANGED, testType), 3352 NM(B_ATTR_INFO_CHANGED, testType), 3353 NM(B_FILE_EXTENSIONS_CHANGED, testType), 3354 NM(B_LONG_DESCRIPTION_CHANGED, testType), 3355 NM(B_SHORT_DESCRIPTION_CHANGED, testType), 3356 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), 3357 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", true), 3358 NM(B_ICON_FOR_TYPE_CHANGED, testType, "text/plain", false), 3359 NM(B_APP_HINT_CHANGED, testType), 3360 NM(B_SNIFFER_RULE_CHANGED, testType), 3361 NM(B_MIME_TYPE_DELETED, testType), 3362 }; 3363 CheckNotificationMessages(messages, sizeof(messages) / sizeof(NM)); 3364 } 3365 3366 // StopWatching() and try again -- no messages should be sent anymore 3367 CHK(BMimeType::StopWatching(target) == B_OK); 3368 // install 3369 CHK(type.InitCheck() == B_OK); 3370 CHK(type.IsInstalled() == false); 3371 CHK(type.Install() == B_OK); 3372 // icon 3373 CHK(type.SetIcon(iconHelperLarge.Bitmap1(), B_LARGE_ICON) == B_OK); 3374 CHK(type.SetIcon(iconHelperMini.Bitmap1(), B_MINI_ICON) == B_OK); 3375 // preferred app 3376 CHK(type.SetPreferredApp(testTypeApp) == B_OK); 3377 // attr info 3378 CHK(type.SetAttrInfo(&attrInfo) == B_OK); 3379 // file extensions 3380 CHK(extensions.AddString("extensions", "arg") == B_OK); 3381 CHK(extensions.AddString("extensions", "ugh") == B_OK); 3382 CHK(type.SetFileExtensions(&extensions) == B_OK); 3383 // long/short description 3384 CHK(type.SetLongDescription("quite short for a long description") == B_OK); 3385 CHK(type.SetShortDescription("short description") == B_OK); 3386 // icon for type 3387 CHK(type.SetIconForType("text/plain", iconHelperLarge.Bitmap1(), 3388 B_LARGE_ICON) == B_OK); 3389 CHK(type.SetIconForType("text/plain", iconHelperMini.Bitmap1(), 3390 B_MINI_ICON) == B_OK); 3391 // app hint 3392 CHK(type.SetAppHint(&appHintRef) == B_OK); 3393 // sniffer rule 3394 CHK(type.SetSnifferRule(snifferRule) == B_OK); 3395 // delete 3396 CHK(type.Delete() == B_OK); 3397 { 3398 CheckNotificationMessages(NULL, 0); 3399 } 3400 3401 // bad args 3402 // StopWatching() another target 3403 NextSubTest(); 3404 // install 3405 CHK(type.InitCheck() == B_OK); 3406 CHK(type.IsInstalled() == false); 3407 CHK(type.Install() == B_OK); 3408 // try to start/stop watching with an invalid target, stop the wrong target 3409 BMessenger target2(fApplication); 3410 CHK(target2.IsValid() == true); 3411 BMessenger target3("application/does-not_exist"); 3412 CHK(target3.IsValid() == false); 3413// R5: An invalid messenger is fine for any reason?! 3414#if !TEST_R5 3415 CHK(BMimeType::StartWatching(target3) == B_BAD_VALUE); 3416#endif 3417 CHK(BMimeType::StartWatching(target) == B_OK); 3418#if !TEST_R5 3419 CHK(BMimeType::StopWatching(target3) == B_BAD_VALUE); 3420#endif 3421 CHK(BMimeType::StopWatching(target2) != B_OK); // R5 == B_BAD_VALUE, Haiku == B_ENTRY_NOT_FOUND 3422 CHK(BMimeType::StopWatching(target) == B_OK); 3423 // delete 3424 CHK(type.Delete() == B_OK); 3425} 3426 3427// CheckNotificationMessage 3428void 3429MimeTypeTest::CheckNotificationMessages(const NotificationMessage *messages, 3430 int32 count) 3431{ 3432 // wait for the messages 3433 snooze(100000); 3434 if (fApplication) { 3435 BMessageQueue &queue = fApplication->Handler().Queue(); 3436 CPPUNIT_ASSERT( queue.Lock() ); 3437 try { 3438 int32 messageNum = 0; 3439 while (BMessage *_message = queue.NextMessage()) { 3440 BMessage message(*_message); 3441 delete _message; 3442//printf("\nmessage: %ld\n", messageNum); 3443//message.PrintToStream(); 3444 CPPUNIT_ASSERT( messageNum < count ); 3445 const NotificationMessage &entry = messages[messageNum]; 3446 CPPUNIT_ASSERT( message.what == B_META_MIME_CHANGED ); 3447 // which 3448 int32 which; 3449 CPPUNIT_ASSERT( message.FindInt32("be:which", &which) 3450 == B_OK ); 3451 CPPUNIT_ASSERT( entry.which == which ); 3452 // type 3453 const char *type; 3454 CPPUNIT_ASSERT( message.FindString("be:type", &type) == B_OK ); 3455 CPPUNIT_ASSERT( entry.type == type ); 3456 // extra type 3457 const char *extraType; 3458 if (entry.hasExtraType) { 3459 CPPUNIT_ASSERT( message.FindString("be:extra_type", 3460 &extraType) == B_OK); 3461 CPPUNIT_ASSERT( entry.extraType == extraType ); 3462 } else { 3463 CPPUNIT_ASSERT( message.FindString("be:extra_type", 3464 &extraType) == B_NAME_NOT_FOUND); 3465 } 3466 // large icon 3467 bool largeIcon; 3468 if (entry.hasLargeIcon) { 3469 CPPUNIT_ASSERT( message.FindBool("be:large_icon", 3470 &largeIcon) == B_OK); 3471 CPPUNIT_ASSERT( entry.largeIcon == largeIcon ); 3472 } else { 3473 CPPUNIT_ASSERT( message.FindBool("be:large_icon", 3474 &largeIcon) == B_NAME_NOT_FOUND); 3475 } 3476 messageNum++; 3477 } 3478 CPPUNIT_ASSERT( messageNum == count ); 3479 } catch (CppUnit::Exception exception) { 3480 queue.Unlock(); 3481 throw exception; 3482 } 3483 queue.Unlock(); 3484 } 3485} 3486 3487// helper class for update_mime_info() tests 3488class MimeInfoTestFile { 3489public: 3490 MimeInfoTestFile(string name, string type, const void *data = NULL, 3491 int32 size = -1) 3492 : name(name), 3493 type(type), 3494 data(NULL), 3495 size(0) 3496 { 3497 if (data) { 3498 if (size == -1) 3499 this->size = strlen((const char*)data) + 1; 3500 else 3501 this->size = size; 3502 this->data = new char[this->size]; 3503 memcpy(this->data, data, this->size); 3504 } 3505 } 3506 3507 ~MimeInfoTestFile() 3508 { 3509 delete[] data; 3510 } 3511 3512 status_t Create() 3513 { 3514 BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 3515 status_t error = file.InitCheck(); 3516 if (error == B_OK && data) { 3517 ssize_t written = file.Write(data, size); 3518 if (written < 0) 3519 error = written; 3520 else if (written != size) 3521 error = B_ERROR; 3522 } 3523 return error; 3524 } 3525 3526 status_t Delete() 3527 { 3528 return BEntry(name.c_str()).Remove(); 3529 } 3530 3531 string name; 3532 string type; 3533 char *data; 3534 int32 size; 3535}; 3536 3537// UpdateMimeInfoTest 3538void 3539MimeTypeTest::UpdateMimeInfoTest() 3540{ 3541// Uncomment the following lines to enjoy the quiet time provided 3542// by a nice, full mime update. :-) 3543 3544// cout << "begin..." << endl; 3545// CHK(update_mime_info(NULL, true, true, false) == B_OK); 3546// cout << "end..." << endl; 3547 3548 // tests: 3549 // * update_mime_info() 3550 3551 // Note: 3552 // * Only synchronous calls are tested. 3553 // * Updating all files is not tested as it takes too long. 3554 3555 // individual files 3556 execCommand(string("mkdir ") + testDir + "/subdir1 " 3557 + testDir + "/subdir2 " 3558 + testDir + "/subdir2/subsubdir1"); 3559 MimeInfoTestFile files[] = { 3560 MimeInfoTestFile(string(testDir) + "/file1.cpp", "text/x-source-code"), 3561 MimeInfoTestFile(string(testDir) + "/subdir1/file1.gif", "image/gif"), 3562 MimeInfoTestFile(string(testDir) + "/subdir2/subsubdir1/file1", 3563 "text/html", "<html>\n<body>\n</body></html>\n") 3564 }; 3565 int fileCount = sizeof(files) / sizeof(MimeInfoTestFile); 3566 // synchronous 3567 for (int32 i = 0; i < fileCount; i++) { 3568 NextSubTest(); 3569 MimeInfoTestFile &file = files[i]; 3570 // no recursion 3571 CHK(file.Create() == B_OK); 3572 CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK); 3573 BNode node(file.name.c_str()); 3574 CHK(node.InitCheck() == B_OK); 3575 BString type; 3576 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3577 node.Unset(); 3578 CHK(type == file.type.c_str()); 3579 CHK(file.Delete() == B_OK); 3580 // recursion 3581 CHK(file.Create() == B_OK); 3582 CHK(update_mime_info(file.name.c_str(), true, true, false) == B_OK); 3583 CHK(node.SetTo(file.name.c_str()) == B_OK); 3584 type = ""; 3585 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3586 node.Unset(); 3587 CHK(type == file.type.c_str()); 3588 CHK(file.Delete() == B_OK); 3589 } 3590 3591//------------------------------------------------------------------------------ 3592// Asynchronous calls 3593//------------------------------------------------------------------------------ 3594 3595 const bigtime_t kSnoozeTime = 500000; 3596 for (int32 i = 0; i < fileCount; i++) { 3597 NextSubTest(); 3598 MimeInfoTestFile &file = files[i]; 3599 // no recursion 3600 CHK(file.Create() == B_OK); 3601 CHK(update_mime_info(file.name.c_str(), false, false, false) == B_OK); 3602 // give the system some time to do the update asynchronously 3603 snooze(kSnoozeTime); 3604 BNode node(file.name.c_str()); 3605 CHK(node.InitCheck() == B_OK); 3606 BString type; 3607 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3608 node.Unset(); 3609 CHK(type == file.type.c_str()); 3610 CHK(file.Delete() == B_OK); 3611 // recursion 3612 CHK(file.Create() == B_OK); 3613 CHK(update_mime_info(file.name.c_str(), true, false, false) == B_OK); 3614 // give the system some time to do the update asynchronously 3615 snooze(kSnoozeTime); 3616 CHK(node.SetTo(file.name.c_str()) == B_OK); 3617 type = ""; 3618 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3619 node.Unset(); 3620 CHK(type == file.type.c_str()); 3621 CHK(file.Delete() == B_OK); 3622 } 3623 3624// TODO: The BeBook says: "if force is true, files are updated even if they've 3625// been updated already." 3626// As I understand this, calling update_mime_info() with force == true on a 3627// file, should set the BEOS:TYPE attribute regardless of whether it already 3628// had a value. The following test shows, that BEOS:TYPE remains unchanged 3629// though. 3630#if TEST_OBOS 3631 for (int32 i = 0; i < fileCount; i++) { 3632 MimeInfoTestFile &file = files[i]; 3633//printf("file: %s\n", file.name.c_str()); 3634 CHK(file.Create() == B_OK); 3635 // add a type attribute 3636 BNode node(file.name.c_str()); 3637 CHK(node.InitCheck() == B_OK); 3638 BString type("text/plain"); 3639 CHK(node.WriteAttrString("BEOS:TYPE", &type) == B_OK); 3640 // update, force == false 3641 CHK(update_mime_info(file.name.c_str(), false, true, false) == B_OK); 3642 type = ""; 3643 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3644 CHK(type == "text/plain"); 3645 // update, force == true 3646 CHK(update_mime_info(file.name.c_str(), false, true, true) == B_OK); 3647 type = ""; 3648 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3649 node.Unset(); 3650//printf("%s <-> %s\n", type.String(), file.type.c_str()); 3651 CHK(type == file.type.c_str()); 3652 CHK(file.Delete() == B_OK); 3653 } 3654#endif // TEST_OBOS 3655 3656 // directory 3657 NextSubTest(); 3658 // create 3659 for (int32 i = 0; i < fileCount; i++) { 3660 MimeInfoTestFile &file = files[i]; 3661 CHK(file.Create() == B_OK); 3662 } 3663 // update, not recursive 3664 CHK(update_mime_info(testDir, false, true, false) == B_OK); 3665 // check 3666 for (int32 i = 0; i < fileCount; i++) { 3667 MimeInfoTestFile &file = files[i]; 3668 BNode node(file.name.c_str()); 3669 CHK(node.InitCheck() == B_OK); 3670 BString type; 3671 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_ENTRY_NOT_FOUND); 3672 } 3673 // delete, re-create 3674 for (int32 i = 0; i < fileCount; i++) { 3675 MimeInfoTestFile &file = files[i]; 3676 CHK(file.Delete() == B_OK); 3677 CHK(file.Create() == B_OK); 3678 } 3679 // update, recursive 3680 CHK(update_mime_info(testDir, true, true, false) == B_OK); 3681 for (int32 i = 0; i < fileCount; i++) { 3682 MimeInfoTestFile &file = files[i]; 3683 BNode node(file.name.c_str()); 3684 CHK(node.InitCheck() == B_OK); 3685 BString type; 3686 CHK(node.ReadAttrString("BEOS:TYPE", &type) == B_OK); 3687 node.Unset(); 3688 CHK(type == file.type.c_str()); 3689 } 3690 // delete 3691 for (int32 i = 0; i < fileCount; i++) { 3692 MimeInfoTestFile &file = files[i]; 3693 CHK(file.Delete() == B_OK); 3694 } 3695 3696 // bad args: non-existing file 3697 NextSubTest(); 3698 BEntry entry(files[0].name.c_str()); 3699 CHK(entry.InitCheck() == B_OK); 3700 CHK(entry.Exists() == false); 3701//#if TEST_R5 3702 CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_OK); 3703//#else 3704// CHK(update_mime_info(files[0].name.c_str(), false, true, false) == B_ENTRY_NOT_FOUND); 3705//#endif 3706} 3707 3708// WriteStringAttr 3709static 3710status_t 3711WriteStringAttr(BNode &node, string name, string _value) 3712{ 3713 // Wrapper for BNode::WriteAttrString() taking string rather than 3714 // const char*/BString* parameters. 3715 BString value(_value.c_str()); 3716 return node.WriteAttrString(name.c_str(), &value); 3717} 3718 3719const uint32 MINI_ICON_TYPE = 'MICN'; 3720const uint32 LARGE_ICON_TYPE = 'ICON'; 3721 3722// helper class for create_app_meta_mime() tests 3723class AppMimeTestFile { 3724public: 3725 AppMimeTestFile(string name, string type, string signature, 3726 string snifferRule, 3727 const void *miniIcon = NULL, const void *largeIcon = NULL) 3728 : name(name), 3729 type(type), 3730 signature(signature), 3731 snifferRule(snifferRule), 3732 miniIcon(NULL), 3733 largeIcon(NULL) 3734 { 3735 SetMiniIcon(miniIcon); 3736 SetLargeIcon(largeIcon); 3737 } 3738 3739 ~AppMimeTestFile() 3740 { 3741 SetMiniIcon(NULL); 3742 SetLargeIcon(NULL); 3743 } 3744 3745 void SetMiniIcon(const void *icon) 3746 { 3747 if (miniIcon) { 3748 delete[] miniIcon; 3749 miniIcon = NULL; 3750 } 3751 if (icon) { 3752 miniIcon = new char[256]; 3753 memcpy(miniIcon, icon, 256); 3754 } 3755 } 3756 3757 void SetLargeIcon(const void *icon) 3758 { 3759 if (largeIcon) { 3760 delete[] largeIcon; 3761 largeIcon = NULL; 3762 } 3763 if (icon) { 3764 largeIcon = new char[1024]; 3765 memcpy(largeIcon, icon, 1024); 3766 } 3767 } 3768 3769 status_t Create(bool setAttributes, bool setResources) 3770 { 3771 BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 3772 status_t error = file.InitCheck(); 3773 // attributes 3774 if (error == B_OK && setAttributes) { 3775 // type 3776 if (type.length() > 0) 3777 error = WriteStringAttr(file, "BEOS:TYPE", type); 3778 // signature 3779 if (error == B_OK) 3780 error = WriteStringAttr(file, "BEOS:APP_SIG", signature); 3781 // sniffer rule 3782 if (error == B_OK) 3783 error = WriteStringAttr(file, "BEOS:SNIFF_RULE", snifferRule); 3784 // mini icon 3785 if (error == B_OK && miniIcon) { 3786 ssize_t written = file.WriteAttr("BEOS:M:STD_ICON", 3787 MINI_ICON_TYPE, 0, miniIcon, 3788 256); 3789 if (written < 0) 3790 error = written; 3791 else if (written != 256) 3792 error = B_ERROR; 3793 } 3794 // large icon (ignored) 3795 if (error == B_OK && largeIcon) { 3796 ssize_t written = file.WriteAttr("META:L:STD_ICON", 3797 LARGE_ICON_TYPE, 0, largeIcon, 3798 1024); 3799 if (written < 0) 3800 error = written; 3801 else if (written != 1024) 3802 error = B_ERROR; 3803 } 3804 } 3805 // resources 3806 if (error == B_OK && setResources) { 3807 BResources resources; 3808 error = resources.SetTo(&file, true); 3809 // type (ignored) 3810 if (error == B_OK && type.length() > 0) { 3811 error = resources.AddResource(B_STRING_TYPE, 2, type.c_str(), 3812 type.length() + 1, "BEOS:TYPE"); 3813 } 3814 // signature (ignored) 3815 if (error == B_OK) { 3816 error = resources.AddResource(B_STRING_TYPE, 1, 3817 signature.c_str(), 3818 signature.length() + 1, 3819 "BEOS:APP_SIG"); 3820 } 3821 // mini icon (ignored) 3822 if (error == B_OK && miniIcon) { 3823 error = resources.AddResource(MINI_ICON_TYPE, 101, miniIcon, 3824 256, "BEOS:M:STD_ICON"); 3825 } 3826 // file types (ignored) 3827 if (error == B_OK) { 3828 BMessage msg; 3829 char *buffer = NULL; 3830 error = msg.AddString("types", "text/x-email"); 3831 if (!error) 3832 error = msg.AddString("types", "video/mpeg"); 3833 if (!error) { 3834 buffer = new char[msg.FlattenedSize()]; 3835 if (!buffer) 3836 error = B_NO_MEMORY; 3837 } 3838 if (!error) 3839 error = msg.Flatten(buffer, msg.FlattenedSize()); 3840 if (!error) 3841 error = resources.AddResource(B_MESSAGE_TYPE, 1, buffer, 3842 msg.FlattenedSize(), "BEOS:FILE_TYPES"); 3843 delete [] buffer; 3844 } 3845 } 3846 return error; 3847 } 3848 3849 status_t Delete(bool deleteMimeType) 3850 { 3851 status_t error = BEntry(name.c_str()).Remove(); 3852 if (error == B_OK && deleteMimeType) { 3853 BMimeType type; 3854 // the type need not necessarily exist 3855 error = type.SetTo(signature.c_str()); 3856 if (error == B_OK && deleteMimeType && type.IsInstalled()) 3857 error = type.Delete(); 3858 } 3859 return error; 3860 } 3861 3862 string name; 3863 string type; 3864 string signature; 3865 string snifferRule; 3866 char *miniIcon; 3867 char *largeIcon; 3868}; 3869 3870// CheckAppMetaMime 3871static 3872void 3873CheckAppMetaMime(AppMimeTestFile &file) 3874{ 3875 BMimeType type; 3876 CHK(type.SetTo(file.signature.c_str()) == B_OK); 3877 CHK(type.IsInstalled() == true); 3878 // short description 3879 char shortDescription[B_MIME_TYPE_LENGTH + 1]; 3880 CHK(type.GetShortDescription(shortDescription) == B_OK); 3881 BPath path(file.name.c_str(), NULL, true); 3882 CHK(string(path.Leaf()) == shortDescription); 3883 // preferred app 3884 char preferredApp[B_MIME_TYPE_LENGTH + 1]; 3885 CHK(type.GetPreferredApp(preferredApp) == B_OK); 3886 CHK(file.signature == preferredApp); 3887 // META:PPATH 3888 BNode typeFile; 3889 string typeFilename(string(mimeDatabaseDir) + "/" + file.signature); 3890// cout << "typeFilename == '" << typeFilename << "'" << endl; 3891 CHK(typeFile.SetTo(typeFilename.c_str()) == B_OK); 3892 char filePath[B_PATH_NAME_LENGTH + 1]; 3893 CHK(typeFile.ReadAttr("META:PPATH", B_STRING_TYPE, 0, filePath, 3894 B_PATH_NAME_LENGTH + 1) > 0); 3895 CHK(path == filePath); 3896 // mini icon 3897 if (file.miniIcon) { 3898 BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8); 3899 CHK(type.GetIcon(&icon, B_MINI_ICON) == B_OK); 3900 CHK(memcmp(icon.Bits(), file.miniIcon, 256) == 0); 3901 } 3902 // large icon 3903/* if (file.miniIcon) { 3904 BBitmap icon(BRect(0, 0, 31, 31), B_CMAP8); 3905 CHK(type.GetIcon(&icon, B_LARGE_ICON) == B_OK); 3906 CHK(memcmp(icon.Bits(), file.largeIcon, 1024) == 0); 3907 }*/ 3908} 3909 3910// CreateAppMetaMimeTest 3911void 3912MimeTypeTest::CreateAppMetaMimeTest() 3913{ 3914 3915// Uncomment the following lines to enjoy the quiet time provided by 3916// a nice, full create_app_meta_mime() update. :-) 3917 3918// cout << "begin..." << endl; 3919// CHK(create_app_meta_mime(NULL, true, true, false) == B_OK); 3920// cout << "end" << endl; 3921 3922 // tests: 3923 // * create_app_meta_mime() 3924 3925 // Note: 3926 // * Only synchronous calls are tested. 3927 // * The recursive flag isn't tested -- the BeBook sais, it is unused. 3928 // * Updating all apps is not tested as it takes too long. 3929 3930 // Create a couple of icons to play around with 3931 char miniIcon1[256]; 3932 char miniIcon2[256]; 3933 for (int ch = 0; ch < 256; ch++) { 3934 miniIcon1[ch] = ch; 3935 miniIcon2[ch] = 255-ch; 3936 } 3937 char largeIcon1[1024]; 3938 char largeIcon2[1024]; 3939 for (int i = 0; i < 1024; i++) { 3940 char ch = i % 256; 3941 largeIcon1[i] = ch; 3942 largeIcon2[i] = 255-ch; 3943 } 3944 3945 // attributes and resources 3946 NextSubTest(); 3947 execCommand(string("mkdir ") + testDir + "/subdir1 " 3948 + testDir + "/subdir2 " 3949 + testDir + "/subdir2/subsubdir1"); 3950 AppMimeTestFile files[] = { 3951 // AppMimeTestFile(name, type, sig, rule, miniIcon, largeIcon) 3952 AppMimeTestFile(string(testDir) + "/file1", 3953 "", 3954 "application/x-vnd.obos.mime.test.test1", 3955 "0.0 ('abc')", 3956 miniIcon1, 3957 NULL), 3958 AppMimeTestFile(string(testDir) + "/file2", 3959 "text/x-source-code", 3960 "application/x-vnd.obos.mime.test.test2", 3961 "0.0 ('xyz')", 3962 miniIcon2, 3963 largeIcon2), 3964 AppMimeTestFile(string(testDir) + "/file3", 3965 "application/x-vnd.Be-elfexecutable", 3966 "application/x-vnd.obos.mime.test.test3", 3967 "0.0 ('rst')", 3968 NULL, 3969 largeIcon1), 3970 }; 3971 const int fileCount = sizeof(files) / sizeof(AppMimeTestFile); 3972//------------------------------------------------------------------------------ 3973// Synchronous calls 3974//------------------------------------------------------------------------------ 3975 for (int32 i = 0; i < fileCount; i++) { 3976 NextSubTest(); 3977 // create file, create_app_meta_mime() 3978 AppMimeTestFile &file = files[i]; 3979 CHK(file.Create(true, true) == B_OK); 3980 CHK(create_app_meta_mime(file.name.c_str(), false, true, false) 3981 == B_OK); 3982 // check the MIME type 3983 CheckAppMetaMime(file); 3984 // clean up 3985 CHK(file.Delete(true) == B_OK); 3986 } 3987// snooze(999000000); 3988 3989 // attributes only 3990 for (int32 i = 0; i < fileCount; i++) { 3991 NextSubTest(); 3992 // create file, create_app_meta_mime() 3993 AppMimeTestFile &file = files[i]; 3994 CHK(file.Create(true, false) == B_OK); 3995 CHK(create_app_meta_mime(file.name.c_str(), false, true, false) 3996 == B_OK); 3997 // check the MIME type 3998 CheckAppMetaMime(file); 3999 // clean up 4000 CHK(file.Delete(true) == B_OK); 4001 } 4002 4003 // resources only 4004 for (int32 i = 0; i < fileCount; i++) { 4005 NextSubTest(); 4006 // create file, create_app_meta_mime() 4007 AppMimeTestFile &file = files[i]; 4008 CHK(file.Create(false, true) == B_OK); 4009 CHK(create_app_meta_mime(file.name.c_str(), false, true, false) 4010 == B_OK); 4011 // check the MIME type 4012 BMimeType type; 4013 CHK(type.SetTo(file.signature.c_str()) == B_OK); 4014 CHK(type.IsInstalled() == false); 4015 // clean up 4016 CHK(file.Delete(false) == B_OK); 4017 } 4018 4019//------------------------------------------------------------------------------ 4020// Asynchronous calls 4021//------------------------------------------------------------------------------ 4022 const bigtime_t kSnoozeTime = 500000; 4023 for (int32 i = 0; i < fileCount; i++) { 4024 NextSubTest(); 4025 // create file, create_app_meta_mime() 4026 AppMimeTestFile &file = files[i]; 4027 CHK(file.Create(true, true) == B_OK); 4028 CHK(create_app_meta_mime(file.name.c_str(), false, false, false) 4029 == B_OK); 4030 // give the system some time to do the update asynchronously 4031 snooze(kSnoozeTime); 4032 // check the MIME type 4033 CheckAppMetaMime(file); 4034 // clean up 4035 CHK(file.Delete(true) == B_OK); 4036 } 4037 4038 // attributes only 4039 for (int32 i = 0; i < fileCount; i++) { 4040 NextSubTest(); 4041 // create file, create_app_meta_mime() 4042 AppMimeTestFile &file = files[i]; 4043 CHK(file.Create(true, false) == B_OK); 4044 CHK(create_app_meta_mime(file.name.c_str(), false, false, false) 4045 == B_OK); 4046 // give the system some time to do the update asynchronously 4047 snooze(kSnoozeTime); 4048 // check the MIME type 4049 CheckAppMetaMime(file); 4050 // clean up 4051 CHK(file.Delete(true) == B_OK); 4052 } 4053 4054 // resources only 4055 for (int32 i = 0; i < fileCount; i++) { 4056 NextSubTest(); 4057 // create file, create_app_meta_mime() 4058 AppMimeTestFile &file = files[i]; 4059 CHK(file.Create(false, true) == B_OK); 4060 CHK(create_app_meta_mime(file.name.c_str(), false, false, false) 4061 == B_OK); 4062 // give the system some time to do the update asynchronously 4063 snooze(kSnoozeTime); 4064 BMimeType type; 4065 CHK(type.SetTo(file.signature.c_str()) == B_OK); 4066 CHK(type.IsInstalled() == false); 4067 // clean up 4068 CHK(file.Delete(false) == B_OK); 4069 } 4070 4071 4072 // test the force flag 4073// TODO: The BeBook says: "If force is true, entries are created even if they 4074// already exist." 4075// As I understand this, re-calling create_app_meta_mime() with force == true, 4076// after modifying the original file (e.g. the mini icon attribute) or 4077// calling it on another file with the same signature, should update the 4078// database entry. But the following tests show, that this doesn't happen. 4079// They fail in the third CheckAppMetaMime(). 4080#if !TEST_R5 4081 // same file, same signature, other parameters 4082 { 4083 char icon1[256]; 4084 char icon2[256]; 4085 memset(icon1, 1, 256); 4086 memset(icon2, 2, 256); 4087 AppMimeTestFile file1(string(testDir) + "/file1", 4088 "application/x-vnd.Be-elfexecutable", 4089 "application/x-vnd.obos.mime.test.test1", 4090 icon1); 4091 AppMimeTestFile file2(string(testDir) + "/file1", 4092 "application/x-vnd.Be-elfexecutable", 4093 "application/x-vnd.obos.mime.test.test1", 4094 icon2); 4095 // create file 1, create_app_meta_mime() 4096 CHK(file1.Create(true, true) == B_OK); 4097 CHK(create_app_meta_mime(file1.name.c_str(), false, true, false) 4098 == B_OK); 4099 // check the MIME type 4100 CheckAppMetaMime(file1); 4101 // create file 2, create_app_meta_mime(), no force 4102 CHK(file2.Create(true, true) == B_OK); 4103 CHK(create_app_meta_mime(file2.name.c_str(), false, true, false) 4104 == B_OK); 4105 // check the MIME type 4106 CheckAppMetaMime(file1); 4107 // create_app_meta_mime(), force 4108 CHK(create_app_meta_mime(file2.name.c_str(), false, true, true) 4109 == B_OK); 4110 // check the MIME type 4111 CheckAppMetaMime(file2); 4112 // clean up 4113 CHK(file2.Delete(true) == B_OK); 4114 } 4115 // different file, same signature, other parameters 4116 { 4117 char icon1[256]; 4118 char icon2[256]; 4119 memset(icon1, 1, 256); 4120 memset(icon2, 2, 256); 4121 AppMimeTestFile file1(string(testDir) + "/file1", 4122 "application/x-vnd.Be-elfexecutable", 4123 "application/x-vnd.obos.mime.test.test1", 4124 icon1); 4125 AppMimeTestFile file2(string(testDir) + "/file2", 4126 "application/x-vnd.Be-elfexecutable", 4127 "application/x-vnd.obos.mime.test.test1", 4128 icon2); 4129 // create file 1, create_app_meta_mime() 4130 CHK(file1.Create(true, true) == B_OK); 4131 CHK(create_app_meta_mime(file1.name.c_str(), false, true, false) 4132 == B_OK); 4133 // check the MIME type 4134 CheckAppMetaMime(file1); 4135 // create file 2, create_app_meta_mime(), no force 4136 CHK(file2.Create(true, true) == B_OK); 4137 CHK(create_app_meta_mime(file2.name.c_str(), false, true, false) 4138 == B_OK); 4139 // check the MIME type 4140 CheckAppMetaMime(file1); 4141 // create_app_meta_mime(), force 4142 CHK(create_app_meta_mime(file2.name.c_str(), false, true, true) 4143 == B_OK); 4144 // check the MIME type 4145 CheckAppMetaMime(file2); 4146 // clean up 4147 CHK(file1.Delete(true) == B_OK); 4148 CHK(file2.Delete(true) == B_OK); 4149 } 4150#endif // !TEST_R5 4151 4152 // bad args 4153 NextSubTest(); 4154 // no signature 4155 CHK(files[0].Create(false, false) == B_OK); 4156 CHK(create_app_meta_mime(files[0].name.c_str(), false, true, false) 4157 == B_OK); 4158 CHK(files[0].Delete(false) == B_OK); 4159 // non-existing file 4160 CHK(create_app_meta_mime(files[0].name.c_str(), false, true, false) 4161 == B_OK); 4162 4163} 4164 4165// CheckIconData 4166static 4167void 4168CheckIconData(const char *device, int32 iconSize, const void* data) 4169{ 4170 // open the device 4171 int fd = open(device, O_RDONLY); 4172 CHK(fd != -1); 4173 // get the icon 4174 char buffer[1024]; 4175 device_icon iconData = { 4176 iconSize, 4177 buffer 4178 }; 4179 int error = ioctl(fd, B_GET_ICON, &iconData); 4180 // close the device 4181 CHK(close(fd) == 0); 4182 CHK(error == 0); 4183 // compare the icon data 4184 CHK(memcmp(data, buffer, iconSize * iconSize) == 0); 4185} 4186 4187// GetDeviceIconTest 4188void 4189MimeTypeTest::GetDeviceIconTest() 4190{ 4191 // tests: 4192 // * get_device_icon() 4193 4194 // test a volume device, a non-volume device, and an invalid dev name 4195 struct test_case { 4196 const char *path; 4197 bool valid; 4198 } testCases[] = { 4199 { "/dev/zero", false }, 4200 { "/boot", true }, 4201 { "/boot/home", false } 4202 }; 4203 const int testCaseCount = sizeof(testCases) / sizeof(test_case); 4204 for (int32 i = 0; i < testCaseCount; i++) { 4205 NextSubTest(); 4206 test_case &testCase = testCases[i]; 4207 // get device name from path name 4208 fs_info info; 4209 const char *deviceName = testCase.path; 4210 if (testCase.valid) { 4211 dev_t dev = dev_for_path(testCase.path); 4212 CHK(dev > 0); 4213 CHK(fs_stat_dev(dev, &info) == 0); 4214 deviceName = info.device_name; 4215 } 4216 // the two valid and one invalid icon size 4217 const int32 iconSizes[] = { 16, 32, 20 }; 4218 const bool validSizes[] = { true, true, false }; 4219 const int sizeCount = sizeof(iconSizes) / sizeof(int32); 4220 for (int32 k = 0; k < sizeCount; k++) { 4221 int32 size = iconSizes[k]; 4222 bool valid = testCase.valid && validSizes[k]; 4223 char buffer[1024]; 4224 if (valid) { 4225 CHK(get_device_icon(deviceName, buffer, size) == B_OK); 4226 CheckIconData(deviceName, size, buffer); 4227 // bad args: NULL buffer 4228// R5: Wanna see KDL? Here you go... 4229#if !TEST_R5 4230 CHK(get_device_icon(deviceName, NULL, size) == B_BAD_VALUE); 4231#endif 4232 } else 4233 CHK(get_device_icon(deviceName, buffer, size) != B_OK); 4234 } 4235 } 4236} 4237 4238// SnifferRuleTest 4239void 4240MimeTypeTest::SnifferRuleTest() 4241{ 4242 // tests: 4243 // * status_t GetSnifferRule(BString *result) const; 4244 // * status_t SetSnifferRule(const char *); 4245 // * static status_t CheckSnifferRule(const char *rule, BString *parseError); 4246 4247 // test a couple of valid and invalid rules 4248 struct test_case { 4249 const char *rule; 4250 const char *error; // NULL, if valid 4251 } testCases[] = { 4252 // valid rules 4253 { "1.0 (\"ABCD\")", NULL }, 4254 { "1.0 ('ABCD')", NULL }, 4255 { " 1.0 ('ABCD') ", NULL }, 4256 { "0.8 [0:3] ('ABCDEFG' | 'abcdefghij')", NULL }, 4257 { "0.5([10]'ABCD'|[17]'abcd'|[13]'EFGH')", NULL } , 4258 { "0.5 \n [0:3] \t ('ABCD' \n | 'abcd' | 'EFGH')", NULL }, 4259 { "0.8 [ 0 : 3 ] ('ABCDEFG' | 'abcdefghij')", NULL }, 4260 { "0.8 [0:3] ('ABCDEFG' & 'abcdefg')", NULL }, 4261// These two rules are accepted by the R5 sniffer checker, but not 4262// by the parser. Thus, we're not accepting them with either. 4263#if TEST_R5 4264 { "1.0 ('ABCD') | ('EFGH')", NULL }, 4265 { "1.0 [0:3] ('ABCD') | [2:4] ('EFGH')", NULL }, 4266#else 4267 { "1.0 ('ABCD') | ('EFGH')", "Sniffer pattern error: missing pattern" }, 4268 { "1.0 [0:3] ('ABCD') | [2:4] ('EFGH')", "Sniffer pattern error: missing pattern" }, 4269#endif 4270 { "0.8 [0:3] (\\077Mkl0x34 & 'abcdefgh')", NULL }, 4271 { "0.8 [0:3] (\\077034 & 'abcd')", NULL }, 4272 { "0.8 [0:3] (\\077\\034 & 'ab')", NULL }, 4273 { "0.8 [0:3] (\\77\\034 & 'ab')", NULL }, 4274 { "0.8 [0:3] (\\7 & 'a')", NULL }, 4275 { "0.8 [0:3] (\"\\17\" & 'a')", NULL }, 4276 { "0.8 [0:3] ('\\17' & 'a')", NULL }, 4277 { "0.8 [0:3] (\\g & 'a')", NULL }, 4278 { "0.8 [0:3] (\\g&\\b)", NULL }, 4279 { "0.8 [0:3] (\\g\\&b & 'abc')", NULL }, 4280 { "0.8 [0:3] (0x3457 & 'ab')", NULL }, 4281 { "0.8 [0:3] (0xA4b7 & 'ab')", NULL }, 4282 { "0.8 [0:3] ('ab\"' & 'abc')", NULL }, 4283 { "0.8 [0:3] (\"ab\\\"\" & 'abc')", NULL }, 4284 { "0.8 [0:3] (\"ab\\A\" & 'abc')", NULL }, 4285 { "0.8 [0:3] (\"ab'\" & 'abc')", NULL }, 4286 { "0.8 [0:3] (\"ab\\\\\" & 'abc')", NULL }, 4287 { "0.8 [-5:-3] (\"abc\" & 'abc')", NULL }, 4288// Also accepted by the R5 sniffer but not the R5 parser. We reject. 4289#if TEST_R5 4290 { "0.8 [5:3] (\"abc\" & 'abc')", NULL }, 4291#else 4292 { "0.8 [5:3] (\"abc\" & 'abc')", "Sniffer Parser Error -- Invalid range: [5:3]" }, 4293#endif 4294 { "1.0 ('ABCD')", NULL }, 4295 { ".2 ('ABCD')", NULL }, 4296 { "0. ('ABCD')", NULL }, 4297 { "1 ('ABCD')", NULL }, 4298 { "+1 ('ABCD')", NULL }, 4299// We accept extended notation floating point numbers now, but 4300// not invalid priorities. Thus our checker chokes on these rules, 4301// whilest R5's does not 4302#if TEST_R5 4303 { "1E25 ('ABCD')", NULL }, 4304 { "1e25 ('ABCD')", NULL }, 4305#else 4306 { "1E25 ('ABCD')", "Sniffer pattern error: invalid priority" }, 4307 { "1e25 ('ABCD')", "Sniffer pattern error: invalid priority" }, 4308#endif 4309 4310// R5 chokes on this rule :-( Why? I don't know. :-) 4311#if TEST_R5 4312 { "1e-3 ('ABCD')", "Sniffer pattern error: missing pattern" }, 4313#else 4314 { "1e-3 ('ABCD')", NULL }, 4315#endif 4316 { "+.003e2 ('ABCD')", NULL }, 4317// R5 chokes on this one too. See how much better our checker/parser is? ;-) 4318#if TEST_R5 4319 { "-123e-9999999999 ('ABCD')", "Sniffer pattern error: bad token" }, // Hooray for the stunning accuracy of floating point :-) 4320#else 4321 { "-123e-9999999999 ('ABCD')", NULL }, // Hooray for the stunning accuracy of floating point :-) 4322#endif 4323 // invalid rules 4324 { "0.0 ('')", 4325 "Sniffer pattern error: illegal empty pattern" }, 4326 { "('ABCD')", 4327 "Sniffer pattern error: match level expected" }, 4328 { "[0:3] ('ABCD')", 4329 "Sniffer pattern error: match level expected" }, 4330 { "0.8 [0:3] ( | 'abcdefghij')", 4331 "Sniffer pattern error: missing pattern" }, 4332 { "0.8 [0:3] ('ABCDEFG' | )", 4333 "Sniffer pattern error: missing pattern" }, 4334 { "[0:3] ('ABCD')", 4335 "Sniffer pattern error: match level expected" }, 4336 { "1.0 (ABCD')", 4337#if TEST_R5 4338 "Sniffer pattern error: misplaced single quote" 4339#else 4340 "Sniffer pattern error: invalid character 'A'" 4341#endif 4342 }, 4343 { "1.0 ('ABCD)", 4344#if TEST_R5 4345 "Sniffer pattern error: unterminated rule" 4346#else 4347 "Sniffer pattern error: unterminated single-quoted string" 4348#endif 4349 }, 4350 { "1.0 (ABCD)", 4351#if TEST_R5 4352 "Sniffer pattern error: missing pattern" 4353#else 4354 "Sniffer pattern error: invalid character 'A'" 4355#endif 4356 }, 4357 { "1.0 (ABCD 'ABCD')", 4358#if TEST_R5 4359 "Sniffer pattern error: missing pattern" 4360#else 4361 "Sniffer pattern error: invalid character 'A'" 4362#endif 4363 }, 4364 { "1.0 'ABCD')", 4365#if TEST_R5 4366 "Sniffer pattern error: missing pattern" 4367#else 4368 "Sniffer pattern error: missing pattern" 4369#endif 4370 }, 4371 { "1.0 ('ABCD'", 4372 "Sniffer pattern error: unterminated rule" }, 4373 { "1.0 'ABCD'", 4374#if TEST_R5 4375 "Sniffer pattern error: missing sniff pattern" 4376#else 4377 "Sniffer pattern error: missing pattern" 4378#endif 4379 }, 4380 { "0.5 [0:3] ('ABCD' | 'abcd' | [13] 'EFGH')", 4381 "Sniffer pattern error: missing pattern" }, 4382 { "0.5('ABCD'|'abcd'|[13]'EFGH')", 4383 "Sniffer pattern error: missing pattern" }, 4384 { "0.5[0:3]([10]'ABCD'|[17]'abcd'|[13]'EFGH')", 4385 "Sniffer pattern error: missing pattern" }, 4386 { "0.8 [0x10:3] ('ABCDEFG' | 'abcdefghij')", 4387 "Sniffer pattern error: pattern offset expected" }, 4388 { "0.8 [0:A] ('ABCDEFG' | 'abcdefghij')", 4389#if TEST_R5 4390 "Sniffer pattern error: pattern range end expected" 4391#else 4392 "Sniffer pattern error: invalid character 'A'" 4393#endif 4394 }, 4395 { "0.8 [0:3] ('ABCDEFG' & 'abcdefghij')", 4396 "Sniffer pattern error: pattern and mask lengths do not match" }, 4397 { "0.8 [0:3] ('ABCDEFG' & 'abcdefg' & 'xyzwmno')", 4398#if TEST_R5 4399 "Sniffer pattern error: unterminated rule" 4400#else 4401 "Sniffer pattern error: expecting '|', ')', or possibly '&'" 4402#endif 4403 }, 4404 { "0.8 [0:3] (\\g&b & 'a')", 4405#if TEST_R5 4406 "Sniffer pattern error: missing mask" 4407#else 4408 "Sniffer pattern error: invalid character 'b'" 4409#endif 4410 }, 4411 { "0.8 [0:3] (\\19 & 'a')", 4412 "Sniffer pattern error: pattern and mask lengths do not match" }, 4413 { "0.8 [0:3] (0x345 & 'ab')", 4414 "Sniffer pattern error: bad hex literal" }, 4415 { "0.8 [0:3] (0x3457M & 'abc')", 4416#if TEST_R5 4417 "Sniffer pattern error: expecting '|' or '&'" 4418#else 4419 "Sniffer pattern error: invalid character 'M'" 4420#endif 4421 }, 4422 { "0.8 [0:3] (0x3457\\7 & 'abc')", 4423#if TEST_R5 4424 "Sniffer pattern error: expecting '|' or '&'" 4425#else 4426 "Sniffer pattern error: expecting '|', ')', or possibly '&'" 4427#endif 4428 }, 4429 4430 // Miscellaneous tests designed to hit every remaining 4431 // relevant "throw new Err()" statement in our scanner. 4432 // R5 versions may come later, but I don't really see any 4433 // good reason why at this point... 4434#if !TEST_R5 4435 { "\x03 ", "Sniffer pattern error: invalid character '\x03'" }, 4436 { "\"blah", "Sniffer pattern error: unterminated double-quoted string" }, 4437 { "0xThisIsNotAHexCode", "Sniffer pattern error: incomplete hex code" }, 4438 { "0xAndNeitherIsThis:-)", "Sniffer pattern error: bad hex literal" }, 4439 { ".NotAFloat", "Sniffer pattern error: incomplete floating point number" }, 4440 { "-NotANumber", "Sniffer pattern error: incomplete signed number" }, 4441 { "+NotANumber", "Sniffer pattern error: incomplete signed number" }, 4442 4443 { "0.0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4444 { "1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4445 { ".0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4446 { "0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4447 { "1e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4448 { "-1e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4449 { "+1e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4450 { "-1.e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4451 { "+1.e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4452 { "-1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4453 { "+1.0e", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4454 4455 { "0.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4456 { "1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4457 { ".0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4458 { "0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4459 { "1e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4460 { "-1e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4461 { "+1e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4462 { "-1.e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4463 { "+1.e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4464 { "-1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4465 { "+1.0e-", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4466 4467 { "0.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4468 { "1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4469 { ".0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4470 { "0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4471 { "1e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4472 { "-1e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4473 { "+1e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4474 { "-1.e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4475 { "+1.e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4476 { "-1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4477 { "+1.0e+", "Sniffer pattern error: incomplete extended-notation floating point number" }, 4478 4479 { "\\11\\", "Sniffer pattern error: incomplete escape sequence" }, 4480 { "\"Escape!! \\", "Sniffer pattern error: incomplete escape sequence" }, 4481 { "'Escape!! \\", "Sniffer pattern error: incomplete escape sequence" }, 4482 4483 { "\\x", "Sniffer pattern error: incomplete escaped hex code" }, 4484 { "\\xNotAHexCode", "Sniffer pattern error: incomplete escaped hex code" }, 4485 { "\\xAlsoNotAHexCode", "Sniffer pattern error: incomplete escaped hex code" }, 4486 { "\\x0", "Sniffer pattern error: incomplete escaped hex code" }, 4487 4488 { "1.0 (\\377)", NULL }, 4489 { "\\400", "Sniffer pattern error: invalid octal literal (octals must be between octal 0 and octal 377 inclusive)" }, 4490 { "\\777", "Sniffer pattern error: invalid octal literal (octals must be between octal 0 and octal 377 inclusive)" }, 4491 { "1.0 (\\800)", NULL }, 4492 4493 { NULL, "Sniffer pattern error: NULL pattern" }, 4494 4495 { "-2", "Sniffer pattern error: invalid priority" }, 4496 { "+2", "Sniffer pattern error: invalid priority" }, 4497 4498 { "1.0", "Sniffer pattern error: missing expression" }, 4499#endif // !TEST_R5 4500 4501//! \todo Our parser chokes on this rule and I have no idea why 4502// I don't currently understand what's wrong with the following rule... 4503// R5 rejects it though, for whatever reason. 4504#if TEST_R5 4505 { "1E-25 ('ABCD')", "Sniffer pattern error: missing pattern" }, 4506#else 4507// { "1E-25 ('ABCD')", NULL }, 4508#endif 4509 }; 4510 4511 const int testCaseCount = sizeof(testCases) / sizeof(test_case); 4512 BMimeType type; 4513 CHK(type.SetTo(testType) == B_OK); 4514 CHK(type.Install() == B_OK); 4515 for (int32 i = 0; i < testCaseCount; i++) { 4516 NextSubTest(); 4517 test_case &testCase = testCases[i]; 4518 BString parseError; 4519 status_t error = BMimeType::CheckSnifferRule(testCase.rule, 4520 &parseError); 4521// printf("\n---------------------\n"); 4522// printf("rule == '%s', %s\n", testCase.rule, (testCase.error ? "should not pass" : "should pass")); 4523 if (testCase.error == NULL) { 4524if (error != B_OK) 4525printf("\nerror:\n%s\n", parseError.String()); 4526 CHK(error == B_OK); 4527 CHK(type.SetSnifferRule(testCase.rule) == B_OK); 4528 BString rule; 4529 CHK(type.GetSnifferRule(&rule) == B_OK); 4530 CHK(rule == testCase.rule); 4531 } else { 4532// printf("error == 0x%lx\n", error); 4533// if (parseError.FindLast(testCase.error) < 0) { 4534// printf("\nexpected:\n%s\n", testCase.error); 4535// printf("\nfound:\n%s\n", parseError.String()); 4536// } 4537 CHK(error == (testCase.rule ? B_BAD_MIME_SNIFFER_RULE : B_BAD_VALUE)); 4538 CHK(parseError.FindLast(testCase.error) >= 0); 4539 4540// R5 treats a NULL rule string as an error, and thus R5::SetSnifferRule(NULL) fails. 4541// We also treat a NULL rule string as an error, but OBOS::SetSnifferRule(NULL) does 4542// not fail, as all OBOS::BMimeType::Set*(NULL) calls are equivalent to the 4543// corresponding OBOS::BMimeType::Delete*() calls. 4544#if TEST_R5 4545 CHK(type.SetSnifferRule(testCase.rule) == B_BAD_MIME_SNIFFER_RULE); 4546#else 4547 if (testCase.rule) 4548 CHK(type.SetSnifferRule(testCase.rule) == B_BAD_MIME_SNIFFER_RULE); 4549 else 4550 CHK(type.SetSnifferRule(testCase.rule) == B_OK); 4551#endif 4552 } 4553 } 4554 4555 // bad args: NULL rule/result string 4556 NextSubTest(); 4557 BString parseError; 4558 CHK(BMimeType::CheckSnifferRule("0.0 ('')", NULL) 4559 == B_BAD_MIME_SNIFFER_RULE); 4560// R5: crashes when passing a NULL rule/result buffer. 4561#if !TEST_R5 4562 CHK(BMimeType::CheckSnifferRule(NULL, &parseError) == B_BAD_VALUE); 4563 CHK(BMimeType::CheckSnifferRule(NULL, NULL) == B_BAD_VALUE); 4564 CHK(type.GetSnifferRule(NULL) == B_BAD_VALUE); 4565#endif 4566 4567 BString rule; 4568 4569 // NULL rule to SetSnifferRule unsets the attribute 4570 NextSubTest(); 4571#if TEST_R5 4572 CHK(type.IsInstalled() == true); 4573 CHK(type.SetSnifferRule(NULL) == B_OK); 4574 CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); 4575#else 4576 CHK(type.IsInstalled() == true); 4577 if (type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND) 4578 CHK(type.SetSnifferRule("0.0 ('abc')") == B_OK); 4579 CHK(type.GetSnifferRule(&rule) == B_OK); 4580 CHK(type.SetSnifferRule(NULL) == B_OK); 4581 CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); 4582 CHK(type.SetSnifferRule(NULL) == B_ENTRY_NOT_FOUND); 4583#endif 4584 4585 // bad args: uninstalled type 4586 CHK(type.Delete() == B_OK); 4587 CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); 4588 CHK(type.SetSnifferRule("0.0 ('ABC')") == B_OK); 4589#if TEST_R5 4590 CHK(type.GetSnifferRule(&rule) == B_ENTRY_NOT_FOUND); 4591#else 4592 CHK(type.GetSnifferRule(&rule) == B_OK); 4593#endif 4594 4595 // bad args: uninitialized BMimeType 4596 type.Unset(); 4597 CHK(type.GetSnifferRule(&rule) != B_OK); 4598 CHK(type.SetSnifferRule("0.0 ('ABC')") != B_OK); 4599} 4600 4601// helper class for GuessMimeType() tests 4602class SniffingTestFile { 4603public: 4604 SniffingTestFile(string name, string extensionType, string contentType, 4605 const void *data = NULL, int32 size = -1, string metaType = "") 4606 : name(name) 4607 , extensionType(extensionType) 4608 , contentType(contentType) 4609 , data(NULL) 4610 , size(0) 4611 , metaType(metaType) 4612 { 4613 // replace wildcard types 4614 if (this->extensionType == "") 4615 this->extensionType = "application/octet-stream"; 4616 if (this->contentType == "") 4617 this->contentType = "application/octet-stream"; 4618 // copy data 4619 if (data) { 4620 if (size == -1) 4621 this->size = strlen((const char*)data) + 1; 4622 else 4623 this->size = size; 4624 this->data = new char[this->size]; 4625 memcpy(this->data, data, this->size); 4626 } 4627 } 4628 4629 ~SniffingTestFile() 4630 { 4631 delete[] data; 4632 } 4633 4634 status_t Create() 4635 { 4636 BFile file(name.c_str(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 4637 ssize_t error = file.InitCheck(); 4638 if (error == B_OK && data) { 4639 ssize_t written = file.Write(data, size); 4640 if (written < 0) 4641 error = written; 4642 else if (written != size) 4643 error = B_ERROR; 4644 } 4645 if (!error && metaType.length() > 0) { 4646 error = file.WriteAttr("META:TYPE", B_STRING_TYPE, 0, metaType.c_str(), 4647 metaType.length()+1); 4648 error = error == (ssize_t)(metaType.length()+1) ? B_OK : error; 4649 } 4650 return error; 4651 } 4652 4653 status_t Delete() 4654 { 4655 return BEntry(name.c_str()).Remove(); 4656 } 4657 4658 string name; 4659 string extensionType; 4660 string contentType; 4661 char *data; 4662 int32 size; 4663 string metaType; 4664}; 4665 4666// SniffingTest 4667void 4668MimeTypeTest::SniffingTest() 4669{ 4670 // tests: 4671 // * GuessMimeType() 4672 4673 // install some test types with sniffer rules 4674 { 4675 BMimeType type; 4676 CHK(type.SetTo(testType) == B_OK); 4677 CHK(type.Install() == B_OK); 4678 CHK(type.SetSnifferRule("0.5 [0:1] ('ABCD_EFGH' & 0xffffffff00ffffffff)") 4679 == B_OK); 4680 CHK(type.SetTo(testType1) == B_OK); 4681 CHK(type.Install() == B_OK); 4682 CHK(type.SetSnifferRule("0.4 ('ABCD')") == B_OK); 4683 CHK(type.SetTo(testType2) == B_OK); 4684 CHK(type.Install() == B_OK); 4685#if TEST_R5 4686 // This rule is invalid! 4687 CHK(type.SetSnifferRule("0.4 [0] ('XYZ') | [0:5] ('CD E')") == B_OK); 4688#else 4689// CHK(type.SetSnifferRule("0.4 ([0] 'XYZ' | [0:5] 'CD E')") == B_OK); 4690#endif 4691 CHK(type.SetTo(testType3) == B_OK); 4692 CHK(type.Install() == B_OK); 4693 CHK(type.SetSnifferRule("0.3 [0:8] ('ABCD' | 'EFGH')") == B_OK); 4694 CHK(type.SetTo(testType4) == B_OK); 4695 CHK(type.Install() == B_OK); 4696 CHK(type.SetSnifferRule("0.2 [0:3] ('ABCD' | 'abcd')") == B_OK); 4697 CHK(type.SetTo(testType5) == B_OK); 4698 CHK(type.Install() == B_OK); 4699 CHK(type.SetSnifferRule("0.2 ('LMNO' & 0xfffeffff)") == B_OK); 4700 } 4701 4702 SniffingTestFile files[] = { 4703 SniffingTestFile(string(testDir) + "/file1.cpp", 4704 "text/x-source-code", ""), 4705 SniffingTestFile(string(testDir) + "/file2.gif", 4706 "image/gif", ""), 4707 SniffingTestFile(string(testDir) + "/file3", 4708 "", "text/html", 4709 "<html>\n<body>\n</body></html>\n"), 4710 SniffingTestFile(string(testDir) + "/file4.cpp", 4711 "text/x-source-code", "text/html", 4712 "<html>\n<body>\n</body></html>\n"), 4713 SniffingTestFile(string(testDir) + "/file5", "", testType1, "ABCD"), 4714 SniffingTestFile(string(testDir) + "/file6", "", testType3, " ABCD"), 4715 SniffingTestFile(string(testDir) + "/file7", "", testType4, "abcd"), 4716 SniffingTestFile(string(testDir) + "/file8", "", testType3, 4717 " ABCDEFGH"), 4718 SniffingTestFile(string(testDir) + "/file9", "", testType, 4719 " ABCD EFGH"), 4720// SniffingTestFile(string(testDir) + "/file10", "", testType2, 4721 SniffingTestFile(string(testDir) + "/file10", "", testType3, 4722 " ABCD EFGH"), 4723 SniffingTestFile(string(testDir) + "/file11", "", testType5, 4724 "LMNO"), 4725 SniffingTestFile(string(testDir) + "/file12", "", testType5, 4726 "LLNO"), 4727 SniffingTestFile(string(testDir) + "/file13", "", "", 4728 "LNNO"), 4729 // meta mime test 4730// bonefish: TODO: Now that content sniffing is enabled again, this doesn't 4731// work properly anymore, since there are actually three types involved: The 4732// extension type ("text/html"), the content type (also "text/html") and the 4733// real type ("application/x-vnd.be-meta-mime") which is concluded from the 4734// existence of the "META:TYPE" attribute rather than the extension or content. 4735//#if !TEST_R5 4736// SniffingTestFile(string(testDir) + "/file14.html", 4737// "text/html", "application/x-vnd.be-meta-mime", 4738// "<html>\n<body>\n</body></html>\n", -1, 4739// "fake-meta-mime-string"), 4740//#endif // !TEST_R5 4741 }; 4742 int fileCount = sizeof(files) / sizeof(SniffingTestFile); 4743 for (int32 i = 0; i < fileCount; i++) { 4744 NextSubTest(); 4745 SniffingTestFile &file = files[i]; 4746 const char *filename = file.name.c_str(); 4747//printf("file: %s\n", filename); 4748 const char *extensionType = file.extensionType.c_str(); 4749 const char *contentType = file.contentType.c_str(); 4750 const char *realType = contentType; 4751 if (file.contentType == "application/octet-stream") 4752 realType = extensionType; 4753 // GuessMimeType(const char*,) 4754 BMimeType type; 4755 CHK(BMimeType::GuessMimeType(filename, &type) == B_OK); 4756//printf("type: `%s', extensionType: `%s'\n", type.Type(), extensionType); 4757 CHK(type == extensionType); 4758 type.Unset(); 4759 // GuessMimeType(const void*, int32,) 4760 if (file.data != NULL) { 4761 CHK(BMimeType::GuessMimeType(file.data, file.size, &type) == B_OK); 4762if (!(type == contentType)) 4763printf("type: %s, should be: %s\n", type.Type(), realType); 4764 CHK(type == contentType); 4765 type.Unset(); 4766 } 4767 CHK(file.Create() == B_OK); 4768 // set BEOS:TYPE to something confusing ;-) 4769 BNode node; 4770 CHK(node.SetTo(filename) == B_OK); 4771 CHK(WriteStringAttr(node, "BEOS:TYPE", "application/x-person") == B_OK); 4772 // GuessMimeType(const ref*,) 4773 entry_ref ref; 4774 CHK(get_ref_for_path(filename, &ref) == B_OK); 4775 CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK); 4776if (!(type == realType)) 4777printf("type: %s, should be: %s (file == '%s')\n", type.Type(), realType, filename); 4778 CHK(type == realType); 4779 type.Unset(); 4780 CHK(file.Delete() == B_OK); 4781 } 4782 4783 // GuessMimeType(const ref*,), invalid/abstract entry 4784 { 4785 NextSubTest(); 4786 string filename = string(testDir) + "/file100.cpp"; 4787 BMimeType type; 4788 entry_ref ref; 4789// invalid entry_ref: R5: Is fine! Haiku: no dice 4790#if TEST_R5 4791 CHK(BMimeType::GuessMimeType(&ref, &type) == B_OK); 4792 CHK(type == "application/octet-stream"); 4793#else 4794 CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK); 4795#endif 4796 // abstract entry_ref 4797 CHK(get_ref_for_path(filename.c_str(), &ref) == B_OK); 4798 // R5: B_NAME_NOT_FOUND, Haiku: 4799 CHK(BMimeType::GuessMimeType(&ref, &type) != B_OK); 4800 } 4801 4802 // bad args 4803 { 4804 NextSubTest(); 4805 SniffingTestFile &file = files[0]; 4806 CHK(file.Create() == B_OK); 4807 const char *filename = file.name.c_str(); 4808 entry_ref ref; 4809 CHK(get_ref_for_path(filename, &ref) == B_OK); 4810 BMimeType type; 4811 // NULL BMimeType 4812 CHK(BMimeType::GuessMimeType(filename, NULL) == B_BAD_VALUE); 4813 CHK(BMimeType::GuessMimeType(file.data, file.size, NULL) 4814 == B_BAD_VALUE); 4815 CHK(BMimeType::GuessMimeType(&ref, NULL) == B_BAD_VALUE); 4816 // NULL filename/ref/data 4817 CHK(BMimeType::GuessMimeType((const char*)NULL, &type) == B_BAD_VALUE); 4818 CHK(BMimeType::GuessMimeType(NULL, 10, &type) == B_BAD_VALUE); 4819 CHK(BMimeType::GuessMimeType((const entry_ref*)NULL, &type) 4820 == B_BAD_VALUE); 4821 // NULL BMimeType and filename/ref/data 4822 CHK(BMimeType::GuessMimeType((const char*)NULL, NULL) == B_BAD_VALUE); 4823 CHK(BMimeType::GuessMimeType(NULL, 10, NULL) == B_BAD_VALUE); 4824 CHK(BMimeType::GuessMimeType((const entry_ref*)NULL, NULL) 4825 == B_BAD_VALUE); 4826 CHK(file.Delete() == B_OK); 4827 } 4828} 4829 4830 4831/* KEY: 4832 + == Tests implemented 4833 * == Function implemented 4834*/ 4835 4836/* Ingo's functions: 4837 4838 // initialization 4839+* BMimeType(); 4840+* BMimeType(const char *mimeType); 4841(* virtual ~BMimeType();) 4842 4843+* status_t SetTo(const char *mimeType); 4844+* status_t SetType(const char *mimeType); 4845+* void Unset(); 4846+* status_t InitCheck() const; 4847 4848 // string access 4849+* const char *Type() const; 4850+* bool IsValid() const; 4851+* static bool IsValid(const char *mimeType); 4852+* bool IsSupertypeOnly() const; 4853+* status_t GetSupertype(BMimeType *superType) const; 4854+* bool Contains(const BMimeType *type) const; 4855+* bool operator==(const BMimeType &type) const; 4856+* bool operator==(const char *type) const; 4857 4858 // MIME database monitoring 4859+ static status_t StartWatching(BMessenger target); 4860+ static status_t StopWatching(BMessenger target); 4861 4862 // C functions 4863+ int update_mime_info(const char *path, int recursive, int synchronous, 4864 int force); 4865+ status_t create_app_meta_mime(const char *path, int recursive, 4866 int synchronous, int force); 4867+ status_t get_device_icon(const char *dev, void *icon, int32 size); 4868 4869 // sniffer rule manipulation 4870+ status_t GetSnifferRule(BString *result) const; 4871+ status_t SetSnifferRule(const char *); 4872+ static status_t CheckSnifferRule(const char *rule, BString *parseError); 4873 4874 // sniffing 4875+ status_t GuessMimeType(const entry_ref *file, BMimeType *result); 4876+ static status_t GuessMimeType(const void *buffer, int32 length, 4877 BMimeType *result); 4878+ static status_t GuessMimeType(const char *filename, BMimeType *result); 4879*/ 4880 4881 4882/* Tyler's functions: 4883 4884 // MIME database access 4885+ status_t Install(); 4886+ status_t Delete(); 4887+ bool IsInstalled() const; 4888+ status_t GetIcon(BBitmap *icon, icon_size size) const; 4889+ status_t GetPreferredApp(char *signature, app_verb verb = B_OPEN) const; 4890+ status_t GetAttrInfo(BMessage *info) const; 4891+ status_t GetFileExtensions(BMessage *extensions) const; 4892+ status_t GetShortDescription(char *description) const; 4893+ status_t GetLongDescription(char *description) const; 4894 status_t GetSupportingApps(BMessage *signatures) const; 4895 4896+ status_t SetIcon(const BBitmap *icon, icon_size size); 4897+ status_t SetPreferredApp(const char *signature, app_verb verb = B_OPEN); 4898+ status_t SetAttrInfo(const BMessage *info); 4899+ status_t SetFileExtensions(const BMessage *extensions); 4900+ status_t SetShortDescription(const char *description); 4901+ status_t SetLongDescription(const char *description); 4902 4903+ static status_t GetInstalledSupertypes(BMessage *super_types); 4904+ static status_t GetInstalledTypes(BMessage *types); 4905+ static status_t GetInstalledTypes(const char *super_type, 4906 BMessage *subtypes); 4907+ static status_t GetWildcardApps(BMessage *wild_ones); 4908 4909+ status_t GetAppHint(entry_ref *ref) const; 4910+ status_t SetAppHint(const entry_ref *ref); 4911 4912+ status_t GetIconForType(const char *type, BBitmap *icon, 4913 icon_size which) const; 4914+ status_t SetIconForType(const char *type, const BBitmap *icon, 4915 icon_size which); 4916*/ 4917 4918 4919