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