1// EntryTest.cpp
2
3#include <errno.h>
4#include <list>
5#include <map>
6#include <set>
7#include <stdio.h>
8#include <unistd.h>
9
10#include <cppunit/TestCaller.h>
11#include <cppunit/TestSuite.h>
12
13#include <Entry.h>
14#include <Directory.h>
15#include <Path.h>
16
17#include "EntryTest.h"
18
19enum test_entry_kind {
20	DIR_ENTRY,
21	FILE_ENTRY,
22	LINK_ENTRY,
23	ABSTRACT_ENTRY,
24	BAD_ENTRY,
25};
26
27struct TestEntry {
28	TestEntry();
29
30	void init(TestEntry &super, string name, test_entry_kind kind,
31			  bool relative = false);
32	void initDir(TestEntry &super, string name);
33	void initFile(TestEntry &super, string name);
34	void initRLink(TestEntry &super, string name, TestEntry &target);
35	void initALink(TestEntry &super, string name, TestEntry &target);
36	void initPath(const char *pathName = NULL);
37	void completeInit();
38	bool isConcrete() const { return !(isAbstract() || isBad()); }
39	bool isAbstract() const { return kind == ABSTRACT_ENTRY; }
40	bool isBad() const { return kind == BAD_ENTRY; }
41	const entry_ref &get_ref();
42
43	TestEntry *		super;
44	string			name;
45	test_entry_kind	kind;
46	string			path;
47	TestEntry *		target;
48	string			link;
49	entry_ref		ref;
50	bool			relative;
51	// C strings
52	const char *	cname;
53	const char *	cpath;
54	const char *	clink;
55};
56
57static list<TestEntry*> allTestEntries;
58
59static TestEntry badTestEntry;
60static TestEntry testDir;
61static TestEntry dir1;
62static TestEntry dir2;
63static TestEntry file1;
64static TestEntry file2;
65static TestEntry file3;
66static TestEntry file4;
67static TestEntry subDir1;
68static TestEntry abstractEntry1;
69static TestEntry badEntry1;
70static TestEntry absDirLink1;
71static TestEntry absDirLink2;
72static TestEntry absDirLink3;
73static TestEntry absDirLink4;
74static TestEntry relDirLink1;
75static TestEntry relDirLink2;
76static TestEntry relDirLink3;
77static TestEntry relDirLink4;
78static TestEntry absFileLink1;
79static TestEntry absFileLink2;
80static TestEntry absFileLink3;
81static TestEntry absFileLink4;
82static TestEntry relFileLink1;
83static TestEntry relFileLink2;
84static TestEntry relFileLink3;
85static TestEntry relFileLink4;
86static TestEntry absCyclicLink1;
87static TestEntry absCyclicLink2;
88static TestEntry relCyclicLink1;
89static TestEntry relCyclicLink2;
90static TestEntry absBadLink1;
91static TestEntry absBadLink2;
92static TestEntry absBadLink3;
93static TestEntry absBadLink4;
94static TestEntry relBadLink1;
95static TestEntry relBadLink2;
96static TestEntry relBadLink3;
97static TestEntry relBadLink4;
98static TestEntry absVeryBadLink1;
99static TestEntry absVeryBadLink2;
100static TestEntry absVeryBadLink3;
101static TestEntry absVeryBadLink4;
102static TestEntry relVeryBadLink1;
103static TestEntry relVeryBadLink2;
104static TestEntry relVeryBadLink3;
105static TestEntry relVeryBadLink4;
106static TestEntry tooLongEntry1;
107static TestEntry tooLongDir1;
108static TestEntry tooLongDir2;
109static TestEntry tooLongDir3;
110static TestEntry tooLongDir4;
111static TestEntry tooLongDir5;
112static TestEntry tooLongDir6;
113static TestEntry tooLongDir7;
114static TestEntry tooLongDir8;
115static TestEntry tooLongDir9;
116static TestEntry tooLongDir10;
117static TestEntry tooLongDir11;
118static TestEntry tooLongDir12;
119static TestEntry tooLongDir13;
120static TestEntry tooLongDir14;
121static TestEntry tooLongDir15;
122static TestEntry tooLongDir16;
123
124static string setUpCommandLine;
125static string tearDownCommandLine;
126
127// forward declarations
128static TestEntry *resolve_link(TestEntry *entry);
129static string get_shortest_relative_path(TestEntry *dir, TestEntry *entry);
130
131static const status_t kErrors[] = {
132	B_BAD_ADDRESS,
133	B_BAD_VALUE,
134	B_CROSS_DEVICE_LINK,
135	B_DEVICE_FULL,
136	B_DIRECTORY_NOT_EMPTY,
137	B_ENTRY_NOT_FOUND,
138	B_ERROR,
139	B_FILE_ERROR,
140	B_FILE_EXISTS,
141	B_FILE_NOT_FOUND,
142	B_IS_A_DIRECTORY,
143	B_LINK_LIMIT,
144	B_NAME_TOO_LONG,
145	B_NO_MORE_FDS,
146	B_NOT_A_DIRECTORY,
147	B_OK,
148	B_PARTITION_TOO_SMALL,
149	B_READ_ONLY_DEVICE,
150	B_UNSUPPORTED,
151	E2BIG
152};
153static const int32 kErrorCount = sizeof(kErrors) / sizeof(status_t);
154
155// get_error_index
156static
157int32
158get_error_index(status_t error)
159{
160	int32 result = -1;
161	for (int32 i = 0; result == -1 && i < kErrorCount; i++) {
162		if (kErrors[i] == error)
163			result = i;
164	}
165	if (result == -1)
166		printf("WARNING: error %lx is not in the list of errors\n", error);
167	return result;
168}
169
170// fuzzy_error
171static
172status_t
173fuzzy_error(status_t error1, status_t error2)
174{
175	status_t result = error1;
176	// encode the two errors in one value
177	int32 index1 = get_error_index(error1);
178	int32 index2 = get_error_index(error2);
179	if (index1 >= 0 && index2 >= 0)
180		result = index1 * kErrorCount + index2 + 1;
181	return result;
182}
183
184// fuzzy_equals
185static
186bool
187fuzzy_equals(status_t error, status_t fuzzyError)
188{
189	bool result = false;
190	if (fuzzyError <= 0)
191		result = (error == fuzzyError);
192	else {
193		// decode the error
194		int32 index1 = (fuzzyError - 1) / kErrorCount;
195		int32 index2 = (fuzzyError - 1) % kErrorCount;
196		if (index1 >= kErrorCount)
197			printf("WARNING: bad fuzzy error: %lx\n", fuzzyError);
198		else {
199			status_t error1 = kErrors[index1];
200			status_t error2 = kErrors[index2];
201			result = (error == error1 || error == error2);
202		}
203	}
204	return result;
205}
206
207
208// Suite
209CppUnit::Test*
210EntryTest::Suite()
211{
212	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
213	typedef CppUnit::TestCaller<EntryTest> TC;
214
215	StatableTest::AddBaseClassTests<EntryTest>("BEntry::", suite);
216
217	suite->addTest( new TC("BEntry::Init Test1", &EntryTest::InitTest1) );
218	suite->addTest( new TC("BEntry::Init Test2", &EntryTest::InitTest2) );
219	suite->addTest( new TC("BEntry::Special cases for Exists(), GetPath(),...",
220						   &EntryTest::SpecialGetCasesTest) );
221	suite->addTest( new TC("BEntry::Rename Test", &EntryTest::RenameTest) );
222	suite->addTest( new TC("BEntry::MoveTo Test", &EntryTest::MoveToTest) );
223	suite->addTest( new TC("BEntry::Remove Test", &EntryTest::RemoveTest) );
224	suite->addTest( new TC("BEntry::Comparison Test",
225						   &EntryTest::ComparisonTest) );
226	suite->addTest( new TC("BEntry::Assignment Test",
227						   &EntryTest::AssignmentTest) );
228	suite->addTest( new TC("BEntry::C Functions Test",
229						   &EntryTest::CFunctionsTest) );
230//	suite->addTest( new TC("BEntry::Miscellaneous Test", &EntryTest::MiscTest) );
231
232	return suite;
233}
234
235// CreateROStatables
236void
237EntryTest::CreateROStatables(TestStatables& testEntries)
238{
239	CreateRWStatables(testEntries);
240}
241
242// CreateRWStatables
243void
244EntryTest::CreateRWStatables(TestStatables& testStatables)
245{
246	TestEntry *testEntries[] = {
247		&dir1, &dir2, &file1, &subDir1,
248		&absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4,
249		&relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4,
250		&absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4,
251		&relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4,
252		&absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4,
253		&relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4,
254		&absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4,
255		&relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4
256	};
257	int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*);
258	for (int32 i = 0; i < testEntryCount; i++) {
259		TestEntry *testEntry = testEntries[i];
260		const char *filename = testEntry->cpath;
261		testStatables.add(new BEntry(filename), filename);
262	}
263}
264
265// CreateUninitializedStatables
266void
267EntryTest::CreateUninitializedStatables(TestStatables& testEntries)
268{
269	testEntries.add(new BEntry, "");
270}
271
272// setUp
273void
274EntryTest::setUp()
275{
276	StatableTest::setUp();
277	execCommand(setUpCommandLine);
278}
279
280// tearDown
281void
282EntryTest::tearDown()
283{
284	StatableTest::tearDown();
285	execCommand(tearDownCommandLine);
286}
287
288// examine_entry
289static
290void
291examine_entry(BEntry &entry, TestEntry *testEntry, bool traverse)
292{
293	if (traverse)
294		testEntry = resolve_link(testEntry);
295	// Exists()
296	CPPUNIT_ASSERT( entry.Exists() == testEntry->isConcrete() );
297	// GetPath()
298	BPath path;
299	CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
300	CPPUNIT_ASSERT( path == testEntry->cpath );
301	// GetName()
302	char name[B_FILE_NAME_LENGTH + 1];
303	CPPUNIT_ASSERT( entry.GetName(name) == B_OK );
304	CPPUNIT_ASSERT( testEntry->name == name );
305	// GetParent(BEntry *)
306	BEntry parentEntry;
307	CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_OK );
308	CPPUNIT_ASSERT( parentEntry.InitCheck() == B_OK );
309	CPPUNIT_ASSERT( parentEntry.GetPath(&path) == B_OK );
310	CPPUNIT_ASSERT( path == testEntry->super->cpath );
311	parentEntry.Unset();
312	path.Unset();
313	// GetParent(BDirectory *)
314	BDirectory parentDir;
315	CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_OK );
316	CPPUNIT_ASSERT( parentDir.GetEntry(&parentEntry) == B_OK );
317	CPPUNIT_ASSERT( parentEntry.InitCheck() == B_OK );
318	CPPUNIT_ASSERT( parentEntry.GetPath(&path) == B_OK );
319	CPPUNIT_ASSERT( path == testEntry->super->cpath );
320	// GetRef()
321	entry_ref ref;
322	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
323	// We can't get a ref of an entry with a too long path name yet.
324	if (testEntry->path.length() < B_PATH_NAME_LENGTH)
325		CPPUNIT_ASSERT( ref == testEntry->get_ref() );
326}
327
328// InitTest1Paths
329void
330EntryTest::InitTest1Paths(TestEntry &_testEntry, status_t error, bool traverse)
331{
332	TestEntry *testEntry = &_testEntry;
333	// absolute path
334	NextSubTest();
335	{
336//printf("%s\n", testEntry->cpath);
337		BEntry entry(testEntry->cpath, traverse);
338		status_t result = entry.InitCheck();
339if (!fuzzy_equals(result, error))
340printf("error: %lx (%lx)\n", result, error);
341		CPPUNIT_ASSERT( fuzzy_equals(result, error) );
342		if (result == B_OK)
343			examine_entry(entry, testEntry, traverse);
344	}
345	// relative path
346	NextSubTest();
347	{
348//printf("%s\n", testEntry->cpath);
349		if (chdir(testEntry->super->cpath) == 0) {
350			BEntry entry(testEntry->cname, traverse);
351			status_t result = entry.InitCheck();
352if (!fuzzy_equals(result, error))
353printf("error: %lx (%lx)\n", result, error);
354			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
355			if (error == B_OK)
356				examine_entry(entry, testEntry, traverse);
357			RestoreCWD();
358		}
359	}
360}
361
362// InitTest1Refs
363void
364EntryTest::InitTest1Refs(TestEntry &_testEntry, status_t error, bool traverse)
365{
366	TestEntry *testEntry = &_testEntry;
367	// absolute path
368	NextSubTest();
369	{
370//printf("%s\n", testEntry->cpath);
371		BEntry entry(&testEntry->get_ref(), traverse);
372		status_t result = entry.InitCheck();
373if (!fuzzy_equals(result, error))
374printf("error: %lx (%lx)\n", result, error);
375		CPPUNIT_ASSERT( fuzzy_equals(result, error) );
376		if (error == B_OK)
377			examine_entry(entry, testEntry, traverse);
378	}
379}
380
381// InitTest1DirPaths
382void
383EntryTest::InitTest1DirPaths(TestEntry &_testEntry, status_t error,
384							 bool traverse)
385{
386	TestEntry *testEntry = &_testEntry;
387	// absolute path
388	NextSubTest();
389	{
390		if (!testEntry->isBad()
391			&& testEntry->path.length() < B_PATH_NAME_LENGTH) {
392//printf("%s\n", testEntry->cpath);
393			BDirectory dir("/boot/home/Desktop");
394			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
395			BEntry entry(&dir, testEntry->cpath, traverse);
396		status_t result = entry.InitCheck();
397if (!fuzzy_equals(result, error))
398printf("error: %lx (%lx)\n", result, error);
399		CPPUNIT_ASSERT( fuzzy_equals(result, error) );
400			if (error == B_OK)
401				examine_entry(entry, testEntry, traverse);
402		}
403	}
404	// relative path (one level)
405	NextSubTest();
406	{
407		if (!testEntry->isBad()
408			&& testEntry->super->path.length() < B_PATH_NAME_LENGTH) {
409//printf("%s + %s\n", testEntry->super->cpath, testEntry->cname);
410			BDirectory dir(testEntry->super->cpath);
411			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
412			BEntry entry(&dir, testEntry->cname, traverse);
413			status_t result = entry.InitCheck();
414if (!fuzzy_equals(result, error))
415printf("error: %lx (%lx)\n", result, error);
416			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
417			if (error == B_OK)
418				examine_entry(entry, testEntry, traverse);
419		}
420	}
421	// relative path (two levels)
422	NextSubTest();
423	{
424		if (!testEntry->super->isBad() && !testEntry->super->super->isBad()) {
425			string entryName  = testEntry->super->name + "/" + testEntry->name;
426//printf("%s + %s\n", testEntry->super->super->cpath, entryName.c_str());
427			BDirectory dir(testEntry->super->super->cpath);
428			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
429			BEntry entry(&dir, entryName.c_str(), traverse);
430			status_t result = entry.InitCheck();
431if (!fuzzy_equals(result, error))
432printf("error: %lx (%lx)\n", result, error);
433			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
434			if (error == B_OK)
435				examine_entry(entry, testEntry, traverse);
436		}
437	}
438}
439
440// InitTest1
441void
442EntryTest::InitTest1()
443{
444	// 1. default constructor
445	NextSubTest();
446	{
447		BEntry entry;
448		CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
449	}
450
451	// 2. BEntry(const char *, bool)
452	// don't traverse
453	InitTest1Paths(dir1, B_OK);
454	InitTest1Paths(dir2, B_OK);
455	InitTest1Paths(file1, B_OK);
456	InitTest1Paths(subDir1, B_OK);
457	InitTest1Paths(abstractEntry1, B_OK);
458	InitTest1Paths(badEntry1, B_ENTRY_NOT_FOUND);
459	InitTest1Paths(absDirLink1, B_OK);
460	InitTest1Paths(absDirLink2, B_OK);
461	InitTest1Paths(absDirLink3, B_OK);
462	InitTest1Paths(absDirLink4, B_OK);
463	InitTest1Paths(relDirLink1, B_OK);
464	InitTest1Paths(relDirLink2, B_OK);
465	InitTest1Paths(relDirLink3, B_OK);
466	InitTest1Paths(relDirLink4, B_OK);
467	InitTest1Paths(absFileLink1, B_OK);
468	InitTest1Paths(absFileLink2, B_OK);
469	InitTest1Paths(absFileLink3, B_OK);
470	InitTest1Paths(absFileLink4, B_OK);
471	InitTest1Paths(relFileLink1, B_OK);
472	InitTest1Paths(relFileLink2, B_OK);
473	InitTest1Paths(relFileLink3, B_OK);
474	InitTest1Paths(relFileLink4, B_OK);
475	InitTest1Paths(absCyclicLink1, B_OK);
476	InitTest1Paths(relCyclicLink1, B_OK);
477	InitTest1Paths(absBadLink1, B_OK);
478	InitTest1Paths(absBadLink2, B_OK);
479	InitTest1Paths(absBadLink3, B_OK);
480	InitTest1Paths(absBadLink4, B_OK);
481	InitTest1Paths(relBadLink1, B_OK);
482	InitTest1Paths(relBadLink2, B_OK);
483	InitTest1Paths(relBadLink3, B_OK);
484	InitTest1Paths(relBadLink4, B_OK);
485	InitTest1Paths(absVeryBadLink1, B_OK);
486	InitTest1Paths(absVeryBadLink2, B_OK);
487	InitTest1Paths(absVeryBadLink3, B_OK);
488	InitTest1Paths(absVeryBadLink4, B_OK);
489	InitTest1Paths(relVeryBadLink1, B_OK);
490	InitTest1Paths(relVeryBadLink2, B_OK);
491	InitTest1Paths(relVeryBadLink3, B_OK);
492	InitTest1Paths(relVeryBadLink4, B_OK);
493// R5: returns E2BIG instead of B_NAME_TOO_LONG
494	InitTest1Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG));
495// R5: returns B_ERROR instead of B_NAME_TOO_LONG
496	InitTest1Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG));
497	// traverse
498	InitTest1Paths(dir1, B_OK, true);
499	InitTest1Paths(dir2, B_OK, true);
500	InitTest1Paths(file1, B_OK, true);
501	InitTest1Paths(subDir1, B_OK, true);
502	InitTest1Paths(abstractEntry1, B_OK, true);
503	InitTest1Paths(badEntry1, B_ENTRY_NOT_FOUND, true);
504	InitTest1Paths(absDirLink1, B_OK, true);
505	InitTest1Paths(absDirLink2, B_OK, true);
506	InitTest1Paths(absDirLink3, B_OK, true);
507	InitTest1Paths(absDirLink4, B_OK, true);
508	InitTest1Paths(relDirLink1, B_OK, true);
509	InitTest1Paths(relDirLink2, B_OK, true);
510	InitTest1Paths(relDirLink3, B_OK, true);
511	InitTest1Paths(relDirLink4, B_OK, true);
512	InitTest1Paths(absFileLink1, B_OK, true);
513	InitTest1Paths(absFileLink2, B_OK, true);
514	InitTest1Paths(absFileLink3, B_OK, true);
515	InitTest1Paths(absFileLink4, B_OK, true);
516	InitTest1Paths(relFileLink1, B_OK, true);
517	InitTest1Paths(relFileLink2, B_OK, true);
518	InitTest1Paths(relFileLink3, B_OK, true);
519	InitTest1Paths(relFileLink4, B_OK, true);
520	InitTest1Paths(absCyclicLink1, B_LINK_LIMIT, true);
521	InitTest1Paths(relCyclicLink1, B_LINK_LIMIT, true);
522	InitTest1Paths(absBadLink1, B_ENTRY_NOT_FOUND, true);
523	InitTest1Paths(absBadLink2, B_ENTRY_NOT_FOUND, true);
524	InitTest1Paths(absBadLink3, B_ENTRY_NOT_FOUND, true);
525	InitTest1Paths(absBadLink4, B_ENTRY_NOT_FOUND, true);
526	InitTest1Paths(relBadLink1, B_ENTRY_NOT_FOUND, true);
527	InitTest1Paths(relBadLink2, B_ENTRY_NOT_FOUND, true);
528	InitTest1Paths(relBadLink3, B_ENTRY_NOT_FOUND, true);
529	InitTest1Paths(relBadLink4, B_ENTRY_NOT_FOUND, true);
530	InitTest1Paths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
531	InitTest1Paths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
532	InitTest1Paths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
533	InitTest1Paths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
534	InitTest1Paths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
535	InitTest1Paths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
536	InitTest1Paths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
537	InitTest1Paths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
538// R5: returns E2BIG instead of B_NAME_TOO_LONG
539	InitTest1Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true);
540// R5: returns B_ERROR instead of B_NAME_TOO_LONG
541	InitTest1Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG), true);
542
543	// special cases (root dir)
544	NextSubTest();
545	{
546		BEntry entry("/");
547		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
548	}
549	// special cases (fs root dir)
550	NextSubTest();
551	{
552		BEntry entry("/boot");
553		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
554	}
555	// bad args
556	NextSubTest();
557	{
558		BEntry entry((const char*)NULL);
559		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
560	}
561
562	// 3. BEntry(const entry_ref *, bool)
563	// don't traverse
564	InitTest1Refs(dir1, B_OK);
565	InitTest1Refs(dir2, B_OK);
566	InitTest1Refs(file1, B_OK);
567	InitTest1Refs(subDir1, B_OK);
568	InitTest1Refs(abstractEntry1, B_OK);
569	InitTest1Refs(absDirLink1, B_OK);
570	InitTest1Refs(absDirLink2, B_OK);
571	InitTest1Refs(absDirLink3, B_OK);
572	InitTest1Refs(absDirLink4, B_OK);
573	InitTest1Refs(relDirLink1, B_OK);
574	InitTest1Refs(relDirLink2, B_OK);
575	InitTest1Refs(relDirLink3, B_OK);
576	InitTest1Refs(relDirLink4, B_OK);
577	InitTest1Refs(absFileLink1, B_OK);
578	InitTest1Refs(absFileLink2, B_OK);
579	InitTest1Refs(absFileLink3, B_OK);
580	InitTest1Refs(absFileLink4, B_OK);
581	InitTest1Refs(relFileLink1, B_OK);
582	InitTest1Refs(relFileLink2, B_OK);
583	InitTest1Refs(relFileLink3, B_OK);
584	InitTest1Refs(relFileLink4, B_OK);
585	InitTest1Refs(absCyclicLink1, B_OK);
586	InitTest1Refs(relCyclicLink1, B_OK);
587	InitTest1Refs(absBadLink1, B_OK);
588	InitTest1Refs(absBadLink2, B_OK);
589	InitTest1Refs(absBadLink3, B_OK);
590	InitTest1Refs(absBadLink4, B_OK);
591	InitTest1Refs(relBadLink1, B_OK);
592	InitTest1Refs(relBadLink2, B_OK);
593	InitTest1Refs(relBadLink3, B_OK);
594	InitTest1Refs(relBadLink4, B_OK);
595	InitTest1Refs(absVeryBadLink1, B_OK);
596	InitTest1Refs(absVeryBadLink2, B_OK);
597	InitTest1Refs(absVeryBadLink3, B_OK);
598	InitTest1Refs(absVeryBadLink4, B_OK);
599	InitTest1Refs(relVeryBadLink1, B_OK);
600	InitTest1Refs(relVeryBadLink2, B_OK);
601	InitTest1Refs(relVeryBadLink3, B_OK);
602	InitTest1Refs(relVeryBadLink4, B_OK);
603	// traverse
604	InitTest1Refs(dir1, B_OK, true);
605	InitTest1Refs(dir2, B_OK, true);
606	InitTest1Refs(file1, B_OK, true);
607	InitTest1Refs(subDir1, B_OK, true);
608	InitTest1Refs(abstractEntry1, B_OK, true);
609	InitTest1Refs(absDirLink1, B_OK, true);
610	InitTest1Refs(absDirLink2, B_OK, true);
611	InitTest1Refs(absDirLink3, B_OK, true);
612	InitTest1Refs(absDirLink4, B_OK, true);
613	InitTest1Refs(relDirLink1, B_OK, true);
614	InitTest1Refs(relDirLink2, B_OK, true);
615	InitTest1Refs(relDirLink3, B_OK, true);
616	InitTest1Refs(relDirLink4, B_OK, true);
617	InitTest1Refs(absFileLink1, B_OK, true);
618	InitTest1Refs(absFileLink2, B_OK, true);
619	InitTest1Refs(absFileLink3, B_OK, true);
620	InitTest1Refs(absFileLink4, B_OK, true);
621	InitTest1Refs(relFileLink1, B_OK, true);
622	InitTest1Refs(relFileLink2, B_OK, true);
623	InitTest1Refs(relFileLink3, B_OK, true);
624	InitTest1Refs(relFileLink4, B_OK, true);
625	InitTest1Refs(absCyclicLink1, B_LINK_LIMIT, true);
626	InitTest1Refs(relCyclicLink1, B_LINK_LIMIT, true);
627	InitTest1Refs(absBadLink1, B_ENTRY_NOT_FOUND, true);
628	InitTest1Refs(absBadLink2, B_ENTRY_NOT_FOUND, true);
629	InitTest1Refs(absBadLink3, B_ENTRY_NOT_FOUND, true);
630	InitTest1Refs(absBadLink4, B_ENTRY_NOT_FOUND, true);
631	InitTest1Refs(relBadLink1, B_ENTRY_NOT_FOUND, true);
632	InitTest1Refs(relBadLink2, B_ENTRY_NOT_FOUND, true);
633	InitTest1Refs(relBadLink3, B_ENTRY_NOT_FOUND, true);
634	InitTest1Refs(relBadLink4, B_ENTRY_NOT_FOUND, true);
635	InitTest1Refs(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
636	InitTest1Refs(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
637	InitTest1Refs(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
638	InitTest1Refs(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
639	InitTest1Refs(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
640	InitTest1Refs(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
641	InitTest1Refs(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
642	InitTest1Refs(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
643	// bad args
644	NextSubTest();
645	{
646		BEntry entry((const entry_ref*)NULL);
647		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
648	}
649
650	// 4. BEntry(const BDirectory *, const char *, bool)
651	// don't traverse
652	InitTest1DirPaths(dir1, B_OK);
653	InitTest1DirPaths(dir2, B_OK);
654	InitTest1DirPaths(file1, B_OK);
655	InitTest1DirPaths(subDir1, B_OK);
656	InitTest1DirPaths(abstractEntry1, B_OK);
657	InitTest1DirPaths(badEntry1, B_ENTRY_NOT_FOUND);
658	InitTest1DirPaths(absDirLink1, B_OK);
659	InitTest1DirPaths(absDirLink2, B_OK);
660	InitTest1DirPaths(absDirLink3, B_OK);
661	InitTest1DirPaths(absDirLink4, B_OK);
662	InitTest1DirPaths(relDirLink1, B_OK);
663	InitTest1DirPaths(relDirLink2, B_OK);
664	InitTest1DirPaths(relDirLink3, B_OK);
665	InitTest1DirPaths(relDirLink4, B_OK);
666	InitTest1DirPaths(absFileLink1, B_OK);
667	InitTest1DirPaths(absFileLink2, B_OK);
668	InitTest1DirPaths(absFileLink3, B_OK);
669	InitTest1DirPaths(absFileLink4, B_OK);
670	InitTest1DirPaths(relFileLink1, B_OK);
671	InitTest1DirPaths(relFileLink2, B_OK);
672	InitTest1DirPaths(relFileLink3, B_OK);
673	InitTest1DirPaths(relFileLink4, B_OK);
674	InitTest1DirPaths(absCyclicLink1, B_OK);
675	InitTest1DirPaths(relCyclicLink1, B_OK);
676	InitTest1DirPaths(absBadLink1, B_OK);
677	InitTest1DirPaths(absBadLink2, B_OK);
678	InitTest1DirPaths(absBadLink3, B_OK);
679	InitTest1DirPaths(absBadLink4, B_OK);
680	InitTest1DirPaths(relBadLink1, B_OK);
681	InitTest1DirPaths(relBadLink2, B_OK);
682	InitTest1DirPaths(relBadLink3, B_OK);
683	InitTest1DirPaths(relBadLink4, B_OK);
684	InitTest1DirPaths(absVeryBadLink1, B_OK);
685	InitTest1DirPaths(absVeryBadLink2, B_OK);
686	InitTest1DirPaths(absVeryBadLink3, B_OK);
687	InitTest1DirPaths(absVeryBadLink4, B_OK);
688	InitTest1DirPaths(relVeryBadLink1, B_OK);
689	InitTest1DirPaths(relVeryBadLink2, B_OK);
690	InitTest1DirPaths(relVeryBadLink3, B_OK);
691	InitTest1DirPaths(relVeryBadLink4, B_OK);
692// R5: returns E2BIG instead of B_NAME_TOO_LONG
693	InitTest1DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG));
694// OBOS: Fails, because the implementation concatenates the dir and leaf
695// 		 name.
696#if !TEST_OBOS /* !!!POSIX ONLY!!! */
697	InitTest1DirPaths(tooLongDir16, B_OK, true);
698#endif
699	// traverse
700	InitTest1DirPaths(dir1, B_OK, true);
701	InitTest1DirPaths(dir2, B_OK, true);
702	InitTest1DirPaths(file1, B_OK, true);
703	InitTest1DirPaths(subDir1, B_OK, true);
704	InitTest1DirPaths(abstractEntry1, B_OK, true);
705	InitTest1DirPaths(badEntry1, B_ENTRY_NOT_FOUND, true);
706	InitTest1DirPaths(absDirLink1, B_OK, true);
707	InitTest1DirPaths(absDirLink2, B_OK, true);
708	InitTest1DirPaths(absDirLink3, B_OK, true);
709	InitTest1DirPaths(absDirLink4, B_OK, true);
710	InitTest1DirPaths(relDirLink1, B_OK, true);
711	InitTest1DirPaths(relDirLink2, B_OK, true);
712	InitTest1DirPaths(relDirLink3, B_OK, true);
713	InitTest1DirPaths(relDirLink4, B_OK, true);
714	InitTest1DirPaths(absFileLink1, B_OK, true);
715	InitTest1DirPaths(absFileLink2, B_OK, true);
716	InitTest1DirPaths(absFileLink3, B_OK, true);
717	InitTest1DirPaths(absFileLink4, B_OK, true);
718	InitTest1DirPaths(relFileLink1, B_OK, true);
719	InitTest1DirPaths(relFileLink2, B_OK, true);
720	InitTest1DirPaths(relFileLink3, B_OK, true);
721	InitTest1DirPaths(relFileLink4, B_OK, true);
722	InitTest1DirPaths(absCyclicLink1, B_LINK_LIMIT, true);
723	InitTest1DirPaths(relCyclicLink1, B_LINK_LIMIT, true);
724	InitTest1DirPaths(absBadLink1, B_ENTRY_NOT_FOUND, true);
725	InitTest1DirPaths(absBadLink2, B_ENTRY_NOT_FOUND, true);
726	InitTest1DirPaths(absBadLink3, B_ENTRY_NOT_FOUND, true);
727	InitTest1DirPaths(absBadLink4, B_ENTRY_NOT_FOUND, true);
728	InitTest1DirPaths(relBadLink1, B_ENTRY_NOT_FOUND, true);
729	InitTest1DirPaths(relBadLink2, B_ENTRY_NOT_FOUND, true);
730	InitTest1DirPaths(relBadLink3, B_ENTRY_NOT_FOUND, true);
731	InitTest1DirPaths(relBadLink4, B_ENTRY_NOT_FOUND, true);
732	InitTest1DirPaths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
733	InitTest1DirPaths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
734	InitTest1DirPaths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
735	InitTest1DirPaths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
736	InitTest1DirPaths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
737	InitTest1DirPaths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
738	InitTest1DirPaths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
739	InitTest1DirPaths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
740// R5: returns E2BIG instead of B_NAME_TOO_LONG
741	InitTest1DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true);
742// OBOS: Fails, because the implementation concatenates the dir and leaf
743// 		 name.
744#if !TEST_OBOS /* !!!POSIX ONLY!!! */
745	InitTest1DirPaths(tooLongDir16, B_OK, true);
746#endif
747
748	// special cases (root dir)
749	NextSubTest();
750	{
751		BDirectory dir("/");
752		BEntry entry(&dir, ".");
753		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
754	}
755	// special cases (fs root dir)
756	NextSubTest();
757	{
758		BDirectory dir("/");
759		BEntry entry(&dir, "boot");
760		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
761	}
762	// NULL path
763	NextSubTest();
764	{
765		BDirectory dir("/");
766		BEntry entry(&dir, (const char*)NULL);
767		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
768	}
769	// bad args (NULL dir)
770// R5: crashs
771#if !TEST_R5
772	NextSubTest();
773	{
774		chdir("/");
775		BEntry entry((const BDirectory*)NULL, "tmp");
776		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
777		RestoreCWD();
778	}
779#endif
780	// strange args (badly initialized dir, absolute path)
781	NextSubTest();
782	{
783		BDirectory dir(badEntry1.cpath);
784		CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND );
785		BEntry entry(&dir, "/tmp");
786		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
787	}
788	// bad args (NULL dir and path)
789// R5: crashs
790#if !TEST_R5
791	NextSubTest();
792	{
793		BEntry entry((const BDirectory*)NULL, (const char*)NULL);
794		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
795	}
796#endif
797	// bad args(NULL dir, absolute path)
798// R5: crashs
799#if !TEST_R5
800	NextSubTest();
801	{
802		BEntry entry((const BDirectory*)NULL, "/tmp");
803		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
804	}
805#endif
806}
807
808// InitTest2Paths
809void
810EntryTest::InitTest2Paths(TestEntry &_testEntry, status_t error, bool traverse)
811{
812	TestEntry *testEntry = &_testEntry;
813	BEntry entry;
814	// absolute path
815	NextSubTest();
816	{
817//printf("%s\n", testEntry->cpath);
818		status_t result = entry.SetTo(testEntry->cpath, traverse);
819if (!fuzzy_equals(result, error))
820printf("error: %lx (%lx)\n", result, error);
821		CPPUNIT_ASSERT( fuzzy_equals(result, error) );
822		CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
823		if (result == B_OK)
824			examine_entry(entry, testEntry, traverse);
825	}
826	// relative path
827	NextSubTest();
828	{
829//printf("%s\n", testEntry->cpath);
830		if (chdir(testEntry->super->cpath) == 0) {
831			status_t result = entry.SetTo(testEntry->cname, traverse);
832if (!fuzzy_equals(result, error))
833printf("error: %lx (%lx)\n", result, error);
834			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
835			CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
836			if (result == B_OK)
837				examine_entry(entry, testEntry, traverse);
838			RestoreCWD();
839		}
840	}
841}
842
843// InitTest2Refs
844void
845EntryTest::InitTest2Refs(TestEntry &_testEntry, status_t error, bool traverse)
846{
847	TestEntry *testEntry = &_testEntry;
848	BEntry entry;
849	// absolute path
850	NextSubTest();
851	{
852//printf("%s\n", testEntry->cpath);
853		status_t result = entry.SetTo(&testEntry->get_ref(), traverse);
854if (!fuzzy_equals(result, error))
855printf("error: %lx (%lx)\n", result, error);
856		CPPUNIT_ASSERT( fuzzy_equals(result, error) );
857		CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
858		if (result == B_OK)
859			examine_entry(entry, testEntry, traverse);
860	}
861}
862
863// InitTest2DirPaths
864void
865EntryTest::InitTest2DirPaths(TestEntry &_testEntry, status_t error,
866							 bool traverse)
867{
868	TestEntry *testEntry = &_testEntry;
869	BEntry entry;
870	// absolute path
871	NextSubTest();
872	{
873		if (!testEntry->isBad()
874			&& testEntry->path.length() < B_PATH_NAME_LENGTH) {
875//printf("%s\n", testEntry->cpath);
876			BDirectory dir("/boot/home/Desktop");
877			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
878			status_t result = entry.SetTo(&dir, testEntry->cpath, traverse);
879if (!fuzzy_equals(result, error))
880printf("error: %lx (%lx)\n", result, error);
881			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
882			CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
883			if (result == B_OK)
884				examine_entry(entry, testEntry, traverse);
885		}
886	}
887	// relative path (one level)
888	NextSubTest();
889	{
890		if (!testEntry->isBad()
891			&& testEntry->super->path.length() < B_PATH_NAME_LENGTH) {
892//printf("%s + %s\n", testEntry->super->cpath, testEntry->cname);
893			BDirectory dir(testEntry->super->cpath);
894			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
895			status_t result = entry.SetTo(&dir, testEntry->cname, traverse);
896if (!fuzzy_equals(result, error))
897printf("error: %lx (%lx)\n", result, error);
898			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
899			CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
900			if (result == B_OK)
901				examine_entry(entry, testEntry, traverse);
902		}
903	}
904	// relative path (two levels)
905	NextSubTest();
906	{
907		if (!testEntry->super->isBad() && !testEntry->super->super->isBad()) {
908			string entryName  = testEntry->super->name + "/" + testEntry->name;
909//printf("%s + %s\n", testEntry->super->super->cpath, entryName.c_str());
910			BDirectory dir(testEntry->super->super->cpath);
911			CPPUNIT_ASSERT( dir.InitCheck() == B_OK );
912			status_t result = entry.SetTo(&dir, entryName.c_str(), traverse);
913if (!fuzzy_equals(result, error))
914printf("error: %lx (%lx)\n", result, error);
915			CPPUNIT_ASSERT( fuzzy_equals(result, error) );
916			CPPUNIT_ASSERT( fuzzy_equals(entry.InitCheck(), error) );
917			if (result == B_OK)
918				examine_entry(entry, testEntry, traverse);
919		}
920	}
921}
922
923// InitTest2
924void
925EntryTest::InitTest2()
926{
927	BEntry entry;
928	// 2. SetTo(const char *, bool)
929	// don't traverse
930	InitTest2Paths(dir1, B_OK);
931	InitTest2Paths(dir2, B_OK);
932	InitTest2Paths(file1, B_OK);
933	InitTest2Paths(subDir1, B_OK);
934	InitTest2Paths(abstractEntry1, B_OK);
935	InitTest2Paths(badEntry1, B_ENTRY_NOT_FOUND);
936	InitTest2Paths(absDirLink1, B_OK);
937	InitTest2Paths(absDirLink2, B_OK);
938	InitTest2Paths(absDirLink3, B_OK);
939	InitTest2Paths(absDirLink4, B_OK);
940	InitTest2Paths(relDirLink1, B_OK);
941	InitTest2Paths(relDirLink2, B_OK);
942	InitTest2Paths(relDirLink3, B_OK);
943	InitTest2Paths(relDirLink4, B_OK);
944	InitTest2Paths(absFileLink1, B_OK);
945	InitTest2Paths(absFileLink2, B_OK);
946	InitTest2Paths(absFileLink3, B_OK);
947	InitTest2Paths(absFileLink4, B_OK);
948	InitTest2Paths(relFileLink1, B_OK);
949	InitTest2Paths(relFileLink2, B_OK);
950	InitTest2Paths(relFileLink3, B_OK);
951	InitTest2Paths(relFileLink4, B_OK);
952	InitTest2Paths(absCyclicLink1, B_OK);
953	InitTest2Paths(relCyclicLink1, B_OK);
954	InitTest2Paths(absBadLink1, B_OK);
955	InitTest2Paths(absBadLink2, B_OK);
956	InitTest2Paths(absBadLink3, B_OK);
957	InitTest2Paths(absBadLink4, B_OK);
958	InitTest2Paths(relBadLink1, B_OK);
959	InitTest2Paths(relBadLink2, B_OK);
960	InitTest2Paths(relBadLink3, B_OK);
961	InitTest2Paths(relBadLink4, B_OK);
962	InitTest2Paths(absVeryBadLink1, B_OK);
963	InitTest2Paths(absVeryBadLink2, B_OK);
964	InitTest2Paths(absVeryBadLink3, B_OK);
965	InitTest2Paths(absVeryBadLink4, B_OK);
966	InitTest2Paths(relVeryBadLink1, B_OK);
967	InitTest2Paths(relVeryBadLink2, B_OK);
968	InitTest2Paths(relVeryBadLink3, B_OK);
969	InitTest2Paths(relVeryBadLink4, B_OK);
970// R5: returns E2BIG instead of B_NAME_TOO_LONG
971	InitTest2Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG));
972// R5: returns B_ERROR instead of B_NAME_TOO_LONG
973	InitTest2Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG));
974	// traverse
975	InitTest2Paths(dir1, B_OK, true);
976	InitTest2Paths(dir2, B_OK, true);
977	InitTest2Paths(file1, B_OK, true);
978	InitTest2Paths(subDir1, B_OK, true);
979	InitTest2Paths(abstractEntry1, B_OK, true);
980	InitTest2Paths(badEntry1, B_ENTRY_NOT_FOUND, true);
981	InitTest2Paths(absDirLink1, B_OK, true);
982	InitTest2Paths(absDirLink2, B_OK, true);
983	InitTest2Paths(absDirLink3, B_OK, true);
984	InitTest2Paths(absDirLink4, B_OK, true);
985	InitTest2Paths(relDirLink1, B_OK, true);
986	InitTest2Paths(relDirLink2, B_OK, true);
987	InitTest2Paths(relDirLink3, B_OK, true);
988	InitTest2Paths(relDirLink4, B_OK, true);
989	InitTest2Paths(absFileLink1, B_OK, true);
990	InitTest2Paths(absFileLink2, B_OK, true);
991	InitTest2Paths(absFileLink3, B_OK, true);
992	InitTest2Paths(absFileLink4, B_OK, true);
993	InitTest2Paths(relFileLink1, B_OK, true);
994	InitTest2Paths(relFileLink2, B_OK, true);
995	InitTest2Paths(relFileLink3, B_OK, true);
996	InitTest2Paths(relFileLink4, B_OK, true);
997	InitTest2Paths(absCyclicLink1, B_LINK_LIMIT, true);
998	InitTest2Paths(relCyclicLink1, B_LINK_LIMIT, true);
999	InitTest2Paths(absBadLink1, B_ENTRY_NOT_FOUND, true);
1000	InitTest2Paths(absBadLink2, B_ENTRY_NOT_FOUND, true);
1001	InitTest2Paths(absBadLink3, B_ENTRY_NOT_FOUND, true);
1002	InitTest2Paths(absBadLink4, B_ENTRY_NOT_FOUND, true);
1003	InitTest2Paths(relBadLink1, B_ENTRY_NOT_FOUND, true);
1004	InitTest2Paths(relBadLink2, B_ENTRY_NOT_FOUND, true);
1005	InitTest2Paths(relBadLink3, B_ENTRY_NOT_FOUND, true);
1006	InitTest2Paths(relBadLink4, B_ENTRY_NOT_FOUND, true);
1007	InitTest2Paths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1008	InitTest2Paths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1009	InitTest2Paths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1010	InitTest2Paths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1011	InitTest2Paths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1012	InitTest2Paths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1013	InitTest2Paths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1014	InitTest2Paths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1015// R5: returns E2BIG instead of B_NAME_TOO_LONG
1016	InitTest2Paths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true);
1017// R5: returns B_ERROR instead of B_NAME_TOO_LONG
1018	InitTest2Paths(tooLongDir16, fuzzy_error(B_ERROR, B_NAME_TOO_LONG), true);
1019	// special cases (root dir)
1020	NextSubTest();
1021	CPPUNIT_ASSERT( entry.SetTo("/") == B_OK );
1022	CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1023	entry.Unset();
1024	// special cases (fs root dir)
1025	NextSubTest();
1026	CPPUNIT_ASSERT( entry.SetTo("/boot") == B_OK );
1027	CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1028	entry.Unset();
1029	// bad args
1030	NextSubTest();
1031	CPPUNIT_ASSERT( entry.SetTo((const char*)NULL) == B_BAD_VALUE );
1032	CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
1033	entry.Unset();
1034
1035	// 3. BEntry(const entry_ref *, bool)
1036	// don't traverse
1037	InitTest2Refs(dir1, B_OK);
1038	InitTest2Refs(dir2, B_OK);
1039	InitTest2Refs(file1, B_OK);
1040	InitTest2Refs(subDir1, B_OK);
1041	InitTest2Refs(abstractEntry1, B_OK);
1042	InitTest2Refs(absDirLink1, B_OK);
1043	InitTest2Refs(absDirLink2, B_OK);
1044	InitTest2Refs(absDirLink3, B_OK);
1045	InitTest2Refs(absDirLink4, B_OK);
1046	InitTest2Refs(relDirLink1, B_OK);
1047	InitTest2Refs(relDirLink2, B_OK);
1048	InitTest2Refs(relDirLink3, B_OK);
1049	InitTest2Refs(relDirLink4, B_OK);
1050	InitTest2Refs(absFileLink1, B_OK);
1051	InitTest2Refs(absFileLink2, B_OK);
1052	InitTest2Refs(absFileLink3, B_OK);
1053	InitTest2Refs(absFileLink4, B_OK);
1054	InitTest2Refs(relFileLink1, B_OK);
1055	InitTest2Refs(relFileLink2, B_OK);
1056	InitTest2Refs(relFileLink3, B_OK);
1057	InitTest2Refs(relFileLink4, B_OK);
1058	InitTest2Refs(absCyclicLink1, B_OK);
1059	InitTest2Refs(relCyclicLink1, B_OK);
1060	InitTest2Refs(absBadLink1, B_OK);
1061	InitTest2Refs(absBadLink2, B_OK);
1062	InitTest2Refs(absBadLink3, B_OK);
1063	InitTest2Refs(absBadLink4, B_OK);
1064	InitTest2Refs(relBadLink1, B_OK);
1065	InitTest2Refs(relBadLink2, B_OK);
1066	InitTest2Refs(relBadLink3, B_OK);
1067	InitTest2Refs(relBadLink4, B_OK);
1068	InitTest2Refs(absVeryBadLink1, B_OK);
1069	InitTest2Refs(absVeryBadLink2, B_OK);
1070	InitTest2Refs(absVeryBadLink3, B_OK);
1071	InitTest2Refs(absVeryBadLink4, B_OK);
1072	InitTest2Refs(relVeryBadLink1, B_OK);
1073	InitTest2Refs(relVeryBadLink2, B_OK);
1074	InitTest2Refs(relVeryBadLink3, B_OK);
1075	InitTest2Refs(relVeryBadLink4, B_OK);
1076	// traverse
1077	InitTest2Refs(dir1, B_OK, true);
1078	InitTest2Refs(dir2, B_OK, true);
1079	InitTest2Refs(file1, B_OK, true);
1080	InitTest2Refs(subDir1, B_OK, true);
1081	InitTest2Refs(abstractEntry1, B_OK, true);
1082	InitTest2Refs(absDirLink1, B_OK, true);
1083	InitTest2Refs(absDirLink2, B_OK, true);
1084	InitTest2Refs(absDirLink3, B_OK, true);
1085	InitTest2Refs(absDirLink4, B_OK, true);
1086	InitTest2Refs(relDirLink1, B_OK, true);
1087	InitTest2Refs(relDirLink2, B_OK, true);
1088	InitTest2Refs(relDirLink3, B_OK, true);
1089	InitTest2Refs(relDirLink4, B_OK, true);
1090	InitTest2Refs(absFileLink1, B_OK, true);
1091	InitTest2Refs(absFileLink2, B_OK, true);
1092	InitTest2Refs(absFileLink3, B_OK, true);
1093	InitTest2Refs(absFileLink4, B_OK, true);
1094	InitTest2Refs(relFileLink1, B_OK, true);
1095	InitTest2Refs(relFileLink2, B_OK, true);
1096	InitTest2Refs(relFileLink3, B_OK, true);
1097	InitTest2Refs(relFileLink4, B_OK, true);
1098	InitTest2Refs(absCyclicLink1, B_LINK_LIMIT, true);
1099	InitTest2Refs(relCyclicLink1, B_LINK_LIMIT, true);
1100	InitTest2Refs(absBadLink1, B_ENTRY_NOT_FOUND, true);
1101	InitTest2Refs(absBadLink2, B_ENTRY_NOT_FOUND, true);
1102	InitTest2Refs(absBadLink3, B_ENTRY_NOT_FOUND, true);
1103	InitTest2Refs(absBadLink4, B_ENTRY_NOT_FOUND, true);
1104	InitTest2Refs(relBadLink1, B_ENTRY_NOT_FOUND, true);
1105	InitTest2Refs(relBadLink2, B_ENTRY_NOT_FOUND, true);
1106	InitTest2Refs(relBadLink3, B_ENTRY_NOT_FOUND, true);
1107	InitTest2Refs(relBadLink4, B_ENTRY_NOT_FOUND, true);
1108	InitTest2Refs(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1109	InitTest2Refs(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1110	InitTest2Refs(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1111	InitTest2Refs(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1112	InitTest2Refs(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1113	InitTest2Refs(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1114	InitTest2Refs(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1115	InitTest2Refs(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1116	// bad args
1117	NextSubTest();
1118	CPPUNIT_ASSERT( entry.SetTo((const entry_ref*)NULL) == B_BAD_VALUE );
1119	CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
1120	entry.Unset();
1121
1122	// 4. BEntry(const BDirectory *, const char *, bool)
1123	// don't traverse
1124	InitTest2DirPaths(dir1, B_OK);
1125	InitTest2DirPaths(dir2, B_OK);
1126	InitTest2DirPaths(file1, B_OK);
1127	InitTest2DirPaths(subDir1, B_OK);
1128	InitTest2DirPaths(abstractEntry1, B_OK);
1129	InitTest2DirPaths(badEntry1, B_ENTRY_NOT_FOUND);
1130	InitTest2DirPaths(absDirLink1, B_OK);
1131	InitTest2DirPaths(absDirLink2, B_OK);
1132	InitTest2DirPaths(absDirLink3, B_OK);
1133	InitTest2DirPaths(absDirLink4, B_OK);
1134	InitTest2DirPaths(relDirLink1, B_OK);
1135	InitTest2DirPaths(relDirLink2, B_OK);
1136	InitTest2DirPaths(relDirLink3, B_OK);
1137	InitTest2DirPaths(relDirLink4, B_OK);
1138	InitTest2DirPaths(absFileLink1, B_OK);
1139	InitTest2DirPaths(absFileLink2, B_OK);
1140	InitTest2DirPaths(absFileLink3, B_OK);
1141	InitTest2DirPaths(absFileLink4, B_OK);
1142	InitTest2DirPaths(relFileLink1, B_OK);
1143	InitTest2DirPaths(relFileLink2, B_OK);
1144	InitTest2DirPaths(relFileLink3, B_OK);
1145	InitTest2DirPaths(relFileLink4, B_OK);
1146	InitTest2DirPaths(absCyclicLink1, B_OK);
1147	InitTest2DirPaths(relCyclicLink1, B_OK);
1148	InitTest2DirPaths(absBadLink1, B_OK);
1149	InitTest2DirPaths(absBadLink2, B_OK);
1150	InitTest2DirPaths(absBadLink3, B_OK);
1151	InitTest2DirPaths(absBadLink4, B_OK);
1152	InitTest2DirPaths(relBadLink1, B_OK);
1153	InitTest2DirPaths(relBadLink2, B_OK);
1154	InitTest2DirPaths(relBadLink3, B_OK);
1155	InitTest2DirPaths(relBadLink4, B_OK);
1156	InitTest2DirPaths(absVeryBadLink1, B_OK);
1157	InitTest2DirPaths(absVeryBadLink2, B_OK);
1158	InitTest2DirPaths(absVeryBadLink3, B_OK);
1159	InitTest2DirPaths(absVeryBadLink4, B_OK);
1160	InitTest2DirPaths(relVeryBadLink1, B_OK);
1161	InitTest2DirPaths(relVeryBadLink2, B_OK);
1162	InitTest2DirPaths(relVeryBadLink3, B_OK);
1163	InitTest2DirPaths(relVeryBadLink4, B_OK);
1164// R5: returns E2BIG instead of B_NAME_TOO_LONG
1165	InitTest2DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG));
1166// OBOS: Fails, because the implementation concatenates the dir and leaf
1167// 		 name.
1168#if !TEST_OBOS /* !!!POSIX ONLY!!! */
1169	InitTest2DirPaths(tooLongDir16, B_OK, true);
1170#endif
1171	// traverse
1172	InitTest2DirPaths(dir1, B_OK, true);
1173	InitTest2DirPaths(dir2, B_OK, true);
1174	InitTest2DirPaths(file1, B_OK, true);
1175	InitTest2DirPaths(subDir1, B_OK, true);
1176	InitTest2DirPaths(abstractEntry1, B_OK, true);
1177	InitTest2DirPaths(badEntry1, B_ENTRY_NOT_FOUND, true);
1178	InitTest2DirPaths(absDirLink1, B_OK, true);
1179	InitTest2DirPaths(absDirLink2, B_OK, true);
1180	InitTest2DirPaths(absDirLink3, B_OK, true);
1181	InitTest2DirPaths(absDirLink4, B_OK, true);
1182	InitTest2DirPaths(relDirLink1, B_OK, true);
1183	InitTest2DirPaths(relDirLink2, B_OK, true);
1184	InitTest2DirPaths(relDirLink3, B_OK, true);
1185	InitTest2DirPaths(relDirLink4, B_OK, true);
1186	InitTest2DirPaths(absFileLink1, B_OK, true);
1187	InitTest2DirPaths(absFileLink2, B_OK, true);
1188	InitTest2DirPaths(absFileLink3, B_OK, true);
1189	InitTest2DirPaths(absFileLink4, B_OK, true);
1190	InitTest2DirPaths(relFileLink1, B_OK, true);
1191	InitTest2DirPaths(relFileLink2, B_OK, true);
1192	InitTest2DirPaths(relFileLink3, B_OK, true);
1193	InitTest2DirPaths(relFileLink4, B_OK, true);
1194	InitTest2DirPaths(absCyclicLink1, B_LINK_LIMIT, true);
1195	InitTest2DirPaths(relCyclicLink1, B_LINK_LIMIT, true);
1196	InitTest2DirPaths(absBadLink1, B_ENTRY_NOT_FOUND, true);
1197	InitTest2DirPaths(absBadLink2, B_ENTRY_NOT_FOUND, true);
1198	InitTest2DirPaths(absBadLink3, B_ENTRY_NOT_FOUND, true);
1199	InitTest2DirPaths(absBadLink4, B_ENTRY_NOT_FOUND, true);
1200	InitTest2DirPaths(relBadLink1, B_ENTRY_NOT_FOUND, true);
1201	InitTest2DirPaths(relBadLink2, B_ENTRY_NOT_FOUND, true);
1202	InitTest2DirPaths(relBadLink3, B_ENTRY_NOT_FOUND, true);
1203	InitTest2DirPaths(relBadLink4, B_ENTRY_NOT_FOUND, true);
1204	InitTest2DirPaths(absVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1205	InitTest2DirPaths(absVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1206	InitTest2DirPaths(absVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1207	InitTest2DirPaths(absVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1208	InitTest2DirPaths(relVeryBadLink1, B_ENTRY_NOT_FOUND, true);
1209	InitTest2DirPaths(relVeryBadLink2, B_ENTRY_NOT_FOUND, true);
1210	InitTest2DirPaths(relVeryBadLink3, B_ENTRY_NOT_FOUND, true);
1211	InitTest2DirPaths(relVeryBadLink4, B_ENTRY_NOT_FOUND, true);
1212// R5: returns E2BIG instead of B_NAME_TOO_LONG
1213	InitTest2DirPaths(tooLongEntry1, fuzzy_error(E2BIG, B_NAME_TOO_LONG), true);
1214// OBOS: Fails, because the implementation concatenates the dir and leaf
1215// 		 name.
1216#if !TEST_OBOS /* !!!POSIX ONLY!!! */
1217	InitTest2DirPaths(tooLongDir16, B_OK, true);
1218#endif
1219	// special cases (root dir)
1220	NextSubTest();
1221	{
1222		BDirectory dir("/");
1223		CPPUNIT_ASSERT( entry.SetTo(&dir, ".") == B_OK );
1224		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1225		entry.Unset();
1226	}
1227	// special cases (fs root dir)
1228	NextSubTest();
1229	{
1230		BDirectory dir("/");
1231		CPPUNIT_ASSERT( entry.SetTo(&dir, "boot") == B_OK );
1232		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1233		entry.Unset();
1234	}
1235	// NULL path
1236	NextSubTest();
1237	{
1238		BDirectory dir("/");
1239		CPPUNIT_ASSERT( entry.SetTo(&dir, (const char*)NULL) == B_OK );
1240		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1241		entry.Unset();
1242	}
1243	// bad args (NULL dir)
1244// R5: crashs
1245#if !TEST_R5
1246	NextSubTest();
1247	{
1248		chdir("/");
1249		CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, "tmp")
1250						== B_BAD_VALUE );
1251		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
1252		RestoreCWD();
1253		entry.Unset();
1254	}
1255#endif
1256	// strange args (badly initialized dir, absolute path)
1257	NextSubTest();
1258	{
1259		BDirectory dir(badEntry1.cpath);
1260		CPPUNIT_ASSERT( dir.InitCheck() == B_ENTRY_NOT_FOUND );
1261		CPPUNIT_ASSERT( entry.SetTo(&dir, "/tmp") == B_OK );
1262		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
1263	}
1264	// bad args (NULL dir and path)
1265// R5: crashs
1266#if !TEST_R5
1267	NextSubTest();
1268	{
1269		CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, (const char*)NULL)
1270						== B_BAD_VALUE );
1271		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
1272		entry.Unset();
1273	}
1274#endif
1275	// bad args(NULL dir, absolute path)
1276// R5: crashs
1277#if !TEST_R5
1278	NextSubTest();
1279	{
1280		CPPUNIT_ASSERT( entry.SetTo((const BDirectory*)NULL, "/tmp")
1281						== B_BAD_VALUE );
1282		CPPUNIT_ASSERT( entry.InitCheck() == B_BAD_VALUE );
1283		entry.Unset();
1284	}
1285#endif
1286}
1287
1288// SpecialGetCasesTest
1289//
1290// Tests special (mostly error) cases for Exists(), GetPath(), GetName(),
1291// GetParent() and GetRef(). The other cases have already been tested in
1292// InitTest1/2().
1293void
1294EntryTest::SpecialGetCasesTest()
1295{
1296	BEntry entry;
1297	// 1. Exists()
1298	// uninitialized
1299	NextSubTest();
1300	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1301	CPPUNIT_ASSERT( entry.Exists() == false );
1302	entry.Unset();
1303	// badly initialized
1304	NextSubTest();
1305	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1306	CPPUNIT_ASSERT( entry.Exists() == false );
1307	entry.Unset();
1308	// root
1309	NextSubTest();
1310	CPPUNIT_ASSERT( entry.SetTo("/") == B_OK );
1311	CPPUNIT_ASSERT( entry.Exists() == true );
1312	entry.Unset();
1313
1314	// 2. GetPath()
1315	BPath path;
1316	// uninitialized
1317	NextSubTest();
1318	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1319	CPPUNIT_ASSERT( entry.GetPath(&path) == B_NO_INIT );
1320	entry.Unset();
1321	// badly initialized
1322	NextSubTest();
1323	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1324	CPPUNIT_ASSERT( entry.GetPath(&path) == B_NO_INIT );
1325	entry.Unset();
1326	// too long pathname
1327// OBOS: Fails, because the implementation concatenates the dir and leaf
1328// 		 name.
1329#if !TEST_OBOS /* !!!POSIX ONLY!!! */
1330	NextSubTest();
1331	BDirectory dir(tooLongDir16.super->super->cpath);
1332	string entryName = tooLongDir16.super->name + "/" + tooLongDir16.name;
1333	CPPUNIT_ASSERT( entry.SetTo(&dir, entryName.c_str()) == B_OK );
1334	CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
1335	CPPUNIT_ASSERT( path == tooLongDir16.cpath );
1336	entry.Unset();
1337#endif
1338
1339	// 3. GetName()
1340	char name[B_FILE_NAME_LENGTH + 1];
1341	// uninitialized
1342	NextSubTest();
1343	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1344	CPPUNIT_ASSERT( entry.GetName(name) == B_NO_INIT );
1345	entry.Unset();
1346	// badly initialized
1347	NextSubTest();
1348	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1349	CPPUNIT_ASSERT( entry.GetName(name) == B_NO_INIT );
1350	entry.Unset();
1351
1352	// 4. GetParent(BEntry *)
1353	BEntry parentEntry;
1354	// uninitialized
1355	NextSubTest();
1356	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1357	CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_NO_INIT );
1358	entry.Unset();
1359	// badly initialized
1360	NextSubTest();
1361	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1362	CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_NO_INIT );
1363	entry.Unset();
1364	// parent of root dir
1365	NextSubTest();
1366	CPPUNIT_ASSERT( entry.SetTo("/") == B_OK );
1367	CPPUNIT_ASSERT( entry.GetParent(&parentEntry) == B_ENTRY_NOT_FOUND );
1368	entry.Unset();
1369
1370	// 5. GetParent(BDirectory *)
1371	BDirectory parentDir;
1372	// uninitialized
1373	NextSubTest();
1374	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1375	CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_NO_INIT );
1376	entry.Unset();
1377	// badly initialized
1378	NextSubTest();
1379	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1380	CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_NO_INIT );
1381	entry.Unset();
1382	// parent of root dir
1383	NextSubTest();
1384	CPPUNIT_ASSERT( entry.SetTo("/") == B_OK );
1385	CPPUNIT_ASSERT( entry.GetParent(&parentDir) == B_ENTRY_NOT_FOUND );
1386	entry.Unset();
1387
1388	// 6. GetRef()
1389	entry_ref ref, ref2;
1390	// uninitialized
1391	NextSubTest();
1392	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1393	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_NO_INIT );
1394	entry.Unset();
1395	// badly initialized
1396	NextSubTest();
1397	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1398	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_NO_INIT );
1399	entry.Unset();
1400	// ref for root dir
1401	NextSubTest();
1402	CPPUNIT_ASSERT( entry.SetTo("/") == B_OK );
1403	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
1404	entry.Unset();
1405}
1406
1407// RenameTestEntry
1408void
1409EntryTest::RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry,
1410						   string newName, bool existing, bool clobber,
1411						   status_t error, uint32 kind)
1412{
1413	NextSubTest();
1414	BEntry entry;
1415	BDirectory dir;
1416	// get all the names
1417	string pathname = testEntry->path;
1418	string dirname = testEntry->super->path;
1419	string newPathname = newTestEntry->path;
1420//printf("path: `%s', dir: `%s', new name: `%s'\n", pathname.c_str(),
1421//dirname.c_str(), newPathname.c_str());
1422	// create the entries
1423	switch (kind) {
1424		case B_FILE_NODE:
1425			CreateFile(pathname.c_str());
1426			break;
1427		case B_DIRECTORY_NODE:
1428			CreateDir(pathname.c_str());
1429			break;
1430		case B_SYMLINK_NODE:
1431			CreateLink(pathname.c_str(), file1.cpath);
1432			break;
1433	}
1434	if (existing)
1435		CreateFile(newPathname.c_str());
1436	// rename the file
1437	CPPUNIT_ASSERT( entry.SetTo(pathname.c_str()) == B_OK );
1438	CPPUNIT_ASSERT( dir.SetTo(dirname.c_str()) == B_OK );
1439	status_t result = entry.Rename(newName.c_str(), clobber);
1440if (result != error) {
1441printf("`%s'.Rename(`%s', %d): ", pathname.c_str(), newName.c_str(), clobber);
1442printf("error: %lx (%lx)\n", result, error);
1443}
1444	CPPUNIT_ASSERT( result == error );
1445	// check and cleanup
1446	if (error == B_OK) {
1447		switch (kind) {
1448			case B_FILE_NODE:
1449				CPPUNIT_ASSERT( !PingFile(pathname.c_str()) );
1450				CPPUNIT_ASSERT( PingFile(newPathname.c_str()) );
1451				break;
1452			case B_DIRECTORY_NODE:
1453				CPPUNIT_ASSERT( !PingDir(pathname.c_str()) );
1454				CPPUNIT_ASSERT( PingDir(newPathname.c_str()) );
1455				break;
1456			case B_SYMLINK_NODE:
1457				CPPUNIT_ASSERT( !PingLink(pathname.c_str()) );
1458				CPPUNIT_ASSERT( PingLink(newPathname.c_str(), file1.cpath) );
1459				break;
1460		}
1461		RemoveFile(newPathname.c_str());
1462	} else {
1463		switch (kind) {
1464			case B_FILE_NODE:
1465				CPPUNIT_ASSERT( PingFile(pathname.c_str()) );
1466				break;
1467			case B_DIRECTORY_NODE:
1468				CPPUNIT_ASSERT( PingDir(pathname.c_str()) );
1469				break;
1470			case B_SYMLINK_NODE:
1471				CPPUNIT_ASSERT( PingLink(pathname.c_str(), file1.cpath) );
1472				break;
1473		}
1474		if (existing) {
1475			CPPUNIT_ASSERT( PingFile(newPathname.c_str()) );
1476			RemoveFile(newPathname.c_str());
1477		}
1478		RemoveFile(pathname.c_str());
1479	}
1480}
1481
1482// RenameTestEntry
1483void
1484EntryTest::RenameTestEntry(TestEntry *testEntry, TestEntry *newTestEntry,
1485						   bool existing, bool clobber, status_t error,
1486						   uint32 kind)
1487{
1488	// relative path
1489	string relPath = get_shortest_relative_path(testEntry->super,
1490												newTestEntry);
1491	if (relPath.length() > 0) {
1492		RenameTestEntry(testEntry, newTestEntry, relPath, existing,
1493						clobber, error, B_FILE_NODE);
1494	}
1495	// absolute path
1496	RenameTestEntry(testEntry, newTestEntry, newTestEntry->path, existing,
1497					clobber, error, B_FILE_NODE);
1498}
1499
1500// RenameTestFile
1501void
1502EntryTest::RenameTestFile(TestEntry *testEntry, TestEntry *newTestEntry,
1503						  bool existing, bool clobber, status_t error)
1504{
1505	RenameTestEntry(testEntry, newTestEntry, existing, clobber, error,
1506					B_FILE_NODE);
1507}
1508
1509// RenameTestDir
1510void
1511EntryTest::RenameTestDir(TestEntry *testEntry, TestEntry *newTestEntry,
1512						 bool existing, bool clobber, status_t error)
1513{
1514	RenameTestEntry(testEntry, newTestEntry, existing, clobber, error,
1515					B_DIRECTORY_NODE);
1516}
1517
1518// RenameTestLink
1519void
1520EntryTest::RenameTestLink(TestEntry *testEntry, TestEntry *newTestEntry,
1521						  bool existing, bool clobber, status_t error)
1522{
1523	RenameTestEntry(testEntry, newTestEntry, existing, clobber, error,
1524					B_SYMLINK_NODE);
1525}
1526
1527// RenameTest
1528void
1529EntryTest::RenameTest()
1530{
1531	BDirectory dir;
1532	BEntry entry;
1533	// file
1534	// same dir
1535	RenameTestFile(&file2, &file2, false, false, B_FILE_EXISTS);
1536	RenameTestFile(&file2, &file2, false, true, B_NOT_ALLOWED);
1537	RenameTestFile(&file2, &file4, false, false, B_OK);
1538	// different dir
1539	RenameTestFile(&file2, &file3, false, false, B_OK);
1540	// different dir, existing file, clobber
1541	RenameTestFile(&file2, &file3, true, true, B_OK);
1542	// different dir, existing file, no clobber
1543	RenameTestFile(&file2, &file3, true, false, B_FILE_EXISTS);
1544	// dir
1545	// same dir
1546	RenameTestDir(&file2, &file2, false, false, B_FILE_EXISTS);
1547	RenameTestDir(&file2, &file2, false, true, B_NOT_ALLOWED);
1548	RenameTestDir(&file2, &file4, false, false, B_OK);
1549	// different dir
1550	RenameTestDir(&file2, &file3, false, false, B_OK);
1551	// different dir, existing file, clobber
1552	RenameTestDir(&file2, &file3, true, true, B_OK);
1553	// different dir, existing file, no clobber
1554	RenameTestDir(&file2, &file3, true, false, B_FILE_EXISTS);
1555	// link
1556	// same dir
1557	RenameTestLink(&file2, &file2, false, false, B_FILE_EXISTS);
1558	RenameTestLink(&file2, &file2, false, true, B_NOT_ALLOWED);
1559	RenameTestLink(&file2, &file4, false, false, B_OK);
1560	// different dir
1561	RenameTestLink(&file2, &file3, false, false, B_OK);
1562	// different dir, existing file, clobber
1563	RenameTestLink(&file2, &file3, true, true, B_OK);
1564	// different dir, existing file, no clobber
1565	RenameTestLink(&file2, &file3, true, false, B_FILE_EXISTS);
1566
1567	// try to clobber a non-empty directory
1568	NextSubTest();
1569	CreateFile(file3.cpath);
1570	CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK );
1571	CPPUNIT_ASSERT( entry.Rename(dir1.cpath, true) == B_DIRECTORY_NOT_EMPTY );
1572	CPPUNIT_ASSERT( PingDir(dir1.cpath) );
1573	CPPUNIT_ASSERT( PingFile(file3.cpath, &entry) );
1574	RemoveFile(file3.cpath);
1575	entry.Unset();
1576	dir.Unset();
1577	// clobber an empty directory
1578	NextSubTest();
1579	CreateFile(file3.cpath);
1580	CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK );
1581	CPPUNIT_ASSERT( entry.Rename(subDir1.cpath, true) == B_OK );
1582	CPPUNIT_ASSERT( PingFile(subDir1.cpath, &entry) );
1583	CPPUNIT_ASSERT( !PingFile(file3.cpath) );
1584	RemoveFile(subDir1.cpath);
1585	entry.Unset();
1586	dir.Unset();
1587	// abstract entry
1588	NextSubTest();
1589	CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK );
1590	CPPUNIT_ASSERT( entry.Rename(file4.cname) == B_ENTRY_NOT_FOUND );
1591	entry.Unset();
1592	dir.Unset();
1593	// uninitialized entry
1594	NextSubTest();
1595	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1596	CPPUNIT_ASSERT( entry.Rename(file4.cpath) == B_NO_INIT );
1597	entry.Unset();
1598	dir.Unset();
1599	// badly initialized entry
1600	NextSubTest();
1601	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1602	CPPUNIT_ASSERT( entry.Rename(file4.cpath) == B_NO_INIT );
1603	entry.Unset();
1604	dir.Unset();
1605	// Verify attempts to rename root
1606	NextSubTest();
1607	BEntry root("/");
1608	CPPUNIT_ASSERT( root.Rename("/", false) == B_FILE_EXISTS );
1609	CPPUNIT_ASSERT( root.Rename("/", true) == B_NOT_ALLOWED );
1610	// Verify abstract entries
1611	NextSubTest();
1612	BEntry abstract(abstractEntry1.cpath);
1613	CPPUNIT_ASSERT( abstract.InitCheck() == B_OK );
1614	CPPUNIT_ASSERT( !abstract.Exists() );
1615	CPPUNIT_ASSERT( abstract.Rename("/boot/DoesntMatter") == B_ENTRY_NOT_FOUND );
1616	CPPUNIT_ASSERT( abstract.Rename("/boot/DontMatter", true) == B_ENTRY_NOT_FOUND );
1617	CPPUNIT_ASSERT( abstract.Rename("/DoesntMatter") == B_CROSS_DEVICE_LINK );
1618	CPPUNIT_ASSERT( abstract.Rename("/DontMatter", true) == B_CROSS_DEVICE_LINK );
1619	// bad args
1620	NextSubTest();
1621	CPPUNIT_ASSERT( entry.SetTo(file1.cpath) == B_OK );
1622	CPPUNIT_ASSERT( equals(entry.Rename(NULL, false), B_FILE_EXISTS,
1623						   B_BAD_VALUE) );
1624	CPPUNIT_ASSERT( equals(entry.Rename(NULL, true), B_NOT_ALLOWED,
1625						   B_BAD_VALUE) );
1626}
1627
1628// MoveToTestEntry
1629void
1630EntryTest::MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir,
1631						   string newName, bool existing, bool clobber,
1632						   status_t error, uint32 kind)
1633{
1634	NextSubTest();
1635	BEntry entry;
1636	BDirectory dir;
1637	// get all the names
1638	string pathname = testEntry->path;
1639	string dirname = testDir->path;
1640	string newPathname = dirname + "/";
1641	if (newName.length() == 0)
1642		newPathname += testEntry->name;
1643	else {
1644		// check, if the new path is absolute
1645		if (newName.find("/") == 0)
1646			newPathname = newName;
1647		else
1648			newPathname += newName;
1649	}
1650//printf("path: `%s', dir: `%s', new name: `%s'\n", pathname.c_str(),
1651//dirname.c_str(), newPathname.c_str());
1652	// create the entries
1653	switch (kind) {
1654		case B_FILE_NODE:
1655			CreateFile(pathname.c_str());
1656			break;
1657		case B_DIRECTORY_NODE:
1658			CreateDir(pathname.c_str());
1659			break;
1660		case B_SYMLINK_NODE:
1661			CreateLink(pathname.c_str(), file1.cpath);
1662			break;
1663	}
1664	if (existing)
1665		CreateFile(newPathname.c_str());
1666	// move the file
1667	CPPUNIT_ASSERT( entry.SetTo(pathname.c_str()) == B_OK );
1668	CPPUNIT_ASSERT( dir.SetTo(dirname.c_str()) == B_OK );
1669	if (newName.length() == 0) {
1670		status_t result = entry.MoveTo(&dir, NULL, clobber);
1671if (result != error) {
1672printf("`%s'.MoveTo(`%s', NULL, %d): ", pathname.c_str(), dirname.c_str(), clobber);
1673printf("error: %lx (%lx)\n", result, error);
1674}
1675		CPPUNIT_ASSERT( result == error );
1676	} else {
1677		status_t result = entry.MoveTo(&dir, newName.c_str(), clobber);
1678if (result != error) {
1679printf("`%s'.MoveTo(`%s', `%s', %d): ", pathname.c_str(), newName.c_str(), dirname.c_str(), clobber);
1680printf("error: %lx (%lx)\n", result, error);
1681}
1682		CPPUNIT_ASSERT( result == error );
1683	}
1684	// check and cleanup
1685	if (error == B_OK) {
1686		switch (kind) {
1687			case B_FILE_NODE:
1688				CPPUNIT_ASSERT( !PingFile(pathname.c_str()) );
1689				CPPUNIT_ASSERT( PingFile(newPathname.c_str()) );
1690				break;
1691			case B_DIRECTORY_NODE:
1692				CPPUNIT_ASSERT( !PingDir(pathname.c_str()) );
1693				CPPUNIT_ASSERT( PingDir(newPathname.c_str()) );
1694				break;
1695			case B_SYMLINK_NODE:
1696				CPPUNIT_ASSERT( !PingLink(pathname.c_str()) );
1697				CPPUNIT_ASSERT( PingLink(newPathname.c_str(), file1.cpath) );
1698				break;
1699		}
1700		RemoveFile(newPathname.c_str());
1701	} else {
1702		switch (kind) {
1703			case B_FILE_NODE:
1704				CPPUNIT_ASSERT( PingFile(pathname.c_str()) );
1705				break;
1706			case B_DIRECTORY_NODE:
1707				CPPUNIT_ASSERT( PingDir(pathname.c_str()) );
1708				break;
1709			case B_SYMLINK_NODE:
1710				CPPUNIT_ASSERT( PingLink(pathname.c_str(), file1.cpath) );
1711				break;
1712		}
1713		if (existing) {
1714			CPPUNIT_ASSERT( PingFile(newPathname.c_str()) );
1715			RemoveFile(newPathname.c_str());
1716		}
1717		RemoveFile(pathname.c_str());
1718	}
1719}
1720
1721// MoveToTestEntry
1722void
1723EntryTest::MoveToTestEntry(TestEntry *testEntry, TestEntry *testDir,
1724						   TestEntry *newTestEntry, bool existing,
1725						   bool clobber, status_t error, uint32 kind)
1726{
1727	if (newTestEntry) {
1728		// Here is the right place to play a little bit with the dir and path
1729		// arguments. At this time we only pass the leaf name and the
1730		// absolute path name.
1731		MoveToTestEntry(testEntry, testDir, newTestEntry->name, existing,
1732						clobber, error, B_FILE_NODE);
1733		MoveToTestEntry(testEntry, &subDir1, newTestEntry->path, existing,
1734						clobber, error, B_FILE_NODE);
1735	} else {
1736		MoveToTestEntry(testEntry, testDir, "", existing, clobber, error,
1737						B_FILE_NODE);
1738	}
1739}
1740
1741// MoveToTestFile
1742void
1743EntryTest::MoveToTestFile(TestEntry *testEntry, TestEntry *testDir,
1744						  TestEntry *newTestEntry, bool existing, bool clobber,
1745						  status_t error)
1746{
1747	MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error,
1748					B_FILE_NODE);
1749}
1750
1751// MoveToTestDir
1752void
1753EntryTest::MoveToTestDir(TestEntry *testEntry, TestEntry *testDir,
1754						 TestEntry *newTestEntry, bool existing, bool clobber,
1755						 status_t error)
1756{
1757	MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error,
1758					B_DIRECTORY_NODE);
1759}
1760
1761// MoveToTestLink
1762void
1763EntryTest::MoveToTestLink(TestEntry *testEntry, TestEntry *testDir,
1764						  TestEntry *newTestEntry, bool existing, bool clobber,
1765						  status_t error)
1766{
1767	MoveToTestEntry(testEntry, testDir, newTestEntry, existing, clobber, error,
1768					B_SYMLINK_NODE);
1769}
1770
1771// MoveToTest
1772void
1773EntryTest::MoveToTest()
1774{
1775	BDirectory dir;
1776	BEntry entry;
1777	// 1. NULL path
1778	// file
1779	// same dir
1780	MoveToTestFile(&file2, file2.super, NULL, false, false, B_FILE_EXISTS);
1781	MoveToTestFile(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED);
1782	// different dir
1783	MoveToTestFile(&file2, &dir2, NULL, false, false, B_OK);
1784	// different dir, existing file, clobber
1785	MoveToTestFile(&file2, &dir2, NULL, true, true, B_OK);
1786	// different dir, existing file, no clobber
1787	MoveToTestFile(&file2, &dir2, NULL, true, false, B_FILE_EXISTS);
1788	// dir
1789	// same dir
1790	MoveToTestDir(&file2, file2.super, NULL, false, false, B_FILE_EXISTS);
1791	MoveToTestDir(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED);
1792	// different dir
1793	MoveToTestDir(&file2, &dir2, NULL, false, false, B_OK);
1794	// different dir, existing file, clobber
1795	MoveToTestDir(&file2, &dir2, NULL, true, true, B_OK);
1796	// different dir, existing file, no clobber
1797	MoveToTestDir(&file2, &dir2, NULL, true, false, B_FILE_EXISTS);
1798	// link
1799	// same dir
1800	MoveToTestLink(&file2, file2.super, NULL, false, false, B_FILE_EXISTS);
1801	MoveToTestLink(&file2, file2.super, NULL, false, true, B_NOT_ALLOWED);
1802	// different dir
1803	MoveToTestLink(&file2, &dir2, NULL, false, false, B_OK);
1804	// different dir, existing file, clobber
1805	MoveToTestLink(&file2, &dir2, NULL, true, true, B_OK);
1806	// different dir, existing file, no clobber
1807	MoveToTestLink(&file2, &dir2, NULL, true, false, B_FILE_EXISTS);
1808
1809	// 2. non NULL path
1810	// file
1811	// same dir
1812	MoveToTestFile(&file2, file2.super, &file2, false, false,
1813				   B_FILE_EXISTS);
1814	MoveToTestFile(&file2, file2.super, &file2, false, true,
1815				   B_NOT_ALLOWED);
1816	MoveToTestFile(&file2, file2.super, &file3, false, false, B_OK);
1817	// different dir
1818	MoveToTestFile(&file2, &dir2, &file3, false, false, B_OK);
1819	// different dir, existing file, clobber
1820	MoveToTestFile(&file2, &dir2, &file3, true, true, B_OK);
1821	// different dir, existing file, no clobber
1822	MoveToTestFile(&file2, &dir2, &file3, true, false, B_FILE_EXISTS);
1823	// dir
1824	// same dir
1825	MoveToTestDir(&file2, file2.super, &file2, false, false,
1826				  B_FILE_EXISTS);
1827	MoveToTestDir(&file2, file2.super, &file2, false, true,
1828				  B_NOT_ALLOWED);
1829	MoveToTestDir(&file2, file2.super, &file3, false, false, B_OK);
1830	// different dir
1831	MoveToTestDir(&file2, &dir2, &file3, false, false, B_OK);
1832	// different dir, existing file, clobber
1833	MoveToTestDir(&file2, &dir2, &file3, true, true, B_OK);
1834	// different dir, existing file, no clobber
1835	MoveToTestDir(&file2, &dir2, &file3, true, false, B_FILE_EXISTS);
1836	// link
1837	// same dir
1838	MoveToTestLink(&file2, file2.super, &file2, false, false,
1839				   B_FILE_EXISTS);
1840	MoveToTestLink(&file2, file2.super, &file2, false, true,
1841				   B_NOT_ALLOWED);
1842	MoveToTestLink(&file2, file2.super, &file3, false, false, B_OK);
1843	// different dir
1844	MoveToTestLink(&file2, &dir2, &file3, false, false, B_OK);
1845	// different dir, existing file, clobber
1846	MoveToTestLink(&file2, &dir2, &file3, true, true, B_OK);
1847	// different dir, existing file, no clobber
1848	MoveToTestLink(&file2, &dir2, &file3, true, false, B_FILE_EXISTS);
1849
1850	// try to clobber a non-empty directory
1851	CreateFile(file3.cpath);
1852	CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK );
1853	CPPUNIT_ASSERT( dir.SetTo(dir1.super->cpath) == B_OK );
1854	CPPUNIT_ASSERT( entry.MoveTo(&dir, dir1.cname, true)
1855					== B_DIRECTORY_NOT_EMPTY );
1856	CPPUNIT_ASSERT( PingDir(dir1.cpath) );
1857	CPPUNIT_ASSERT( PingFile(file3.cpath, &entry) );
1858	RemoveFile(file3.cpath);
1859	entry.Unset();
1860	dir.Unset();
1861	// clobber an empty directory
1862	CreateFile(file3.cpath);
1863	CPPUNIT_ASSERT( entry.SetTo(file3.cpath) == B_OK );
1864	CPPUNIT_ASSERT( dir.SetTo(subDir1.super->cpath) == B_OK );
1865	CPPUNIT_ASSERT( entry.MoveTo(&dir, subDir1.cname, true) == B_OK );
1866	CPPUNIT_ASSERT( PingFile(subDir1.cpath, &entry) );
1867	CPPUNIT_ASSERT( !PingFile(file3.cpath) );
1868	RemoveFile(subDir1.cpath);
1869	entry.Unset();
1870	dir.Unset();
1871	// abstract entry
1872	CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK );
1873	CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK );
1874	CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_ENTRY_NOT_FOUND );
1875	entry.Unset();
1876	dir.Unset();
1877	// uninitialized entry
1878	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1879	CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK );
1880	CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_NO_INIT );
1881	entry.Unset();
1882	dir.Unset();
1883	// badly initialized entry
1884	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1885	CPPUNIT_ASSERT( dir.SetTo(dir2.cpath) == B_OK );
1886	CPPUNIT_ASSERT( entry.MoveTo(&dir) == B_NO_INIT );
1887	entry.Unset();
1888	dir.Unset();
1889	// bad args (NULL dir)
1890// R5: crashs
1891#if !TEST_R5
1892	CreateFile(file2.cpath);
1893	CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK );
1894	CPPUNIT_ASSERT( entry.MoveTo(NULL, file3.cpath) == B_BAD_VALUE );
1895	RemoveFile(file3.cpath);
1896	entry.Unset();
1897	dir.Unset();
1898#endif
1899	// uninitialized dir, absolute path
1900	CreateFile(file2.cpath);
1901	CPPUNIT_ASSERT( entry.SetTo(file2.cpath) == B_OK );
1902	CPPUNIT_ASSERT( dir.InitCheck() == B_NO_INIT );
1903	CPPUNIT_ASSERT( entry.MoveTo(&dir, file3.cpath) == B_BAD_VALUE );
1904	RemoveFile(file3.cpath);
1905	entry.Unset();
1906	dir.Unset();
1907}
1908
1909// RemoveTest
1910void
1911EntryTest::RemoveTest()
1912{
1913	BEntry entry;
1914	// file
1915	NextSubTest();
1916	CPPUNIT_ASSERT( entry.SetTo(file1.cpath) == B_OK );
1917	CPPUNIT_ASSERT( entry.Remove() == B_OK );
1918	CPPUNIT_ASSERT( !PingFile(file1.cpath) );
1919	entry.Unset();
1920	// symlink
1921	NextSubTest();
1922	CPPUNIT_ASSERT( entry.SetTo(absFileLink1.cpath) == B_OK );
1923	CPPUNIT_ASSERT( entry.Remove() == B_OK );
1924	CPPUNIT_ASSERT( !PingLink(absFileLink1.cpath) );
1925	entry.Unset();
1926	// empty dir
1927	NextSubTest();
1928	CPPUNIT_ASSERT( entry.SetTo(subDir1.cpath) == B_OK );
1929	CPPUNIT_ASSERT( entry.Remove() == B_OK );
1930	CPPUNIT_ASSERT( !PingDir(subDir1.cpath) );
1931	entry.Unset();
1932	// non-empty dir
1933	NextSubTest();
1934	CPPUNIT_ASSERT( entry.SetTo(dir1.cpath) == B_OK );
1935	CPPUNIT_ASSERT( entry.Remove() == B_DIRECTORY_NOT_EMPTY );
1936	CPPUNIT_ASSERT( PingDir(dir1.cpath) );
1937	entry.Unset();
1938	// abstract entry
1939	NextSubTest();
1940	CPPUNIT_ASSERT( entry.SetTo(abstractEntry1.cpath) == B_OK );
1941	CPPUNIT_ASSERT( entry.Remove() == B_ENTRY_NOT_FOUND );
1942	entry.Unset();
1943	// uninitialized
1944	NextSubTest();
1945	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
1946	CPPUNIT_ASSERT( entry.Remove() == B_NO_INIT );
1947	entry.Unset();
1948	// badly initialized
1949	NextSubTest();
1950	CPPUNIT_ASSERT( entry.SetTo(badEntry1.cpath) == B_ENTRY_NOT_FOUND );
1951	CPPUNIT_ASSERT( entry.Remove() == B_NO_INIT );
1952	entry.Unset();
1953}
1954
1955// compareEntries
1956static
1957void
1958compareEntries(const BEntry &entry, const BEntry &entry2,
1959			   const TestEntry *testEntry, const TestEntry *testEntry2,
1960			   bool traversed, bool traversed2)
1961{
1962	if (!testEntry->isBad() && !testEntry2->isBad()
1963		&& (!traversed && testEntry->isConcrete())
1964		&& (!traversed2 && testEntry2->isConcrete())) {
1965//printf("compare: `%s', `%s'\n", testEntry->cpath, testEntry2->cpath);
1966//printf("InitCheck(): %x, %x\n", entry.InitCheck(), entry2.InitCheck());
1967		CPPUNIT_ASSERT( (entry == entry2) == (testEntry == testEntry2) );
1968		CPPUNIT_ASSERT( (entry == entry2) == (testEntry2 == testEntry) );
1969		CPPUNIT_ASSERT( (entry != entry2) == (testEntry != testEntry2) );
1970		CPPUNIT_ASSERT( (entry != entry2) == (testEntry2 != testEntry) );
1971	}
1972}
1973
1974// ComparisonTest
1975void
1976EntryTest::ComparisonTest()
1977{
1978	// uninitialized
1979	NextSubTest();
1980	{
1981		BEntry entry;
1982		BEntry entry2;
1983		CPPUNIT_ASSERT( entry == entry2 );
1984		CPPUNIT_ASSERT( entry2 == entry );
1985		CPPUNIT_ASSERT( !(entry != entry2) );
1986		CPPUNIT_ASSERT( !(entry2 != entry) );
1987	}
1988	// initialized + uninitialized
1989	NextSubTest();
1990	{
1991		BEntry entry(file1.cpath);
1992		BEntry entry2;
1993		CPPUNIT_ASSERT( !(entry == entry2) );
1994		CPPUNIT_ASSERT( !(entry2 == entry) );
1995		CPPUNIT_ASSERT( entry != entry2 );
1996		CPPUNIT_ASSERT( entry2 != entry );
1997	}
1998	{
1999		BEntry entry;
2000		BEntry entry2(file1.cpath);
2001		CPPUNIT_ASSERT( !(entry == entry2) );
2002		CPPUNIT_ASSERT( !(entry2 == entry) );
2003		CPPUNIT_ASSERT( entry != entry2 );
2004		CPPUNIT_ASSERT( entry2 != entry );
2005	}
2006	// initialized
2007	TestEntry *testEntries[] = {
2008		&dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1,
2009		&absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4,
2010		&relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4,
2011		&absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4,
2012		&relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4,
2013		&absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4,
2014		&relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4,
2015		&absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4,
2016		&relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4
2017	};
2018	int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*);
2019	for (int32 i = 0; i < testEntryCount; i++) {
2020		NextSubTest();
2021		TestEntry *testEntry = testEntries[i];
2022		TestEntry *traversedTestEntry = resolve_link(testEntry);
2023		BEntry entry(testEntry->cpath);
2024		BEntry traversedEntry(testEntry->cpath, true);
2025		for (int32 k = 0; k < testEntryCount; k++) {
2026			TestEntry *testEntry2 = testEntries[k];
2027			TestEntry *traversedTestEntry2 = resolve_link(testEntry2);
2028			BEntry entry2(testEntry2->cpath);
2029			BEntry traversedEntry2(testEntry2->cpath, true);
2030			compareEntries(entry, entry2, testEntry, testEntry2, false, false);
2031			compareEntries(traversedEntry, entry2,
2032						   traversedTestEntry, testEntry2, true, false);
2033			compareEntries(entry, traversedEntry2,
2034						   testEntry, traversedTestEntry2, false, true);
2035			compareEntries(traversedEntry, traversedEntry2,
2036						   traversedTestEntry, traversedTestEntry2,
2037						   true, true);
2038		}
2039	}
2040}
2041
2042// AssignmentTest
2043void
2044EntryTest::AssignmentTest()
2045{
2046	// 1. copy constructor
2047	// uninitialized
2048	NextSubTest();
2049	{
2050		BEntry entry;
2051		CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
2052		BEntry entry2(entry);
2053// R5: returns B_BAD_VALUE instead of B_NO_INIT
2054		CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) );
2055		CPPUNIT_ASSERT( entry == entry2 );
2056	}
2057	// initialized
2058	TestEntry *testEntries[] = {
2059		&dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1,
2060		&absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4,
2061		&relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4,
2062		&absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4,
2063		&relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4,
2064		&absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4,
2065		&relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4,
2066		&absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4,
2067		&relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4
2068	};
2069	int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*);
2070	for (int32 i = 0; i < testEntryCount; i++) {
2071		NextSubTest();
2072		TestEntry *testEntry = testEntries[i];
2073		BEntry entry(testEntry->cpath);
2074		BEntry entry2(entry);
2075		CPPUNIT_ASSERT( entry == entry2 );
2076		CPPUNIT_ASSERT( entry2 == entry );
2077		CPPUNIT_ASSERT( !(entry != entry2) );
2078		CPPUNIT_ASSERT( !(entry2 != entry) );
2079	}
2080
2081	// 2. assignment operator
2082	// uninitialized
2083	NextSubTest();
2084	{
2085		BEntry entry;
2086		CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
2087		BEntry entry2;
2088		entry2 = entry;
2089// R5: returns B_BAD_VALUE instead of B_NO_INIT
2090		CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) );
2091		CPPUNIT_ASSERT( entry == entry2 );
2092	}
2093	NextSubTest();
2094	{
2095		BEntry entry;
2096		CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
2097		BEntry entry2(file1.cpath);
2098		entry2 = entry;
2099// R5: returns B_BAD_VALUE instead of B_NO_INIT
2100		CPPUNIT_ASSERT( equals(entry2.InitCheck(), B_BAD_VALUE, B_NO_INIT) );
2101		CPPUNIT_ASSERT( entry == entry2 );
2102	}
2103	// initialized
2104	for (int32 i = 0; i < testEntryCount; i++) {
2105		NextSubTest();
2106		TestEntry *testEntry = testEntries[i];
2107		BEntry entry(testEntry->cpath);
2108		BEntry entry2;
2109		BEntry entry3(file1.cpath);
2110		entry2 = entry;
2111		entry3 = entry;
2112		CPPUNIT_ASSERT( entry == entry2 );
2113		CPPUNIT_ASSERT( entry2 == entry );
2114		CPPUNIT_ASSERT( !(entry != entry2) );
2115		CPPUNIT_ASSERT( !(entry2 != entry) );
2116		CPPUNIT_ASSERT( entry == entry3 );
2117		CPPUNIT_ASSERT( entry3 == entry );
2118		CPPUNIT_ASSERT( !(entry != entry3) );
2119		CPPUNIT_ASSERT( !(entry3 != entry) );
2120	}
2121}
2122
2123// get_entry_ref_for_entry
2124static
2125status_t
2126get_entry_ref_for_entry(const char *dir, const char *leaf, entry_ref *ref)
2127{
2128	status_t error = (dir && leaf ? B_OK : B_BAD_VALUE);
2129	struct stat dirStat;
2130	if (lstat(dir, &dirStat) == 0) {
2131		ref->device = dirStat.st_dev;
2132		ref->directory = dirStat.st_ino;
2133		ref->set_name(leaf);
2134	} else
2135		error = errno;
2136	return error;
2137}
2138
2139// entry_ref >
2140bool
2141operator>(const entry_ref & a, const entry_ref & b)
2142{
2143	return (a.device > b.device
2144		|| (a.device == b.device
2145			&& (a.directory > b.directory
2146			|| (a.directory == b.directory
2147				&& (a.name != NULL && b.name == NULL
2148				|| (a.name != NULL && b.name != NULL
2149					&& strcmp(a.name, b.name) > 0))))));
2150}
2151
2152// CFunctionsTest
2153void
2154EntryTest::CFunctionsTest()
2155{
2156	// get_ref_for_path(), <
2157	TestEntry *testEntries[] = {
2158		&dir1, &dir2, &file1, &subDir1, &abstractEntry1, &badEntry1,
2159		&absDirLink1, &absDirLink2, &absDirLink3, &absDirLink4,
2160		&relDirLink1, &relDirLink2, &relDirLink3, &relDirLink4,
2161		&absFileLink1, &absFileLink2, &absFileLink3, &absFileLink4,
2162		&relFileLink1, &relFileLink2, &relFileLink3, &relFileLink4,
2163		&absBadLink1, &absBadLink2, &absBadLink3, &absBadLink4,
2164		&relBadLink1, &relBadLink2, &relBadLink3, &relBadLink4,
2165		&absVeryBadLink1, &absVeryBadLink2, &absVeryBadLink3, &absVeryBadLink4,
2166		&relVeryBadLink1, &relVeryBadLink2, &relVeryBadLink3, &relVeryBadLink4
2167	};
2168	int32 testEntryCount = sizeof(testEntries) / sizeof(TestEntry*);
2169	for (int32 i = 0; i < testEntryCount; i++) {
2170		NextSubTest();
2171		TestEntry *testEntry = testEntries[i];
2172		const char *path = testEntry->cpath;
2173		entry_ref ref;
2174		if (testEntry->isBad())
2175			CPPUNIT_ASSERT( get_ref_for_path(path, &ref) == B_ENTRY_NOT_FOUND );
2176		else {
2177			CPPUNIT_ASSERT( get_ref_for_path(path, &ref) == B_OK );
2178			const entry_ref &testEntryRef = testEntry->get_ref();
2179			CPPUNIT_ASSERT( testEntryRef.device == ref.device );
2180			CPPUNIT_ASSERT( testEntryRef.directory == ref.directory );
2181			CPPUNIT_ASSERT( strcmp(testEntryRef.name, ref.name) == 0 );
2182			CPPUNIT_ASSERT( testEntryRef == ref );
2183			CPPUNIT_ASSERT( !(testEntryRef != ref) );
2184			CPPUNIT_ASSERT(  ref == testEntryRef );
2185			CPPUNIT_ASSERT(  !(ref != testEntryRef) );
2186			for (int32 k = 0; k < testEntryCount; k++) {
2187				TestEntry *testEntry2 = testEntries[k];
2188				const char *path2 = testEntry2->cpath;
2189				entry_ref ref2;
2190				if (!testEntry2->isBad()) {
2191					CPPUNIT_ASSERT( get_ref_for_path(path2, &ref2) == B_OK );
2192					int cmp = 0;
2193					if (ref > ref2)
2194						cmp = 1;
2195					else if (ref2 > ref)
2196						cmp = -1;
2197					CPPUNIT_ASSERT(  (ref == ref2) == (cmp == 0) );
2198					CPPUNIT_ASSERT(  (ref2 == ref) == (cmp == 0) );
2199					CPPUNIT_ASSERT(  (ref != ref2) == (cmp != 0) );
2200					CPPUNIT_ASSERT(  (ref2 != ref) == (cmp != 0) );
2201					CPPUNIT_ASSERT(  (ref < ref2) == (cmp < 0) );
2202					CPPUNIT_ASSERT(  (ref2 < ref) == (cmp > 0) );
2203				}
2204			}
2205		}
2206	}
2207	// root dir
2208	NextSubTest();
2209	entry_ref ref, ref2;
2210	CPPUNIT_ASSERT( get_ref_for_path("/", &ref) == B_OK );
2211	CPPUNIT_ASSERT( get_entry_ref_for_entry("/", ".", &ref2) == B_OK );
2212	CPPUNIT_ASSERT( ref.device == ref2.device );
2213	CPPUNIT_ASSERT( ref.directory == ref2.directory );
2214	CPPUNIT_ASSERT( strcmp(ref.name, ref2.name) == 0 );
2215	CPPUNIT_ASSERT(  ref == ref2 );
2216	// fs root dir
2217	NextSubTest();
2218	CPPUNIT_ASSERT( get_ref_for_path("/boot", &ref) == B_OK );
2219	CPPUNIT_ASSERT( get_entry_ref_for_entry("/", "boot", &ref2) == B_OK );
2220	CPPUNIT_ASSERT( ref.device == ref2.device );
2221	CPPUNIT_ASSERT( ref.directory == ref2.directory );
2222	CPPUNIT_ASSERT( strcmp(ref.name, ref2.name) == 0 );
2223	CPPUNIT_ASSERT(  ref == ref2 );
2224	// uninitialized
2225	NextSubTest();
2226	ref = entry_ref();
2227	ref2 = entry_ref();
2228	CPPUNIT_ASSERT(  ref == ref2 );
2229	CPPUNIT_ASSERT(  !(ref != ref2) );
2230	CPPUNIT_ASSERT(  !(ref < ref2) );
2231	CPPUNIT_ASSERT(  !(ref2 < ref) );
2232	CPPUNIT_ASSERT( get_entry_ref_for_entry("/", ".", &ref2) == B_OK );
2233	CPPUNIT_ASSERT(  !(ref == ref2) );
2234	CPPUNIT_ASSERT(  ref != ref2 );
2235	CPPUNIT_ASSERT(  ref < ref2 );
2236	CPPUNIT_ASSERT(  !(ref2 < ref) );
2237}
2238
2239
2240// isHarmlessPathname
2241bool
2242isHarmlessPathname(const char *path)
2243{
2244	bool result = false;
2245	if (path) {
2246		const char *harmlessDir = "/tmp/";
2247		result = (string(path).find(harmlessDir) == 0);
2248	}
2249if (!result)
2250printf("WARNING: `%s' is not a harmless pathname.\n", path);
2251	return result;
2252}
2253
2254// CreateLink
2255void
2256EntryTest::CreateLink(const char *link, const char *target)
2257{
2258	if (link && target && isHarmlessPathname(link)) {
2259		execCommand(string("rm -rf ") + link
2260					+ " ; ln -s " + target + " " + link);
2261	}
2262}
2263
2264// CreateFile
2265void
2266EntryTest::CreateFile(const char *file)
2267{
2268	if (file && isHarmlessPathname(file))
2269		execCommand(string("rm -rf ") + file + " ; touch " + file);
2270}
2271
2272// CreateDir
2273void
2274EntryTest::CreateDir(const char *dir)
2275{
2276	if (dir  && isHarmlessPathname(dir))
2277		execCommand(string("rm -rf ") + dir + " ; mkdir " + dir);
2278}
2279
2280// RemoveFile
2281void
2282EntryTest::RemoveFile(const char *file)
2283{
2284	if (file && isHarmlessPathname(file))
2285		execCommand(string("rm -rf ") + file);
2286}
2287
2288// PingFile
2289bool
2290EntryTest::PingFile(const char *path, BEntry *entry)
2291{
2292	bool result = false;
2293	// check existence and type
2294	struct stat st;
2295	if (lstat(path, &st) == 0)
2296		result = (S_ISREG(st.st_mode));
2297	// check entry
2298	if (result && entry) {
2299		BPath entryPath;
2300		result = (entry->GetPath(&entryPath) == B_OK && entryPath == path);
2301	}
2302	return result;
2303}
2304
2305// PingDir
2306bool
2307EntryTest::PingDir(const char *path, BEntry *entry)
2308{
2309	bool result = false;
2310	// check existence and type
2311	struct stat st;
2312	if (lstat(path, &st) == 0)
2313		result = (S_ISDIR(st.st_mode));
2314	// check entry
2315	if (result && entry) {
2316		BPath entryPath;
2317		result = (entry->GetPath(&entryPath) == B_OK && entryPath == path);
2318	}
2319	return result;
2320}
2321
2322// PingLink
2323bool
2324EntryTest::PingLink(const char *path, const char *target, BEntry *entry)
2325{
2326	bool result = false;
2327	// check existence and type
2328	struct stat st;
2329	if (lstat(path, &st) == 0)
2330		result = (S_ISLNK(st.st_mode));
2331	// check target
2332	if (result && target) {
2333		char linkTarget[B_PATH_NAME_LENGTH + 1];
2334		ssize_t size = readlink(path, linkTarget, B_PATH_NAME_LENGTH);
2335		result = (size >= 0);
2336		if (result) {
2337			linkTarget[size] = 0;
2338			result = (string(linkTarget) == target);
2339		}
2340	}
2341	// check entry
2342	if (result && entry) {
2343		BPath entryPath;
2344		result = (entry->GetPath(&entryPath) == B_OK && entryPath == path);
2345	}
2346	return result;
2347}
2348
2349// MiscTest
2350void
2351EntryTest::MiscTest()
2352{
2353	BNode node(file1.cpath);
2354	BEntry entry(file1.cpath);
2355
2356	CPPUNIT_ASSERT(node.Lock() == B_OK);
2357	CPPUNIT_ASSERT( entry.Exists() );
2358}
2359
2360
2361
2362// directory name for too long path name (70 characters)
2363static const char *tooLongDirname =
2364	"1234567890123456789012345678901234567890123456789012345678901234567890";
2365
2366// too long entry name (257 characters)
2367static const char *tooLongEntryname =
2368	"1234567890123456789012345678901234567890123456789012345678901234567890"
2369	"1234567890123456789012345678901234567890123456789012345678901234567890"
2370	"1234567890123456789012345678901234567890123456789012345678901234567890"
2371	"12345678901234567890123456789012345678901234567";
2372
2373
2374static void
2375init_entry_test()
2376{
2377	// root dir for testing
2378	testDir.initDir(badTestEntry, "testDir");
2379	testDir.initPath((string("/tmp/") + testDir.name).c_str());
2380	allTestEntries.pop_back();
2381	// other entries
2382	dir1.initDir(testDir, "dir1");
2383	dir2.initDir(testDir, "dir2");
2384	file1.initFile(dir1, "file1");
2385	file2.init(dir1, "file2", ABSTRACT_ENTRY);
2386	file3.init(dir2, "file3", ABSTRACT_ENTRY);
2387	file4.init(dir1, "file4", ABSTRACT_ENTRY);
2388	subDir1.initDir(dir1, "subDir1");
2389	abstractEntry1.init(dir1, "abstractEntry1", ABSTRACT_ENTRY);
2390	badEntry1.init(abstractEntry1, "badEntry1", BAD_ENTRY);
2391	absDirLink1.initALink(dir1, "absDirLink1", subDir1);
2392	absDirLink2.initALink(dir1, "absDirLink2", absDirLink1);
2393	absDirLink3.initALink(dir2, "absDirLink3", absDirLink2);
2394	absDirLink4.initALink(testDir, "absDirLink4", absDirLink3);
2395	relDirLink1.initRLink(dir1, "relDirLink1", subDir1);
2396	relDirLink2.initRLink(dir1, "relDirLink2", relDirLink1);
2397	relDirLink3.initRLink(dir2, "relDirLink3", relDirLink2);
2398	relDirLink4.initRLink(testDir, "relDirLink4", relDirLink3);
2399	absFileLink1.initALink(dir1, "absFileLink1", file1);
2400	absFileLink2.initALink(dir1, "absFileLink2", absFileLink1);
2401	absFileLink3.initALink(dir2, "absFileLink3", absFileLink2);
2402	absFileLink4.initALink(testDir, "absFileLink4", absFileLink3);
2403	relFileLink1.initRLink(dir1, "relFileLink1", file1);
2404	relFileLink2.initRLink(dir1, "relFileLink2", relFileLink1);
2405	relFileLink3.initRLink(dir2, "relFileLink3", relFileLink2);
2406	relFileLink4.initRLink(testDir, "relFileLink4", relFileLink3);
2407	absCyclicLink1.initALink(dir1, "absCyclicLink1", absCyclicLink2);
2408	absCyclicLink2.initALink(dir1, "absCyclicLink2", absCyclicLink1);
2409	relCyclicLink1.initRLink(dir1, "relCyclicLink1", relCyclicLink2);
2410	relCyclicLink2.initRLink(dir1, "relCyclicLink2", relCyclicLink1);
2411	absBadLink1.initALink(dir1, "absBadLink1", abstractEntry1);
2412	absBadLink2.initALink(dir1, "absBadLink2", absBadLink1);
2413	absBadLink3.initALink(dir2, "absBadLink3", absBadLink2);
2414	absBadLink4.initALink(testDir, "absBadLink4", absBadLink3);
2415	relBadLink1.initRLink(dir1, "relBadLink1", abstractEntry1);
2416	relBadLink2.initRLink(dir1, "relBadLink2", relBadLink1);
2417	relBadLink3.initRLink(dir2, "relBadLink3", relBadLink2);
2418	relBadLink4.initRLink(testDir, "relBadLink4", relBadLink3);
2419	absVeryBadLink1.initALink(dir1, "absVeryBadLink1", badEntry1);
2420	absVeryBadLink2.initALink(dir1, "absVeryBadLink2", absVeryBadLink1);
2421	absVeryBadLink3.initALink(dir2, "absVeryBadLink3", absVeryBadLink2);
2422	absVeryBadLink4.initALink(testDir, "absVeryBadLink4", absVeryBadLink3);
2423	relVeryBadLink1.initRLink(dir1, "relVeryBadLink1", badEntry1);
2424	relVeryBadLink2.initRLink(dir1, "relVeryBadLink2", relVeryBadLink1);
2425	relVeryBadLink3.initRLink(dir2, "relVeryBadLink3", relVeryBadLink2);
2426	relVeryBadLink4.initRLink(testDir, "relVeryBadLink4", relVeryBadLink3);
2427	tooLongEntry1.init(testDir, tooLongEntryname, ABSTRACT_ENTRY);
2428	tooLongDir1.initDir(testDir, tooLongDirname);
2429	tooLongDir2.initDir(tooLongDir1, tooLongDirname);
2430	tooLongDir3.initDir(tooLongDir2, tooLongDirname);
2431	tooLongDir4.initDir(tooLongDir3, tooLongDirname);
2432	tooLongDir5.initDir(tooLongDir4, tooLongDirname);
2433	tooLongDir6.initDir(tooLongDir5, tooLongDirname);
2434	tooLongDir7.initDir(tooLongDir6, tooLongDirname);
2435	tooLongDir8.initDir(tooLongDir7, tooLongDirname);
2436	tooLongDir9.initDir(tooLongDir8, tooLongDirname);
2437	tooLongDir10.initDir(tooLongDir9, tooLongDirname);
2438	tooLongDir11.initDir(tooLongDir10, tooLongDirname);
2439	tooLongDir12.initDir(tooLongDir11, tooLongDirname);
2440	tooLongDir13.initDir(tooLongDir12, tooLongDirname);
2441	tooLongDir14.initDir(tooLongDir13, tooLongDirname);
2442	tooLongDir15.initDir(tooLongDir14, tooLongDirname);
2443	tooLongDir16.initDir(tooLongDir15, tooLongDirname);
2444
2445	// init paths
2446	for (list<TestEntry*>::iterator it = allTestEntries.begin();
2447		 it != allTestEntries.end(); it++) {
2448		(*it)->initPath();
2449	}
2450	// complete initialization
2451	testDir.completeInit();
2452	for (list<TestEntry*>::iterator it = allTestEntries.begin();
2453		 it != allTestEntries.end(); it++) {
2454		(*it)->completeInit();
2455	}
2456	// create the set up command line
2457	setUpCommandLine = string("mkdir ") + testDir.path;
2458	for (list<TestEntry*>::iterator it = allTestEntries.begin();
2459		 it != allTestEntries.end(); it++) {
2460		TestEntry *entry = *it;
2461		string command;
2462		switch (entry->kind) {
2463			case ABSTRACT_ENTRY:
2464				break;
2465			case DIR_ENTRY:
2466			{
2467				if (entry->path.length() < B_PATH_NAME_LENGTH) {
2468					command = string("mkdir ") + entry->path;
2469				} else {
2470					command = string("( ")
2471						+ "cd " + entry->super->super->path + " ; "
2472						+ " mkdir " + entry->super->name + "/" + entry->name
2473						+ " )";
2474				}
2475				break;
2476			}
2477			case FILE_ENTRY:
2478			{
2479				command = string("touch ") + entry->path;
2480				break;
2481			}
2482			case LINK_ENTRY:
2483			{
2484				command = string("ln -s ") + entry->link + " " + entry->path;
2485				break;
2486			}
2487			default:
2488				break;
2489		}
2490		if (command.length() > 0) {
2491			if (setUpCommandLine.length() == 0)
2492				setUpCommandLine = command;
2493			else
2494				setUpCommandLine += string(" ; ") + command;
2495		}
2496	}
2497	// create the tear down command line
2498	tearDownCommandLine = string("rm -rf ") + testDir.path;
2499}
2500
2501struct InitEntryTest {
2502	InitEntryTest()
2503	{
2504		init_entry_test();
2505	}
2506} _InitEntryTest;
2507
2508
2509// TestEntry
2510
2511// constructor
2512TestEntry::TestEntry()
2513		 : super(&badTestEntry),
2514		   name("badTestEntry"),
2515		   kind(BAD_ENTRY),
2516		   path("/tmp/badTestEntry"),
2517		   target(&badTestEntry),
2518		   link(),
2519		   ref(),
2520		   relative(true),
2521		   cname(""),
2522		   cpath(""),
2523		   clink("")
2524{
2525}
2526
2527// init
2528void
2529TestEntry::init(TestEntry &super, string name, test_entry_kind kind,
2530				bool relative)
2531{
2532	this->super		= &super;
2533	this->name		= name;
2534	this->kind		= kind;
2535	this->relative	= relative;
2536	allTestEntries.push_back(this);
2537}
2538
2539// initDir
2540void
2541TestEntry::initDir(TestEntry &super, string name)
2542{
2543	init(super, name, DIR_ENTRY);
2544}
2545
2546// initFile
2547void
2548TestEntry::initFile(TestEntry &super, string name)
2549{
2550	init(super, name, FILE_ENTRY);
2551}
2552
2553// initRLink
2554void
2555TestEntry::initRLink(TestEntry &super, string name, TestEntry &target)
2556{
2557	init(super, name, LINK_ENTRY, true);
2558	this->target = &target;
2559}
2560
2561// initALink
2562void
2563TestEntry::initALink(TestEntry &super, string name, TestEntry &target)
2564{
2565	init(super, name, LINK_ENTRY, false);
2566	this->target = &target;
2567}
2568
2569// initPath
2570void
2571TestEntry::initPath(const char *pathName)
2572{
2573	if (pathName)
2574		path = pathName;
2575	else
2576		path = super->path + "/" + name;
2577}
2578
2579// completeInit
2580void
2581TestEntry::completeInit()
2582{
2583	// init link
2584	if (kind == LINK_ENTRY) {
2585		if (relative)
2586			link = get_shortest_relative_path(super, target);
2587		else
2588			link = target->path;
2589	}
2590	// init the C strings
2591	cname = name.c_str();
2592	cpath = path.c_str();
2593	clink = link.c_str();
2594}
2595
2596// get_ref
2597const entry_ref &
2598TestEntry::get_ref()
2599{
2600	if (isConcrete() || isAbstract())
2601		get_entry_ref_for_entry(super->cpath, cname, &ref);
2602	return ref;
2603}
2604
2605// get_shortest_relative_path
2606static
2607string
2608get_shortest_relative_path(TestEntry *dir, TestEntry *entry)
2609{
2610	string relPath;
2611	// put all super directories (including dir itself) of the dir in a set
2612	map<TestEntry*, int> superDirs;
2613	int dirSuperLevel = 0;
2614	for (TestEntry *superDir = dir;
2615		 superDir != &badTestEntry;
2616		 superDir = superDir->super, dirSuperLevel++) {
2617		superDirs[superDir] = dirSuperLevel;
2618	}
2619	// find the first super dir that dir and entry have in common
2620	TestEntry *commonSuperDir = &badTestEntry;
2621	int targetSuperLevel = 0;
2622	for (TestEntry *superDir = entry;
2623		 commonSuperDir == &badTestEntry
2624		 && superDir != &badTestEntry;
2625		 superDir = superDir->super, targetSuperLevel++) {
2626		if (superDirs.find(superDir) != superDirs.end())
2627			commonSuperDir = superDir;
2628	}
2629	// construct the relative path
2630	if (commonSuperDir != &badTestEntry) {
2631		dirSuperLevel = superDirs[commonSuperDir];
2632		if (dirSuperLevel == 0 && targetSuperLevel == 0) {
2633			// entry == dir
2634			relPath == ".";
2635		} else {
2636			// levels down
2637			for (TestEntry *superDir = entry;
2638				 superDir != commonSuperDir;
2639				 superDir = superDir->super) {
2640				if (relPath.length() == 0)
2641					relPath = superDir->name;
2642				else
2643					relPath = superDir->name + "/" + relPath;
2644			}
2645			// levels up
2646			for (int i = dirSuperLevel; i > 0; i--) {
2647				if (relPath.length() == 0)
2648					relPath = "..";
2649				else
2650					relPath = string("../") + relPath;
2651			}
2652		}
2653	}
2654	return relPath;
2655}
2656
2657// resolve_link
2658static
2659TestEntry *
2660resolve_link(TestEntry *entry)
2661{
2662	set<TestEntry*> followedLinks;
2663	while (entry != &badTestEntry && entry->kind == LINK_ENTRY) {
2664		if (followedLinks.find(entry) == followedLinks.end()) {
2665			followedLinks.insert(entry);
2666			entry = entry->target;
2667		} else
2668			entry = &badTestEntry;	// cyclic link
2669	}
2670	return entry;
2671}
2672
2673
2674
2675
2676