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