1 // ResourcesTest.cpp
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6
7 #include <string>
8 using std::string;
9 #include <vector>
10 using std::vector;
11
12 #include <ByteOrder.h>
13 #include <File.h>
14 #include <Mime.h>
15 #include <Resources.h>
16 #include <String.h>
17 #include <TypeConstants.h>
18 #include <TestShell.h>
19
20 #include "ResourcesTest.h"
21
22 static const char *testDir = "/tmp/testDir";
23 static const char *x86ResFile = "/tmp/testDir/x86.rsrc";
24 static const char *ppcResFile = "/tmp/testDir/ppc.rsrc";
25 static const char *elfFile = "/tmp/testDir/elf";
26 static const char *elfNoResFile = "/tmp/testDir/elf-no-res";
27 static const char *pefFile = "/tmp/testDir/pef";
28 static const char *pefNoResFile = "/tmp/testDir/pef-no-res";
29 static const char *emptyFile = "/tmp/testDir/empty-file";
30 static const char *noResFile = "/tmp/testDir/no-res-file";
31 static const char *testFile1 = "/tmp/testDir/testFile1";
32 static const char *testFile2 = "/tmp/testDir/testFile2";
33 static const char *noSuchFile = "/tmp/testDir/no-such-file";
34 static const char *x86ResName = "x86.rsrc";
35 static const char *ppcResName = "ppc.rsrc";
36 static const char *elfName = "elf";
37 static const char *elfNoResName = "elf-no-res";
38 static const char *pefName = "pef";
39 static const char *pefNoResName = "pef-no-res";
40
41 static const int32 kEmptyResourceFileSize = 1984;
42
43 struct ResourceInfo {
ResourceInfoResourceInfo44 ResourceInfo(type_code type, int32 id, const void *data, size_t size,
45 const char *name = NULL)
46 : type(type),
47 id(id),
48 name(NULL),
49 data(NULL),
50 size(size)
51 {
52 if (data) {
53 this->data = new char[size];
54 memcpy(this->data, data, size);
55 }
56 if (name) {
57 int32 len = strlen(name);
58 this->name = new char[len + 1];
59 strcpy(this->name, name);
60 }
61 }
62
~ResourceInfoResourceInfo63 ~ResourceInfo()
64 {
65 delete[] name;
66 delete[] data;
67 }
68
69 type_code type;
70 int32 id;
71 char *name;
72 char *data;
73 size_t size;
74 };
75
76 static const char *testResData1 = "I like strings, especially cellos.";
77 static const int32 testResSize1 = strlen(testResData1) + 1;
78 static const int32 testResData2 = 42;
79 static const int32 testResSize2 = sizeof(int32);
80 static const char *testResData3 = "application/bread-roll-counter";
81 static const int32 testResSize3 = strlen(testResData3) + 1;
82 static const char *testResData4 = "This is a long string. At least longer "
83 "than the first one";
84 static const int32 testResSize4 = strlen(testResData1) + 1;
85 static const char *testResData6 = "Short, but true.";
86 static const int32 testResSize6 = strlen(testResData6) + 1;
87
88 static const ResourceInfo testResource1(B_STRING_TYPE, 74, testResData1,
89 testResSize1, "a string resource");
90 static const ResourceInfo testResource2(B_INT32_TYPE, 17, &testResData2,
91 testResSize2, "just a resource");
92 static const ResourceInfo testResource3(B_MIME_STRING_TYPE, 29, testResData3,
93 testResSize3, "another resource");
94 static const ResourceInfo testResource4(B_STRING_TYPE, 75, &testResData4,
95 testResSize4,
96 "a second string resource");
97 static const ResourceInfo testResource5(B_MIME_STRING_TYPE, 74, &testResData1,
98 testResSize1, "a string resource");
99 static const ResourceInfo testResource6(B_STRING_TYPE, 74, &testResData6,
100 testResSize6,
101 "a third string resource");
102
103 // helper class: maintains a ResourceInfo set
104 struct ResourceSet {
105 typedef vector<const ResourceInfo*> ResInfoSet;
106
ResourceSetResourceSet107 ResourceSet() : fResources() { }
108
ResourceSetResourceSet109 ResourceSet(const ResourceSet &resourceSet)
110 : fResources()
111 {
112 fResources = resourceSet.fResources;
113 }
114
addResourceSet115 void add(const ResourceInfo *info)
116 {
117 if (info) {
118 remove(info->type, info->id);
119 fResources.insert(fResources.end(), info);
120 }
121 }
122
removeResourceSet123 void remove(const ResourceInfo *info)
124 {
125 if (info)
126 remove(info->type, info->id);
127 }
128
removeResourceSet129 void remove(type_code type, int32 id)
130 {
131 for (ResInfoSet::iterator it = fResources.begin();
132 it != fResources.end();
133 it++) {
134 const ResourceInfo *info = *it;
135 if (info->type == type && info->id == id) {
136 fResources.erase(it);
137 break;
138 }
139 }
140 }
141
sizeResourceSet142 int32 size() const
143 {
144 return fResources.size();
145 }
146
infoAtResourceSet147 const ResourceInfo *infoAt(int32 index) const
148 {
149 const ResourceInfo *info = NULL;
150 if (index >= 0 && index < size())
151 info = fResources[index];
152 return info;
153 }
154
findResourceSet155 const ResourceInfo *find(type_code type, int32 id) const
156 {
157 const ResourceInfo *result = NULL;
158 for (ResInfoSet::const_iterator it = fResources.begin();
159 result == NULL && it != fResources.end();
160 it++) {
161 const ResourceInfo *info = *it;
162 if (info->type == type && info->id == id)
163 result = info;
164 }
165 return result;
166 }
167
168 ResInfoSet fResources;
169 };
170
171
172 // Suite
173 CppUnit::Test*
Suite()174 ResourcesTest::Suite() {
175 CppUnit::TestSuite *suite = new CppUnit::TestSuite();
176 typedef CppUnit::TestCaller<ResourcesTest> TC;
177
178 suite->addTest( new TC("BResources::Init Test",
179 &ResourcesTest::InitTest) );
180 suite->addTest( new TC("BResources::Read Test",
181 &ResourcesTest::ReadTest) );
182 suite->addTest( new TC("BResources::Sync Test",
183 &ResourcesTest::SyncTest) );
184 suite->addTest( new TC("BResources::Merge Test",
185 &ResourcesTest::MergeTest) );
186 suite->addTest( new TC("BResources::WriteTo Test",
187 &ResourcesTest::WriteToTest) );
188 suite->addTest( new TC("BResources::AddRemove Test",
189 &ResourcesTest::AddRemoveTest) );
190 suite->addTest( new TC("BResources::ReadWrite Test",
191 &ResourcesTest::ReadWriteTest) );
192
193 return suite;
194 }
195
196 // setUp
197 void
setUp()198 ResourcesTest::setUp()
199 {
200 BasicTest::setUp();
201 BString unescapedTestDir(BTestShell::GlobalTestDir());
202 unescapedTestDir.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\');
203 string resourcesTestDir(unescapedTestDir.String());
204 resourcesTestDir += "/resources";
205 execCommand(string("mkdir ") + testDir
206 + " ; cp " + resourcesTestDir + "/" + x86ResName + " "
207 + resourcesTestDir + "/" + ppcResName + " "
208 + resourcesTestDir + "/" + elfName + " "
209 + resourcesTestDir + "/" + elfNoResName + " "
210 + resourcesTestDir + "/" + pefName + " "
211 + resourcesTestDir + "/" + pefNoResName + " "
212 + testDir
213 + " ; touch " + emptyFile
214 + " ; echo \"That's not a resource file.\" > " + noResFile
215 );
216 }
217
218 // tearDown
219 void
tearDown()220 ResourcesTest::tearDown()
221 {
222 execCommand(string("rm -rf ") + testDir);
223 BasicTest::tearDown();
224 }
225
226 // InitTest
227 void
InitTest()228 ResourcesTest::InitTest()
229 {
230 // 1. existing files, read only
231 // x86 resource file
232 NextSubTest();
233 {
234 BResources resources;
235 BFile file(x86ResFile, B_READ_ONLY);
236 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
237 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
238 }
239 // ppc resource file
240 NextSubTest();
241 {
242 BResources resources;
243 BFile file(ppcResFile, B_READ_ONLY);
244 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
245 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
246 }
247 // ELF binary containing resources
248 NextSubTest();
249 {
250 BResources resources;
251 BFile file(elfFile, B_READ_ONLY);
252 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
253 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
254 }
255 // ELF binary not containing resources
256 NextSubTest();
257 {
258 BResources resources;
259 BFile file(elfNoResFile, B_READ_ONLY);
260 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
261 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
262 }
263 // PEF binary containing resources
264 NextSubTest();
265 {
266 BResources resources;
267 BFile file(pefFile, B_READ_ONLY);
268 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
269 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
270 }
271 // PEF binary not containing resources
272 NextSubTest();
273 {
274 BResources resources;
275 BFile file(pefNoResFile, B_READ_ONLY);
276 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
277 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
278 }
279 // empty file
280 NextSubTest();
281 {
282 BResources resources;
283 BFile file(emptyFile, B_READ_ONLY);
284 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
285 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
286 }
287 // non-resource file
288 NextSubTest();
289 {
290 BResources resources;
291 BFile file(noResFile, B_READ_ONLY);
292 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
293 CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR,
294 B_IO_ERROR) );
295 }
296
297 // 2. existing files, read only, clobber
298 // x86 resource file
299 NextSubTest();
300 {
301 BResources resources;
302 BFile file(x86ResFile, B_READ_ONLY);
303 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
304 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
305 }
306 // ppc resource file
307 NextSubTest();
308 {
309 BResources resources;
310 BFile file(ppcResFile, B_READ_ONLY);
311 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
312 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
313 }
314 // ELF binary containing resources
315 NextSubTest();
316 {
317 BResources resources;
318 BFile file(elfFile, B_READ_ONLY);
319 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
320 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
321 }
322 // ELF binary not containing resources
323 NextSubTest();
324 {
325 BResources resources;
326 BFile file(elfNoResFile, B_READ_ONLY);
327 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
328 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
329 }
330 // PEF binary containing resources
331 NextSubTest();
332 {
333 BResources resources;
334 BFile file(pefFile, B_READ_ONLY);
335 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
336 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
337 }
338 // PEF binary not containing resources
339 NextSubTest();
340 {
341 BResources resources;
342 BFile file(pefNoResFile, B_READ_ONLY);
343 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
344 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
345 }
346 // empty file
347 NextSubTest();
348 {
349 BResources resources;
350 BFile file(emptyFile, B_READ_ONLY);
351 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
352 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
353 }
354 // non-resource file
355 NextSubTest();
356 {
357 BResources resources;
358 BFile file(noResFile, B_READ_ONLY);
359 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
360 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
361 }
362
363 // 3. existing files, read/write
364 // x86 resource file
365 NextSubTest();
366 {
367 BResources resources;
368 BFile file(x86ResFile, B_READ_WRITE);
369 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
370 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
371 }
372 // ppc resource file
373 NextSubTest();
374 {
375 BResources resources;
376 BFile file(ppcResFile, B_READ_WRITE);
377 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
378 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
379 }
380 // ELF binary containing resources
381 NextSubTest();
382 {
383 BResources resources;
384 BFile file(elfFile, B_READ_WRITE);
385 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
386 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
387 }
388 // ELF binary not containing resources
389 NextSubTest();
390 {
391 BResources resources;
392 BFile file(elfNoResFile, B_READ_WRITE);
393 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
394 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
395 }
396 // PEF binary containing resources
397 NextSubTest();
398 {
399 BResources resources;
400 BFile file(pefFile, B_READ_WRITE);
401 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
402 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
403 }
404 // PEF binary not containing resources
405 NextSubTest();
406 {
407 BResources resources;
408 BFile file(pefNoResFile, B_READ_WRITE);
409 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
410 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
411 }
412 // empty file
413 NextSubTest();
414 {
415 BResources resources;
416 BFile file(emptyFile, B_READ_WRITE);
417 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
418 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
419 }
420 // non-resource file
421 NextSubTest();
422 {
423 BResources resources;
424 BFile file(noResFile, B_READ_WRITE);
425 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
426 CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR,
427 B_IO_ERROR) );
428 }
429
430 // 4. existing files, read/write, clobber
431 // x86 resource file
432 NextSubTest();
433 {
434 BResources resources;
435 BFile file(x86ResFile, B_READ_WRITE);
436 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
437 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
438 CPPUNIT_ASSERT( resources.Sync() == B_OK );
439 }
440 // ppc resource file
441 NextSubTest();
442 {
443 BResources resources;
444 BFile file(ppcResFile, B_READ_WRITE);
445 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
446 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
447 CPPUNIT_ASSERT( resources.Sync() == B_OK );
448 }
449 // ELF binary containing resources
450 NextSubTest();
451 {
452 BResources resources;
453 BFile file(elfFile, B_READ_WRITE);
454 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
455 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
456 CPPUNIT_ASSERT( resources.Sync() == B_OK );
457 }
458 // ELF binary not containing resources
459 NextSubTest();
460 {
461 BResources resources;
462 BFile file(elfNoResFile, B_READ_WRITE);
463 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
464 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
465 CPPUNIT_ASSERT( resources.Sync() == B_OK );
466 }
467 // PEF binary containing resources
468 NextSubTest();
469 {
470 BResources resources;
471 BFile file(pefFile, B_READ_WRITE);
472 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
473 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
474 CPPUNIT_ASSERT( resources.Sync() == B_OK );
475 }
476 // PEF binary not containing resources
477 NextSubTest();
478 {
479 BResources resources;
480 BFile file(pefNoResFile, B_READ_WRITE);
481 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
482 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
483 CPPUNIT_ASSERT( resources.Sync() == B_OK );
484 }
485 // empty file
486 NextSubTest();
487 {
488 BResources resources;
489 BFile file(emptyFile, B_READ_WRITE);
490 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
491 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
492 CPPUNIT_ASSERT( resources.Sync() == B_OK );
493 }
494 // non-resource file
495 NextSubTest();
496 {
497 BResources resources;
498 BFile file(noResFile, B_READ_WRITE);
499 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
500 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
501 }
502
503 // 5. bad args
504 // uninitialized file
505 NextSubTest();
506 {
507 BResources resources;
508 BFile file;
509 CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT );
510 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_NO_INIT );
511 }
512 // badly initialized file
513 NextSubTest();
514 {
515 BResources resources;
516 BFile file(noSuchFile, B_READ_ONLY);
517 CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND );
518 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND );
519 }
520 // NULL file
521 NextSubTest();
522 {
523 BResources resources;
524 // R5: A NULL file is B_OK!
525 // CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_BAD_VALUE );
526 CPPUNIT_ASSERT( resources.SetTo((BFile*)NULL, false) == B_OK );
527 }
528 }
529
530 // ReadResTest
531 static
532 void
ReadResTest(BResources & resources,const ResourceInfo & info,bool exists)533 ReadResTest(BResources& resources, const ResourceInfo& info, bool exists)
534 {
535 if (exists) {
536 // test an existing resource
537 // HasResource()
538 CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == true );
539 CPPUNIT_ASSERT( resources.HasResource(info.type, info.name)
540 == true );
541 // GetResourceInfo()
542 const char *name;
543 size_t length;
544 int32 id;
545 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id,
546 &name, &length) == true );
547 CPPUNIT_ASSERT( name == NULL && info.name == NULL
548 || name != NULL && info.name != NULL
549 && !strcmp(name, info.name) );
550 CPPUNIT_ASSERT( length == info.size );
551 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name,
552 &id, &length) == true );
553 CPPUNIT_ASSERT( id == info.id );
554 CPPUNIT_ASSERT( length == info.size );
555 // LoadResource
556 size_t length1;
557 size_t length2;
558 const void *data1
559 = resources.LoadResource(info.type, info.id, &length1);
560 const void *data2
561 = resources.LoadResource(info.type, info.name, &length2);
562 CPPUNIT_ASSERT( length1 == info.size && length2 == info.size );
563 CPPUNIT_ASSERT( data1 != NULL && data1 == data2 );
564 CPPUNIT_ASSERT( !memcmp(data1, info.data, info.size) );
565 // GetResourceInfo()
566 type_code type = 0;
567 id = 0;
568 length = 0;
569 name = NULL;
570 CPPUNIT_ASSERT( resources.GetResourceInfo(data1, &type, &id, &length,
571 &name) == true );
572 CPPUNIT_ASSERT( type == info.type );
573 CPPUNIT_ASSERT( id == info.id );
574 CPPUNIT_ASSERT( length == info.size );
575 CPPUNIT_ASSERT( name == NULL && info.name == NULL
576 || name != NULL && info.name != NULL
577 && !strcmp(name, info.name) );
578 // ReadResource()
579 const int32 bufferSize = 1024;
580 char buffer[bufferSize];
581 memset(buffer, 0x0f, bufferSize);
582 // read past the end
583 status_t error = resources.ReadResource(info.type, info.id, buffer,
584 info.size + 2, bufferSize);
585 CPPUNIT_ASSERT( error == B_OK );
586 for (int32 i = 0; i < bufferSize; i++)
587 CPPUNIT_ASSERT( buffer[i] == 0x0f );
588 // read 2 bytes from the middle
589 int32 offset = (info.size - 2) / 2;
590 error = resources.ReadResource(info.type, info.id, buffer, offset, 2);
591 CPPUNIT_ASSERT( error == B_OK );
592 CPPUNIT_ASSERT( !memcmp(buffer, (const char*)info.data + offset, 2) );
593 for (int32 i = 2; i < bufferSize; i++)
594 CPPUNIT_ASSERT( buffer[i] == 0x0f );
595 // read the whole chunk
596 error = resources.ReadResource(info.type, info.id, buffer, 0,
597 bufferSize);
598 CPPUNIT_ASSERT( error == B_OK );
599 CPPUNIT_ASSERT( !memcmp(buffer, info.data, info.size) );
600 // FindResource()
601 size_t lengthFound1;
602 size_t lengthFound2;
603 void *dataFound1
604 = resources.FindResource(info.type, info.id, &lengthFound1);
605 void *dataFound2
606 = resources.FindResource(info.type, info.name, &lengthFound2);
607 CPPUNIT_ASSERT( dataFound1 != NULL && dataFound2 != NULL );
608 CPPUNIT_ASSERT( lengthFound1 == info.size
609 && lengthFound2 == info.size );
610 CPPUNIT_ASSERT( !memcmp(dataFound1, info.data, info.size) );
611 CPPUNIT_ASSERT( !memcmp(dataFound2, info.data, info.size) );
612 free(dataFound1);
613 free(dataFound2);
614 } else {
615 // test a non-existing resource
616 // HasResource()
617 CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == false );
618 CPPUNIT_ASSERT( resources.HasResource(info.type, info.name)
619 == false );
620 // GetResourceInfo()
621 const char *name;
622 size_t length;
623 int32 id;
624 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id,
625 &name, &length) == false );
626 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name,
627 &id, &length) == false );
628 // LoadResource
629 size_t length1;
630 size_t length2;
631 const void *data1
632 = resources.LoadResource(info.type, info.id, &length1);
633 const void *data2
634 = resources.LoadResource(info.type, info.name, &length2);
635 CPPUNIT_ASSERT( data1 == NULL && data2 == NULL );
636 // ReadResource()
637 const int32 bufferSize = 1024;
638 char buffer[bufferSize];
639 status_t error = resources.ReadResource(info.type, info.id, buffer,
640 0, bufferSize);
641 CPPUNIT_ASSERT( error == B_BAD_VALUE );
642 // FindResource()
643 size_t lengthFound1;
644 size_t lengthFound2;
645 void *dataFound1
646 = resources.FindResource(info.type, info.id, &lengthFound1);
647 void *dataFound2
648 = resources.FindResource(info.type, info.name, &lengthFound2);
649 CPPUNIT_ASSERT( dataFound1 == NULL && dataFound2 == NULL );
650 }
651 }
652
653 // ReadBadResTest
654 static
655 void
ReadBadResTest(BResources & resources,const ResourceInfo & info)656 ReadBadResTest(BResources& resources, const ResourceInfo& info)
657 {
658 // HasResource()
659 CPPUNIT_ASSERT( resources.HasResource(info.type, info.id) == false );
660 CPPUNIT_ASSERT( resources.HasResource(info.type, info.name)
661 == false );
662 // GetResourceInfo()
663 type_code type;
664 const char *name;
665 size_t length;
666 int32 id;
667 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id,
668 &name, &length) == false );
669 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name,
670 &id, &length) == false );
671 CPPUNIT_ASSERT( resources.GetResourceInfo(0, &type, &id,
672 &name, &length) == false );
673 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, 0, &id,
674 &name, &length) == false );
675 // LoadResource
676 size_t length1;
677 size_t length2;
678 const void *data1
679 = resources.LoadResource(info.type, info.id, &length1);
680 const void *data2
681 = resources.LoadResource(info.type, info.name, &length2);
682 CPPUNIT_ASSERT( data1 == NULL && data2 == NULL );
683 // ReadResource()
684 const int32 bufferSize = 1024;
685 char buffer[bufferSize];
686 status_t error = resources.ReadResource(info.type, info.id, buffer,
687 0, bufferSize);
688 CPPUNIT_ASSERT( error == B_BAD_VALUE );
689 // FindResource()
690 size_t lengthFound1;
691 size_t lengthFound2;
692 void *dataFound1
693 = resources.FindResource(info.type, info.id, &lengthFound1);
694 void *dataFound2
695 = resources.FindResource(info.type, info.name, &lengthFound2);
696 CPPUNIT_ASSERT( dataFound1 == NULL && dataFound2 == NULL );
697 }
698
699 // ReadTest
700 void
ReadTest()701 ResourcesTest::ReadTest()
702 {
703 // tests:
704 // * HasResource()
705 // * GetResourceInfo()
706 // * LoadResource()
707 // * ReadResource()
708 // * FindResource()
709 // * PreloadResource()
710
711 // 1. basic tests
712 // x86 resource file
713 NextSubTest();
714 {
715 BFile file(x86ResFile, B_READ_ONLY);
716 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
717 BResources resources;
718 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
719 ReadResTest(resources, testResource1, true);
720 ReadResTest(resources, testResource2, true);
721 ReadResTest(resources, testResource3, true);
722 ReadResTest(resources, testResource4, false);
723 ReadResTest(resources, testResource5, false);
724 }
725 // ppc resource file
726 NextSubTest();
727 {
728 BFile file(ppcResFile, B_READ_ONLY);
729 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
730 BResources resources;
731 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
732 ReadResTest(resources, testResource1, true);
733 ReadResTest(resources, testResource2, true);
734 ReadResTest(resources, testResource3, true);
735 ReadResTest(resources, testResource4, false);
736 ReadResTest(resources, testResource5, false);
737 }
738 // ELF binary containing resources
739 NextSubTest();
740 {
741 BFile file(elfFile, B_READ_ONLY);
742 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
743 BResources resources;
744 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
745 ReadResTest(resources, testResource1, true);
746 ReadResTest(resources, testResource2, true);
747 ReadResTest(resources, testResource3, true);
748 ReadResTest(resources, testResource4, false);
749 ReadResTest(resources, testResource5, false);
750 }
751 // ELF binary not containing resources
752 NextSubTest();
753 {
754 BFile file(elfNoResFile, B_READ_ONLY);
755 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
756 BResources resources;
757 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
758 ReadResTest(resources, testResource1, false);
759 ReadResTest(resources, testResource2, false);
760 ReadResTest(resources, testResource3, false);
761 ReadResTest(resources, testResource4, false);
762 ReadResTest(resources, testResource5, false);
763 }
764 // PEF binary containing resources
765 NextSubTest();
766 {
767 BFile file(pefFile, B_READ_ONLY);
768 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
769 BResources resources;
770 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
771 ReadResTest(resources, testResource1, true);
772 ReadResTest(resources, testResource2, true);
773 ReadResTest(resources, testResource3, true);
774 ReadResTest(resources, testResource4, false);
775 ReadResTest(resources, testResource5, false);
776 }
777 // PEF binary not containing resources
778 NextSubTest();
779 {
780 BFile file(pefNoResFile, B_READ_ONLY);
781 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
782 BResources resources;
783 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
784 ReadResTest(resources, testResource1, false);
785 ReadResTest(resources, testResource2, false);
786 ReadResTest(resources, testResource3, false);
787 ReadResTest(resources, testResource4, false);
788 ReadResTest(resources, testResource5, false);
789 }
790
791 // 2. PreloadResource()
792 // Hard to test: just preload all and check, if it still works.
793 NextSubTest();
794 {
795 BFile file(x86ResFile, B_READ_ONLY);
796 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
797 BResources resources;
798 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
799 // non existing type
800 CPPUNIT_ASSERT( resources.PreloadResourceType(B_MESSENGER_TYPE)
801 == B_OK );
802 // int32 type
803 CPPUNIT_ASSERT( resources.PreloadResourceType(B_INT32_TYPE) == B_OK );
804 // all types
805 CPPUNIT_ASSERT( resources.PreloadResourceType() == B_OK );
806 ReadResTest(resources, testResource1, true);
807 ReadResTest(resources, testResource2, true);
808 ReadResTest(resources, testResource3, true);
809 ReadResTest(resources, testResource4, false);
810 ReadResTest(resources, testResource5, false);
811 }
812 // uninitialized BResources
813 NextSubTest();
814 {
815 BResources resources;
816 // int32 type
817 CPPUNIT_ASSERT( resources.PreloadResourceType(B_INT32_TYPE) == B_OK );
818 // all types
819 CPPUNIT_ASSERT( resources.PreloadResourceType() == B_OK );
820 }
821
822 // 3. the index versions of GetResourceInfo()
823 // index only
824 NextSubTest();
825 {
826 BFile file(x86ResFile, B_READ_ONLY);
827 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
828 BResources resources;
829 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
830 const ResourceInfo *resourceInfos[] = {
831 &testResource1, &testResource2, &testResource3
832 };
833 int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*);
834 for (int32 i = 0; i < resourceCount; i++) {
835 const ResourceInfo &info = *resourceInfos[i];
836 type_code type;
837 int32 id;
838 const char *name;
839 size_t length;
840 CPPUNIT_ASSERT( resources.GetResourceInfo(i, &type, &id, &name,
841 &length) == true );
842 CPPUNIT_ASSERT( id == info.id );
843 CPPUNIT_ASSERT( type == info.type );
844 CPPUNIT_ASSERT( name == NULL && info.name == NULL
845 || name != NULL && info.name != NULL
846 && !strcmp(name, info.name) );
847 CPPUNIT_ASSERT( length == info.size );
848 }
849 type_code type;
850 int32 id;
851 const char *name;
852 size_t length;
853 CPPUNIT_ASSERT( resources.GetResourceInfo(resourceCount, &type, &id,
854 &name, &length) == false );
855 }
856 // type and index
857 NextSubTest();
858 {
859 BFile file(x86ResFile, B_READ_WRITE);
860 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
861 BResources resources;
862 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
863 CPPUNIT_ASSERT( resources.AddResource(testResource4.type,
864 testResource4.id,
865 testResource4.data,
866 testResource4.size,
867 testResource4.name) == B_OK );
868
869 const ResourceInfo *resourceInfos[] = {
870 &testResource1, &testResource4
871 };
872 int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*);
873 type_code type = resourceInfos[0]->type;
874 for (int32 i = 0; i < resourceCount; i++) {
875 const ResourceInfo &info = *resourceInfos[i];
876 int32 id;
877 const char *name;
878 size_t length;
879 CPPUNIT_ASSERT( resources.GetResourceInfo(type, i, &id, &name,
880 &length) == true );
881 CPPUNIT_ASSERT( id == info.id );
882 CPPUNIT_ASSERT( type == info.type );
883 CPPUNIT_ASSERT( name == NULL && info.name == NULL
884 || name != NULL && info.name != NULL
885 && !strcmp(name, info.name) );
886 CPPUNIT_ASSERT( length == info.size );
887 }
888 int32 id;
889 const char *name;
890 size_t length;
891 CPPUNIT_ASSERT( resources.GetResourceInfo(type, resourceCount, &id,
892 &name, &length) == false );
893 }
894
895 // 4. error cases
896 // non-resource file
897 NextSubTest();
898 {
899 BResources resources;
900 BFile file(noResFile, B_READ_ONLY);
901 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
902 CPPUNIT_ASSERT( equals(resources.SetTo(&file, false), B_ERROR,
903 B_IO_ERROR) );
904 ReadBadResTest(resources, testResource1);
905 }
906 // uninitialized file
907 NextSubTest();
908 {
909 BResources resources;
910 BFile file;
911 CPPUNIT_ASSERT( file.InitCheck() == B_NO_INIT );
912 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_NO_INIT );
913 ReadBadResTest(resources, testResource1);
914 }
915 // badly initialized file
916 NextSubTest();
917 {
918 BResources resources;
919 BFile file(noSuchFile, B_READ_ONLY);
920 CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND );
921 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND );
922 ReadBadResTest(resources, testResource1);
923 }
924 // NULL file
925 NextSubTest();
926 {
927 BResources resources;
928 // R5: A NULL file is B_OK!
929 // CPPUNIT_ASSERT( resources.SetTo(NULL, false) == B_BAD_VALUE );
930 CPPUNIT_ASSERT( resources.SetTo((BFile*)NULL, false) == B_OK );
931 ReadBadResTest(resources, testResource1);
932 }
933 // bad args
934 NextSubTest();
935 {
936 BFile file(x86ResFile, B_READ_ONLY);
937 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
938 BResources resources;
939 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
940 const ResourceInfo &info = testResource1;
941 // GetResourceInfo()
942 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id,
943 NULL, NULL) == true );
944 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.name,
945 NULL, NULL) == true );
946 CPPUNIT_ASSERT( resources.GetResourceInfo(int32(0), (type_code*)NULL,
947 NULL, NULL, NULL) == true );
948 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, 0, NULL,
949 NULL, NULL) == true );
950 // LoadResource
951 const void *data1
952 = resources.LoadResource(info.type, info.id, NULL);
953 const void *data2
954 = resources.LoadResource(info.type, info.name, NULL);
955 CPPUNIT_ASSERT( data1 != NULL && data2 != NULL );
956 // ReadResource()
957 const int32 bufferSize = 1024;
958 status_t error = resources.ReadResource(info.type, info.id, NULL,
959 0, bufferSize);
960 CPPUNIT_ASSERT( error == B_BAD_VALUE );
961 // FindResource()
962 void *dataFound1
963 = resources.FindResource(info.type, info.id, NULL);
964 void *dataFound2
965 = resources.FindResource(info.type, info.name, NULL);
966 CPPUNIT_ASSERT( dataFound1 != NULL && dataFound2 != NULL );
967 free(dataFound1);
968 free(dataFound2);
969 }
970 }
971
972 // AddResources
973 static
974 void
AddResources(BResources & resources,const ResourceInfo * resourceInfos[],int32 count)975 AddResources(BResources &resources, const ResourceInfo *resourceInfos[],
976 int32 count)
977 {
978 for (int32 i = 0; i < count; i++) {
979 const ResourceInfo &info = *resourceInfos[i];
980 CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data,
981 info.size, info.name) == B_OK );
982 }
983 }
984
985 // CompareFiles
986 static
987 void
CompareFiles(BFile & file1,BFile & file2)988 CompareFiles(BFile &file1, BFile &file2)
989 {
990 off_t size1 = 0;
991 off_t size2 = 0;
992 CPPUNIT_ASSERT( file1.GetSize(&size1) == B_OK );
993 CPPUNIT_ASSERT( file2.GetSize(&size2) == B_OK );
994 CPPUNIT_ASSERT( size1 == size2 );
995 char *buffer1 = new char[size1];
996 char *buffer2 = new char[size2];
997 CPPUNIT_ASSERT( file1.ReadAt(0, buffer1, size1) == size1 );
998 CPPUNIT_ASSERT( file2.ReadAt(0, buffer2, size2) == size2 );
999 for (int32 i = 0; i < size1; i++)
1000 CPPUNIT_ASSERT( buffer1[i] == buffer2[i] );
1001 delete[] buffer1;
1002 delete[] buffer2;
1003 }
1004
1005 // CompareResources
1006 static
1007 void
CompareResources(BResources & resources,const ResourceSet & resourceSet)1008 CompareResources(BResources &resources, const ResourceSet &resourceSet)
1009 {
1010 // compare the count
1011 int32 count = resourceSet.size();
1012 {
1013 type_code type;
1014 int32 id;
1015 const char *name;
1016 size_t length;
1017 CPPUNIT_ASSERT( resources.GetResourceInfo(count, &type, &id,
1018 &name, &length) == false );
1019 }
1020 // => resources contains at most count resources. If it contains all the
1021 // resources that are in resourceSet, then the sets are equal.
1022 for (int32 i = 0; i < count; i++) {
1023 const ResourceInfo &info = *resourceSet.infoAt(i);
1024 const char *name;
1025 size_t length;
1026 CPPUNIT_ASSERT( resources.GetResourceInfo(info.type, info.id, &name,
1027 &length) == true );
1028 CPPUNIT_ASSERT( name == NULL && info.name == NULL
1029 || name != NULL && info.name != NULL
1030 && !strcmp(name, info.name) );
1031 CPPUNIT_ASSERT( length == info.size );
1032 const void *data = resources.LoadResource(info.type, info.id, &length);
1033 CPPUNIT_ASSERT( data != NULL && length == info.size );
1034 CPPUNIT_ASSERT( !memcmp(data, info.data, info.size) );
1035 }
1036 }
1037
1038 // AddResource
1039 static
1040 void
AddResource(BResources & resources,ResourceSet & resourceSet,const ResourceInfo & info)1041 AddResource(BResources &resources, ResourceSet &resourceSet,
1042 const ResourceInfo &info)
1043 {
1044 resourceSet.add(&info);
1045 CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data,
1046 info.size, info.name) == B_OK );
1047 CompareResources(resources, resourceSet);
1048 }
1049
1050 // RemoveResource
1051 static
1052 void
RemoveResource(BResources & resources,ResourceSet & resourceSet,const ResourceInfo & info,bool firstVersion)1053 RemoveResource(BResources &resources, ResourceSet &resourceSet,
1054 const ResourceInfo &info, bool firstVersion)
1055 {
1056 resourceSet.remove(&info);
1057 if (firstVersion) {
1058 CPPUNIT_ASSERT( resources.RemoveResource(info.type, info.id) == B_OK );
1059 } else {
1060 size_t size;
1061 const void *data = resources.LoadResource(info.type, info.id, &size);
1062 CPPUNIT_ASSERT( data != NULL );
1063 CPPUNIT_ASSERT( resources.RemoveResource(data) == B_OK );
1064 }
1065 CompareResources(resources, resourceSet);
1066 }
1067
1068 // ListResources
1069 /*static
1070 void
1071 ListResources(BResources &resources)
1072 {
1073 printf("Resources:\n");
1074 type_code type;
1075 int32 id;
1076 const char *name;
1077 size_t size;
1078 for (int32 i = 0;
1079 resources.GetResourceInfo(i, &type, &id, &name, &size);
1080 i++) {
1081 type_code bigType = htonl(type);
1082 printf("resource %2ld: type: `%.4s', id: %3ld, size: %5lu\n", i,
1083 (char*)&bigType, id, size);
1084 }
1085 }*/
1086
1087 // SyncTest
1088 void
SyncTest()1089 ResourcesTest::SyncTest()
1090 {
1091 // Sync() is not easy to test. We just check its return value for now.
1092 NextSubTest();
1093 execCommand(string("cp ") + x86ResFile + " " + testFile1);
1094 {
1095 BFile file(testFile1, B_READ_WRITE);
1096 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1097 BResources resources;
1098 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1099 // add a resource and Sync()
1100 CPPUNIT_ASSERT( resources.AddResource(testResource4.type,
1101 testResource4.id,
1102 testResource4.data,
1103 testResource4.size,
1104 testResource4.name) == B_OK );
1105 CPPUNIT_ASSERT( resources.Sync() == B_OK );
1106 // remove a resource and Sync()
1107 CPPUNIT_ASSERT( resources.RemoveResource(testResource1.type,
1108 testResource1.id) == B_OK );
1109 CPPUNIT_ASSERT( resources.Sync() == B_OK );
1110 }
1111 // error cases
1112 // read only file
1113 NextSubTest();
1114 {
1115 BFile file(testFile1, B_READ_ONLY);
1116 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1117 BResources resources;
1118 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1119 CPPUNIT_ASSERT( resources.Sync() == B_NOT_ALLOWED );
1120 }
1121 // uninitialized BResources
1122 NextSubTest();
1123 {
1124 BResources resources;
1125 CPPUNIT_ASSERT( resources.Sync() == B_NO_INIT );
1126 }
1127 // badly initialized BResources
1128 NextSubTest();
1129 {
1130 BFile file(noSuchFile, B_READ_ONLY);
1131 CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND );
1132 BResources resources;
1133 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_ENTRY_NOT_FOUND );
1134 CPPUNIT_ASSERT( resources.Sync() == B_NO_INIT );
1135 }
1136 }
1137
1138 // MergeTest
1139 void
MergeTest()1140 ResourcesTest::MergeTest()
1141 {
1142 // empty file, merge with resources from another file
1143 NextSubTest();
1144 {
1145 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1146 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1147 BResources resources;
1148 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1149 BFile file2(x86ResFile, B_READ_ONLY);
1150 CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK );
1151 ResourceSet resourceSet;
1152 resourceSet.add(&testResource1);
1153 resourceSet.add(&testResource2);
1154 resourceSet.add(&testResource3);
1155 CompareResources(resources, resourceSet);
1156 }
1157 // empty file, add some resources first and then merge with resources
1158 // from another file
1159 NextSubTest();
1160 {
1161 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1162 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1163 BResources resources;
1164 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1165 // add some resources
1166 ResourceSet resourceSet;
1167 AddResource(resources, resourceSet, testResource4);
1168 AddResource(resources, resourceSet, testResource5);
1169 AddResource(resources, resourceSet, testResource6);
1170 // merge
1171 BFile file2(x86ResFile, B_READ_ONLY);
1172 CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK );
1173 resourceSet.add(&testResource1); // replaces testResource6
1174 resourceSet.add(&testResource2);
1175 resourceSet.add(&testResource3);
1176 CompareResources(resources, resourceSet);
1177 }
1178 // error cases
1179 // bad args
1180 NextSubTest();
1181 {
1182 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1183 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1184 BResources resources;
1185 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1186 BFile file2(noResFile, B_READ_ONLY);
1187 // non-resource file
1188 CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_IO_ERROR );
1189 // NULL file
1190 // R5: crashs
1191 #if !TEST_R5
1192 CPPUNIT_ASSERT( resources.MergeFrom(NULL) == B_BAD_VALUE );
1193 #endif
1194 }
1195 // uninitialized BResources
1196 // R5: returns B_OK!
1197 NextSubTest();
1198 {
1199 BResources resources;
1200 BFile file2(x86ResFile, B_READ_ONLY);
1201 CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK );
1202 }
1203 // badly initialized BResources
1204 // R5: returns B_OK!
1205 NextSubTest();
1206 {
1207 BFile file(noSuchFile, B_READ_ONLY);
1208 CPPUNIT_ASSERT( file.InitCheck() == B_ENTRY_NOT_FOUND );
1209 BResources resources;
1210 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_ENTRY_NOT_FOUND );
1211 BFile file2(x86ResFile, B_READ_ONLY);
1212 CPPUNIT_ASSERT( resources.MergeFrom(&file2) == B_OK );
1213 }
1214 }
1215
1216 // WriteToTest
1217 void
WriteToTest()1218 ResourcesTest::WriteToTest()
1219 {
1220 // take a file with resources and write them to an empty file
1221 NextSubTest();
1222 {
1223 BFile file(x86ResFile, B_READ_ONLY);
1224 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1225 BResources resources;
1226 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1227 BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1228 CPPUNIT_ASSERT( file2.InitCheck() == B_OK );
1229 CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK);
1230 CPPUNIT_ASSERT( resources.File() == file2 );
1231 }
1232 // take a file with resources and write them to an non-empty non-resource
1233 // file
1234 NextSubTest();
1235 {
1236 BFile file(x86ResFile, B_READ_ONLY);
1237 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1238 BResources resources;
1239 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1240 BFile file2(noResFile, B_READ_WRITE);
1241 CPPUNIT_ASSERT( file2.InitCheck() == B_OK );
1242 CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_IO_ERROR);
1243 CPPUNIT_ASSERT( resources.File() == file2 );
1244 }
1245 // take a file with resources and write them to an ELF file
1246 NextSubTest();
1247 execCommand(string("cp ") + elfNoResFile + " " + testFile1);
1248 {
1249 BFile file(x86ResFile, B_READ_ONLY);
1250 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1251 BResources resources;
1252 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1253 BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1254 CPPUNIT_ASSERT( file2.InitCheck() == B_OK );
1255 CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK);
1256 CPPUNIT_ASSERT( resources.File() == file2 );
1257 }
1258 // empty file, add a resource, write it to another file
1259 NextSubTest();
1260 {
1261 BFile file(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1262 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1263 BResources resources;
1264 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1265 // add a resource
1266 ResourceSet resourceSet;
1267 AddResource(resources, resourceSet, testResource1);
1268 // write to another file
1269 BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1270 CPPUNIT_ASSERT( file2.InitCheck() == B_OK );
1271 CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK);
1272 CPPUNIT_ASSERT( resources.File() == file2 );
1273 // check, whether the first file has been modified -- it shouldn't be
1274 off_t fileSize = 0;
1275 CPPUNIT_ASSERT( file.GetSize(&fileSize) == B_OK );
1276 CPPUNIT_ASSERT( fileSize == 0 );
1277 }
1278 // uninitialized BResources
1279 NextSubTest();
1280 execCommand(string("cp ") + elfNoResFile + " " + testFile1);
1281 {
1282 BResources resources;
1283 BFile file2(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1284 CPPUNIT_ASSERT( file2.InitCheck() == B_OK );
1285 CPPUNIT_ASSERT( resources.WriteTo(&file2) == B_OK);
1286 CPPUNIT_ASSERT( resources.File() == file2 );
1287 }
1288 // bad args: NULL file
1289 // R5: crashs
1290 NextSubTest();
1291 {
1292 BFile file(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1293 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1294 BResources resources;
1295 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1296 #if !TEST_R5
1297 CPPUNIT_ASSERT( resources.WriteTo(NULL) == B_BAD_VALUE);
1298 #endif
1299 }
1300 }
1301
1302 // AddRemoveTest
1303 void
AddRemoveTest()1304 ResourcesTest::AddRemoveTest()
1305 {
1306 // tests:
1307 // * AddResource()
1308 // * RemoveResource()
1309 // * WriteResource()
1310
1311 // Start with an empty file, add all the resources of our x86 resource
1312 // file and compare the two bytewise.
1313 // This does of course only work on x86 machines.
1314 NextSubTest();
1315 {
1316 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1317 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1318 BResources resources;
1319 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1320 const ResourceInfo *resourceInfos[] = {
1321 &testResource1, &testResource2, &testResource3
1322 };
1323 int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*);
1324 AddResources(resources, resourceInfos, resourceCount);
1325 }
1326 {
1327 BFile file1(testFile1, B_READ_ONLY);
1328 BFile file2(x86ResFile, B_READ_ONLY);
1329 CompareFiles(file1, file2);
1330 }
1331 // Now remove all resources and compare the file with an empty resource
1332 // file.
1333 NextSubTest();
1334 {
1335 BFile file(testFile1, B_READ_WRITE);
1336 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1337 BResources resources;
1338 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1339 const ResourceInfo *resourceInfos[] = {
1340 &testResource1, &testResource2, &testResource3
1341 };
1342 int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*);
1343 for (int32 i = 0; i < resourceCount; i++) {
1344 const ResourceInfo &info = *resourceInfos[i];
1345 CPPUNIT_ASSERT( resources.RemoveResource(info.type, info.id)
1346 == B_OK );
1347 }
1348 BFile file2(testFile2, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1349 BResources resources2;
1350 CPPUNIT_ASSERT( resources2.SetTo(&file2, true) == B_OK );
1351 }
1352 {
1353 BFile file1(testFile1, B_READ_ONLY);
1354 BFile file2(testFile2, B_READ_ONLY);
1355 CompareFiles(file1, file2);
1356 }
1357 // Same file, use the other remove version.
1358 NextSubTest();
1359 execCommand(string("cp ") + x86ResFile + " " + testFile1);
1360 {
1361 BFile file(testFile1, B_READ_WRITE);
1362 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1363 BResources resources;
1364 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1365 const ResourceInfo *resourceInfos[] = {
1366 &testResource1, &testResource2, &testResource3
1367 };
1368 int32 resourceCount = sizeof(resourceInfos) / sizeof(ResourceInfo*);
1369 for (int32 i = 0; i < resourceCount; i++) {
1370 const ResourceInfo &info = *resourceInfos[i];
1371 size_t size;
1372 const void *data = resources.LoadResource(info.type, info.id,
1373 &size);
1374 CPPUNIT_ASSERT( data != NULL );
1375 CPPUNIT_ASSERT( resources.RemoveResource(data) == B_OK );
1376 }
1377 }
1378 {
1379 BFile file1(testFile1, B_READ_ONLY);
1380 BFile file2(testFile2, B_READ_ONLY);
1381 CompareFiles(file1, file2);
1382 }
1383 // some arbitrary adding and removing...
1384 NextSubTest();
1385 {
1386 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1387 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1388 BResources resources;
1389 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1390 ResourceSet resourceSet;
1391 AddResource(resources, resourceSet, testResource1);
1392 AddResource(resources, resourceSet, testResource2);
1393 RemoveResource(resources, resourceSet, testResource1, true);
1394 AddResource(resources, resourceSet, testResource3);
1395 AddResource(resources, resourceSet, testResource4);
1396 RemoveResource(resources, resourceSet, testResource3, false);
1397 AddResource(resources, resourceSet, testResource5);
1398 AddResource(resources, resourceSet, testResource1);
1399 AddResource(resources, resourceSet, testResource6); // replaces 1
1400 RemoveResource(resources, resourceSet, testResource2, true);
1401 RemoveResource(resources, resourceSet, testResource5, false);
1402 RemoveResource(resources, resourceSet, testResource6, true);
1403 RemoveResource(resources, resourceSet, testResource4, false);
1404 }
1405 // bad args
1406 NextSubTest();
1407 {
1408 BFile file(testFile1, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1409 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1410 BResources resources;
1411 CPPUNIT_ASSERT( resources.SetTo(&file, true) == B_OK );
1412 CPPUNIT_ASSERT( resources.RemoveResource(NULL) == B_BAD_VALUE );
1413 CPPUNIT_ASSERT( resources.RemoveResource(B_INT32_TYPE, 0)
1414 == B_BAD_VALUE );
1415 CPPUNIT_ASSERT( resources.AddResource(B_INT32_TYPE, 0, NULL, 7,
1416 "Hey!") == B_BAD_VALUE );
1417 }
1418 // uninitialized BResources
1419 NextSubTest();
1420 {
1421 BResources resources;
1422 const ResourceInfo &info = testResource1;
1423 CPPUNIT_ASSERT( resources.AddResource(info.type, info.id, info.data,
1424 info.size, info.name)
1425 == B_OK );
1426 }
1427 }
1428
1429 // ReadWriteTest
1430 void
ReadWriteTest()1431 ResourcesTest::ReadWriteTest()
1432 {
1433 // ReadResource() has already been tested in ReadTest(). Thus we focus on
1434 // WriteResource().
1435 // Open a file and write a little bit into one of its resources.
1436 NextSubTest();
1437 execCommand(string("cp ") + x86ResFile + " " + testFile1);
1438 {
1439 BFile file(testFile1, B_READ_WRITE);
1440 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1441 BResources resources;
1442 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1443 const ResourceInfo &info = testResource1;
1444 type_code type = info.type;
1445 int32 id = info.id;
1446 // write at the beginning of the resource
1447 char writeBuffer[1024];
1448 for (int32 i = 0; i < 1024; i++)
1449 writeBuffer[i] = i & 0xff;
1450 char readBuffer[1024];
1451 memset(readBuffer, 0, 1024);
1452 CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, 0, 10)
1453 == B_OK );
1454 size_t length;
1455 const void *data = resources.LoadResource(type, id, &length);
1456 CPPUNIT_ASSERT( data != NULL && length == info.size );
1457 CPPUNIT_ASSERT( !memcmp(data, writeBuffer, 10) );
1458 CPPUNIT_ASSERT( !memcmp((const char*)data + 10, info.data + 10,
1459 info.size - 10) );
1460 // completely overwrite the resource with the former data
1461 CPPUNIT_ASSERT( resources.WriteResource(type, id, info.data, 0,
1462 info.size) == B_OK );
1463 data = resources.LoadResource(type, id, &length);
1464 CPPUNIT_ASSERT( data != NULL && length == info.size );
1465 CPPUNIT_ASSERT( !memcmp(data, info.data, info.size) );
1466 // write something in the middle
1467 size_t offset = (info.size - 2) / 2;
1468 CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, offset,
1469 2) == B_OK );
1470 data = resources.LoadResource(type, id, &length);
1471 CPPUNIT_ASSERT( data != NULL && length == info.size );
1472 CPPUNIT_ASSERT( !memcmp(data, info.data, offset) );
1473 CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer, 2) );
1474 CPPUNIT_ASSERT( !memcmp((const char*)data + offset + 2,
1475 info.data + offset + 2,
1476 info.size - offset - 2) );
1477 // write starting inside the resource, but extending it
1478 size_t writeSize = info.size + 3;
1479 CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, offset,
1480 writeSize) == B_OK );
1481 data = resources.LoadResource(type, id, &length);
1482 CPPUNIT_ASSERT( data != NULL && length == (size_t)offset + writeSize );
1483 CPPUNIT_ASSERT( !memcmp(data, info.data, offset) );
1484 CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer,
1485 writeSize) );
1486 // write past the end of the resource
1487 size_t newOffset = length + 30;
1488 size_t newWriteSize = 17;
1489 CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer,
1490 newOffset, newWriteSize)
1491 == B_OK );
1492 data = resources.LoadResource(type, id, &length);
1493 CPPUNIT_ASSERT( data != NULL && length == newOffset + newWriteSize );
1494 CPPUNIT_ASSERT( !memcmp(data, info.data, offset) );
1495 CPPUNIT_ASSERT( !memcmp((const char*)data + offset, writeBuffer,
1496 writeSize) );
1497 // [offset + writeSize, newOffset) unspecified
1498 CPPUNIT_ASSERT( !memcmp((const char*)data + newOffset, writeBuffer,
1499 newWriteSize) );
1500 }
1501 // error cases
1502 // bad args
1503 NextSubTest();
1504 {
1505 BFile file(testFile1, B_READ_WRITE);
1506 CPPUNIT_ASSERT( file.InitCheck() == B_OK );
1507 BResources resources;
1508 CPPUNIT_ASSERT( resources.SetTo(&file, false) == B_OK );
1509 const ResourceInfo &info = testResource1;
1510 type_code type = info.type;
1511 int32 id = info.id;
1512 // NULL buffer
1513 CPPUNIT_ASSERT( resources.WriteResource(type, id, NULL, 0, 10)
1514 == B_BAD_VALUE );
1515 // non existing resource
1516 char writeBuffer[1024];
1517 CPPUNIT_ASSERT( resources.WriteResource(B_MESSENGER_TYPE, 0,
1518 writeBuffer, 0, 10)
1519 == B_BAD_VALUE );
1520 }
1521 // uninitialized BResources
1522 NextSubTest();
1523 {
1524 BResources resources;
1525 const ResourceInfo &info = testResource1;
1526 type_code type = info.type;
1527 int32 id = info.id;
1528 char writeBuffer[1024];
1529 CPPUNIT_ASSERT( resources.WriteResource(type, id, writeBuffer, 0, 10)
1530 == B_BAD_VALUE );
1531 }
1532 }
1533
1534
1535
1536
1537
1538