1// NodeTest.cpp
2
3#include <cppunit/TestCase.h>
4#include <cppunit/TestCaller.h>
5#include <cppunit/TestSuite.h>
6#include <TestUtils.h>
7
8#include <errno.h>
9#include <fs_attr.h>	// For struct attr_info
10#include <stdio.h>
11#include <unistd.h>
12#include <sys/stat.h>	// For struct stat
13
14#include <Directory.h>
15#include <Entry.h>
16#include <Node.h>
17#include <StorageDefs.h>
18#include <String.h>
19#include <TypeConstants.h>
20
21#include "NodeTest.h"
22
23
24// == for attr_info
25static
26inline
27bool
28operator==(const attr_info &info1, const attr_info &info2)
29{
30	return (info1.type == info2.type && info1.size == info2.size);
31}
32
33// Suite
34CppUnit::Test*
35NodeTest::Suite() {
36	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
37
38	StatableTest::AddBaseClassTests<NodeTest>("BNode::", suite);
39
40	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Init Test1", &NodeTest::InitTest1) );
41	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Init Test2", &NodeTest::InitTest2) );
42	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Attribute Directory Test", &NodeTest::AttrDirTest) );
43	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Attribute Read/Write/Remove Test", &NodeTest::AttrTest) );
44	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Attribute Rename Test"
45#if TEST_R5
46														" (NOTE: test not actually performed with R5 libraries)"
47#endif
48														, &NodeTest::AttrRenameTest) );
49	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Attribute Info Test", &NodeTest::AttrInfoTest) );
50	// TODO: AttrBString deadlocks entire OS (UnitTester at 100% CPU,
51	// windows don't respond to actions, won't open, OS won't even shut down)
52	//suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Attribute BString Test", &NodeTest::AttrBStringTest) );
53	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Sync Test", &NodeTest::SyncTest) );
54	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Dup Test", &NodeTest::DupTest) );
55	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Equality Test", &NodeTest::EqualityTest) );
56	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Assignment Test", &NodeTest::AssignmentTest) );
57	suite->addTest( new CppUnit::TestCaller<NodeTest>("BNode::Lock Test"
58														, &NodeTest::LockTest) );
59
60	return suite;
61}
62
63// ConvertTestNodesToStatables
64static
65void
66ConvertTestStatablesToNodes(TestNodes& testNodes, TestStatables& testStatables)
67{
68	BNode *node;
69	string entryName;
70	for (testNodes.rewind(); testNodes.getNext(node, entryName); )
71		testStatables.add(node, entryName);
72	testNodes.clear();	// avoid deletion
73}
74
75// CreateROStatables
76void
77NodeTest::CreateROStatables(TestStatables& testEntries)
78{
79	TestNodes testNodes;
80	CreateRONodes(testNodes);
81	ConvertTestStatablesToNodes(testNodes, testEntries);
82}
83
84// CreateRWStatables
85void
86NodeTest::CreateRWStatables(TestStatables& testEntries)
87{
88	TestNodes testNodes;
89	CreateRWNodes(testNodes);
90	ConvertTestStatablesToNodes(testNodes, testEntries);
91}
92
93// CreateUninitializedStatables
94void
95NodeTest::CreateUninitializedStatables(TestStatables& testEntries)
96{
97	TestNodes testNodes;
98	CreateUninitializedNodes(testNodes);
99	ConvertTestStatablesToNodes(testNodes, testEntries);
100}
101
102// CreateRONodes
103void
104NodeTest::CreateRONodes(TestNodes& testEntries)
105{
106	const char *filename;
107	filename = "/tmp";
108	testEntries.add(new BNode(filename), filename);
109	filename = "/";
110	testEntries.add(new BNode(filename), filename);
111	filename = "/boot";
112	testEntries.add(new BNode(filename), filename);
113	filename = "/boot/home";
114	testEntries.add(new BNode(filename), filename);
115	filename = "/boot/home/Desktop";
116	testEntries.add(new BNode(filename), filename);
117	filename = existingFilename;
118	testEntries.add(new BNode(filename), filename);
119	filename = dirLinkname;
120	testEntries.add(new BNode(filename), filename);
121	filename = fileLinkname;
122	testEntries.add(new BNode(filename), filename);
123}
124
125// CreateRWNodes
126void
127NodeTest::CreateRWNodes(TestNodes& testEntries)
128{
129	const char *filename;
130	filename = existingFilename;
131	testEntries.add(new BNode(filename), filename);
132	filename = existingDirname;
133	testEntries.add(new BNode(filename), filename);
134	filename = existingSubDirname;
135	testEntries.add(new BNode(filename), filename);
136	filename = dirLinkname;
137	testEntries.add(new BNode(filename), filename);
138	filename = fileLinkname;
139	testEntries.add(new BNode(filename), filename);
140	filename = relDirLinkname;
141	testEntries.add(new BNode(filename), filename);
142	filename = relFileLinkname;
143	testEntries.add(new BNode(filename), filename);
144	filename = cyclicLinkname1;
145	testEntries.add(new BNode(filename), filename);
146}
147
148// CreateUninitializedNodes
149void
150NodeTest::CreateUninitializedNodes(TestNodes& testEntries)
151{
152	testEntries.add(new BNode, "");
153}
154
155// setUp
156void
157NodeTest::setUp()
158{
159	StatableTest::setUp();
160	execCommand(
161		string("touch ") + existingFilename
162		+ "; mkdir " + existingDirname
163		+ "; mkdir " + existingSubDirname
164		+ "; ln -s " + existingDirname + " " + dirLinkname
165		+ "; ln -s " + existingFilename + " " + fileLinkname
166		+ "; ln -s " + existingRelDirname + " " + relDirLinkname
167		+ "; ln -s " + existingRelFilename + " " + relFileLinkname
168		+ "; ln -s " + nonExistingDirname + " " + badLinkname
169		+ "; ln -s " + cyclicLinkname1 + " " + cyclicLinkname2
170		+ "; ln -s " + cyclicLinkname2 + " " + cyclicLinkname1
171	);
172}
173
174// tearDown
175void
176NodeTest::tearDown()
177{
178	StatableTest::tearDown();
179	// cleanup
180	string cmdLine("rm -rf ");
181	for (int32 i = 0; i < allFilenameCount; i++)
182		cmdLine += string(" ") + allFilenames[i];
183	if (allFilenameCount > 0)
184		execCommand(cmdLine);
185}
186
187// InitTest1
188void
189NodeTest::InitTest1()
190{
191	const char *dirLink = dirLinkname;
192	const char *dirSuperLink = dirSuperLinkname;
193	const char *dirRelLink = dirRelLinkname;
194	const char *fileLink = fileLinkname;
195	const char *existingDir = existingDirname;
196	const char *existingSuperDir = existingSuperDirname;
197	const char *existingRelDir = existingRelDirname;
198	const char *existingFile = existingFilename;
199	const char *existingSuperFile = existingSuperFilename;
200	const char *existingRelFile = existingRelFilename;
201	const char *nonExisting = nonExistingDirname;
202	const char *nonExistingSuper = nonExistingSuperDirname;
203	const char *nonExistingRel = nonExistingRelDirname;
204	// 1. default constructor
205	NextSubTest();
206	{
207		BNode node;
208		CPPUNIT_ASSERT( node.InitCheck() == B_NO_INIT );
209	}
210
211	// 2. BNode(const char*)
212	NextSubTest();
213	{
214		BNode node(fileLink);
215		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
216	}
217	NextSubTest();
218	{
219		BNode node(nonExisting);
220		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
221	}
222	NextSubTest();
223	{
224		BNode node((const char *)NULL);
225		CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_VALUE, B_NO_INIT) );
226	}
227	NextSubTest();
228	{
229		BNode node("");
230		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
231	}
232	NextSubTest();
233	{
234		BNode node(existingFile);
235		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
236	}
237	NextSubTest();
238	{
239		BNode node(existingDir);
240		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
241	}
242	NextSubTest();
243	{
244		BNode node(tooLongEntryname);
245		CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG );
246	}
247
248	// 3. BNode(const BEntry*)
249	NextSubTest();
250	{
251		BEntry entry(dirLink);
252		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
253		BNode node(&entry);
254		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
255	}
256	NextSubTest();
257	{
258		BEntry entry(nonExisting);
259		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
260		BNode node(&entry);
261		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
262	}
263	NextSubTest();
264	{
265		BNode node((BEntry *)NULL);
266		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
267	}
268	NextSubTest();
269	{
270		BEntry entry;
271		BNode node(&entry);
272		CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) );
273	}
274	NextSubTest();
275	{
276		BEntry entry(existingFile);
277		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
278		BNode node(&entry);
279		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
280
281	}
282	NextSubTest();
283	{
284		BEntry entry(existingDir);
285		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
286		BNode node(&entry);
287		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
288
289	}
290	NextSubTest();
291	{
292		BEntry entry(tooLongEntryname);
293		// R5 returns E2BIG instead of B_NAME_TOO_LONG
294		CPPUNIT_ASSERT( equals(entry.InitCheck(), E2BIG, B_NAME_TOO_LONG) );
295		BNode node(&entry);
296		CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) );
297	}
298
299	// 4. BNode(const entry_ref*)
300	NextSubTest();
301	{
302		BEntry entry(dirLink);
303		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
304		entry_ref ref;
305		CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
306		BNode node(&ref);
307		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
308	}
309	NextSubTest();
310	{
311		BEntry entry(nonExisting);
312		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
313		entry_ref ref;
314		CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
315		BNode node(&ref);
316		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
317	}
318	NextSubTest();
319	{
320		BNode node((entry_ref *)NULL);
321		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
322	}
323	NextSubTest();
324	{
325		BEntry entry(existingFile);
326		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
327		entry_ref ref;
328		CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
329		BNode node(&ref);
330		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
331	}
332	NextSubTest();
333	{
334		BEntry entry(existingDir);
335		CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
336		entry_ref ref;
337		CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
338		BNode node(&ref);
339		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
340	}
341
342	// 5. BNode(const BDirectory*, const char*)
343	NextSubTest();
344	{
345		BDirectory pathDir(dirSuperLink);
346		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
347		BNode node(&pathDir, dirRelLink);
348		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
349	}
350	NextSubTest();
351	{
352		BDirectory pathDir(dirSuperLink);
353		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
354		BNode node(&pathDir, dirLink);
355		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
356	}
357	NextSubTest();
358	{
359		BDirectory pathDir(nonExistingSuper);
360		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
361		BNode node(&pathDir, nonExistingRel);
362		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
363	}
364	NextSubTest();
365	{
366		BNode node((BDirectory *)NULL, (const char *)NULL);
367		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
368	}
369	NextSubTest();
370	{
371		BNode node((BDirectory *)NULL, dirLink);
372		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
373	}
374	NextSubTest();
375	{
376		BDirectory pathDir(dirSuperLink);
377		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
378		BNode node(&pathDir, (const char *)NULL);
379		CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
380	}
381	NextSubTest();
382	{
383		BDirectory pathDir(dirSuperLink);
384		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
385		BNode node(&pathDir, "");
386		CPPUNIT_ASSERT(node.InitCheck() == B_ENTRY_NOT_FOUND);
387	}
388	NextSubTest();
389	{
390		BDirectory pathDir(existingSuperFile);
391		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
392		BNode node(&pathDir, existingRelFile);
393		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
394	}
395	NextSubTest();
396	{
397		BDirectory pathDir(existingSuperDir);
398		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
399		BNode node(&pathDir, existingRelDir);
400		CPPUNIT_ASSERT( node.InitCheck() == B_OK );
401	}
402	NextSubTest();
403	{
404		BDirectory pathDir(tooLongSuperEntryname);
405		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
406		BNode node(&pathDir, tooLongRelEntryname);
407		CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG );
408	}
409	NextSubTest();
410	{
411		BDirectory pathDir(fileSuperDirname);
412		CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
413		BNode node(&pathDir, fileRelDirname);
414		CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
415	}
416}
417
418// InitTest2
419void
420NodeTest::InitTest2()
421{
422	const char *dirLink = dirLinkname;
423	const char *dirSuperLink = dirSuperLinkname;
424	const char *dirRelLink = dirRelLinkname;
425	const char *fileLink = fileLinkname;
426	const char *existingDir = existingDirname;
427	const char *existingSuperDir = existingSuperDirname;
428	const char *existingRelDir = existingRelDirname;
429	const char *existingFile = existingFilename;
430	const char *existingSuperFile = existingSuperFilename;
431	const char *existingRelFile = existingRelFilename;
432	const char *nonExisting = nonExistingDirname;
433	const char *nonExistingSuper = nonExistingSuperDirname;
434	const char *nonExistingRel = nonExistingRelDirname;
435	BNode node;
436	// 2. BNode(const char*)
437	NextSubTest();
438	CPPUNIT_ASSERT( node.SetTo(fileLink) == B_OK );
439	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
440	//
441	NextSubTest();
442	CPPUNIT_ASSERT( node.SetTo(nonExisting) == B_ENTRY_NOT_FOUND );
443	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
444	//
445	NextSubTest();
446	CPPUNIT_ASSERT( equals(node.SetTo((const char *)NULL), B_BAD_VALUE,
447						   B_NO_INIT) );
448	CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_VALUE, B_NO_INIT) );
449	//
450	NextSubTest();
451	CPPUNIT_ASSERT( node.SetTo("") == B_ENTRY_NOT_FOUND );
452	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
453	//
454	NextSubTest();
455	CPPUNIT_ASSERT( node.SetTo(existingFile) == B_OK );
456	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
457	//
458	NextSubTest();
459	CPPUNIT_ASSERT( node.SetTo(existingDir) == B_OK );
460	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
461	//
462	NextSubTest();
463	CPPUNIT_ASSERT( node.SetTo(tooLongEntryname) == B_NAME_TOO_LONG );
464	CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG );
465
466	// 3. BNode(const BEntry*)
467	NextSubTest();
468	BEntry entry(dirLink);
469	CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
470	CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK );
471	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
472	//
473	NextSubTest();
474	CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK );
475	CPPUNIT_ASSERT( node.SetTo(&entry) == B_ENTRY_NOT_FOUND );
476	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
477	//
478	NextSubTest();
479	CPPUNIT_ASSERT( node.SetTo((BEntry *)NULL) == B_BAD_VALUE );
480	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
481	//
482	NextSubTest();
483	entry.Unset();
484	CPPUNIT_ASSERT( entry.InitCheck() == B_NO_INIT );
485	CPPUNIT_ASSERT( equals(node.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) );
486	CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) );
487	//
488	NextSubTest();
489	CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK );
490	CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK );
491	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
492	//
493	NextSubTest();
494	CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK );
495	CPPUNIT_ASSERT( node.SetTo(&entry) == B_OK );
496	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
497	//
498	NextSubTest();
499	// R5 returns E2BIG instead of B_NAME_TOO_LONG
500	CPPUNIT_ASSERT( equals(entry.SetTo(tooLongEntryname), E2BIG, B_NAME_TOO_LONG) );
501	CPPUNIT_ASSERT( equals(node.SetTo(&entry), B_BAD_ADDRESS, B_BAD_VALUE) );
502	CPPUNIT_ASSERT( equals(node.InitCheck(), B_BAD_ADDRESS, B_BAD_VALUE) );
503
504	// 4. BNode(const entry_ref*)
505	NextSubTest();
506	CPPUNIT_ASSERT( entry.SetTo(dirLink) == B_OK );
507	entry_ref ref;
508	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
509	CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK );
510	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
511	//
512	NextSubTest();
513	CPPUNIT_ASSERT( entry.SetTo(nonExisting) == B_OK );
514	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
515	CPPUNIT_ASSERT( node.SetTo(&ref) == B_ENTRY_NOT_FOUND );
516	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
517	//
518	NextSubTest();
519	CPPUNIT_ASSERT( node.SetTo((entry_ref *)NULL) == B_BAD_VALUE );
520	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
521	//
522	NextSubTest();
523	CPPUNIT_ASSERT( entry.SetTo(existingFile) == B_OK );
524	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
525	CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK );
526	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
527	//
528	NextSubTest();
529	CPPUNIT_ASSERT( entry.SetTo(existingDir) == B_OK );
530	CPPUNIT_ASSERT( entry.GetRef(&ref) == B_OK );
531	CPPUNIT_ASSERT( node.SetTo(&ref) == B_OK );
532	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
533
534	// 5. BNode(const BDirectory*, const char*)
535	NextSubTest();
536	BDirectory pathDir(dirSuperLink);
537	CPPUNIT_ASSERT( pathDir.InitCheck() == B_OK );
538	CPPUNIT_ASSERT( node.SetTo(&pathDir, dirRelLink) == B_OK );
539	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
540	//
541	NextSubTest();
542	CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK );
543	CPPUNIT_ASSERT( node.SetTo(&pathDir, dirLink) == B_BAD_VALUE );
544	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
545	//
546	NextSubTest();
547	CPPUNIT_ASSERT( pathDir.SetTo(nonExistingSuper) == B_OK );
548	CPPUNIT_ASSERT( node.SetTo(&pathDir, nonExistingRel) == B_ENTRY_NOT_FOUND );
549	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
550	//
551	NextSubTest();
552	CPPUNIT_ASSERT( node.SetTo((BDirectory *)NULL, (const char *)NULL)
553					== B_BAD_VALUE );
554	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
555	//
556	NextSubTest();
557	CPPUNIT_ASSERT( node.SetTo((BDirectory *)NULL, dirLink) == B_BAD_VALUE );
558	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
559	//
560	NextSubTest();
561	CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK );
562	CPPUNIT_ASSERT( node.SetTo(&pathDir, (const char *)NULL) == B_BAD_VALUE );
563	CPPUNIT_ASSERT( node.InitCheck() == B_BAD_VALUE );
564	//
565	NextSubTest();
566	CPPUNIT_ASSERT( pathDir.SetTo(dirSuperLink) == B_OK );
567	CPPUNIT_ASSERT(node.SetTo(&pathDir, "") == B_ENTRY_NOT_FOUND);
568	CPPUNIT_ASSERT(node.InitCheck() == B_ENTRY_NOT_FOUND);
569	//
570	NextSubTest();
571	CPPUNIT_ASSERT( pathDir.SetTo(existingSuperFile) == B_OK );
572	CPPUNIT_ASSERT( node.SetTo(&pathDir, existingRelFile) == B_OK );
573	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
574	//
575	NextSubTest();
576	CPPUNIT_ASSERT( pathDir.SetTo(existingSuperDir) == B_OK );
577	CPPUNIT_ASSERT( node.SetTo(&pathDir, existingRelDir) == B_OK );
578	CPPUNIT_ASSERT( node.InitCheck() == B_OK );
579	//
580	NextSubTest();
581	CPPUNIT_ASSERT( pathDir.SetTo(tooLongSuperEntryname) == B_OK );
582	CPPUNIT_ASSERT( node.SetTo(&pathDir, tooLongRelEntryname) == B_NAME_TOO_LONG );
583	CPPUNIT_ASSERT( node.InitCheck() == B_NAME_TOO_LONG );
584	//
585	NextSubTest();
586	CPPUNIT_ASSERT( pathDir.SetTo(fileSuperDirname) == B_OK );
587	CPPUNIT_ASSERT( node.SetTo(&pathDir, fileRelDirname) == B_ENTRY_NOT_FOUND );
588	CPPUNIT_ASSERT( node.InitCheck() == B_ENTRY_NOT_FOUND );
589}
590
591// WriteAttributes
592static
593void
594WriteAttributes(BNode &node, const char **attrNames, const char **attrValues,
595				int32 attrCount)
596{
597	for (int32 i = 0; i < attrCount; i++) {
598		const char *attrName = attrNames[i];
599		const char *attrValue = attrValues[i];
600		int32 valueSize = strlen(attrValue) + 1;
601		CPPUNIT_ASSERT( node.WriteAttr(attrName, B_STRING_TYPE, 0, attrValue,
602									   valueSize) == valueSize );
603	}
604}
605
606// AttrDirTest
607void
608NodeTest::AttrDirTest(BNode &node)
609{
610	// node should not have any attributes at the beginning
611	char nameBuffer[B_ATTR_NAME_LENGTH];
612	CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND );
613	// add some
614	const char *attrNames[] = {
615		"attr1", "attr2", "attr3", "attr4", "attr5"
616	};
617	const char *attrValues[] = {
618		"value1", "value2", "value3", "value4", "value5"
619	};
620	int32 attrCount = sizeof(attrNames) / sizeof(const char *);
621	WriteAttributes(node, attrNames, attrValues, attrCount);
622	TestSet testSet;
623	for (int32 i = 0; i < attrCount; i++)
624		testSet.add(attrNames[i]);
625	// get all attribute names
626	// R5: We have to rewind, we wouldn't get any attribute otherwise.
627	CPPUNIT_ASSERT( node.RewindAttrs() == B_OK );
628	while (node.GetNextAttrName(nameBuffer) == B_OK)
629		CPPUNIT_ASSERT( testSet.test(nameBuffer) == true );
630	CPPUNIT_ASSERT( testSet.testDone() == true );
631	CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND );
632	// rewind, get one attribute, rewind again and iterate through the whole
633	// list again
634	CPPUNIT_ASSERT( node.RewindAttrs() == B_OK );
635	testSet.rewind();
636	CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_OK );
637	CPPUNIT_ASSERT( testSet.test(nameBuffer) == true );
638	CPPUNIT_ASSERT( node.RewindAttrs() == B_OK );
639	testSet.rewind();
640	while (node.GetNextAttrName(nameBuffer) == B_OK)
641		CPPUNIT_ASSERT( testSet.test(nameBuffer) == true );
642	CPPUNIT_ASSERT( testSet.testDone() == true );
643	CPPUNIT_ASSERT( node.GetNextAttrName(nameBuffer) == B_ENTRY_NOT_FOUND );
644	// bad args
645	CPPUNIT_ASSERT( node.RewindAttrs() == B_OK );
646	testSet.rewind();
647// R5: crashs, if passing a NULL buffer
648#if !TEST_R5
649	CPPUNIT_ASSERT( node.GetNextAttrName(NULL) == B_BAD_VALUE );
650#endif
651}
652
653// AttrDirTest
654void
655NodeTest::AttrDirTest()
656{
657	// uninitialized objects
658	NextSubTest();
659	TestNodes testEntries;
660	CreateUninitializedNodes(testEntries);
661	BNode *node;
662	string nodeName;
663	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
664		char nameBuffer[B_ATTR_NAME_LENGTH];
665		CPPUNIT_ASSERT( node->RewindAttrs() != B_OK );
666		CPPUNIT_ASSERT( node->GetNextAttrName(nameBuffer) != B_OK );
667	}
668	testEntries.delete_all();
669	// existing entries
670	NextSubTest();
671	CreateRWNodes(testEntries);
672	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
673		AttrDirTest(*node);
674	}
675	testEntries.delete_all();
676}
677
678// AttrTest
679void
680NodeTest::AttrTest(BNode &node)
681{
682	// add some attributes
683	const char *attrNames[] = {
684		"attr1", "attr2", "attr3", "attr4", "attr5"
685	};
686	const char *attrValues[] = {
687		"value1", "value2", "value3", "value4", "value5"
688	};
689	const char *newAttrValues[] = {
690		"fd", "kkgkjsdhfgkjhsd", "lihuhuh", "", "alkfgnakdfjgn"
691	};
692	int32 attrCount = sizeof(attrNames) / sizeof(const char *);
693	WriteAttributes(node, attrNames, attrValues, attrCount);
694	char buffer[1024];
695	// read and check them
696	for (int32 i = 0; i < attrCount; i++) {
697		const char *attrName = attrNames[i];
698		const char *attrValue = attrValues[i];
699		int32 valueSize = strlen(attrValue) + 1;
700		CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer,
701									  sizeof(buffer)) == valueSize );
702		CPPUNIT_ASSERT( strcmp(buffer, attrValue) == 0 );
703	}
704	// write a new value for each attribute
705	WriteAttributes(node, attrNames, newAttrValues, attrCount);
706	// read and check them
707	for (int32 i = 0; i < attrCount; i++) {
708		const char *attrName = attrNames[i];
709		const char *attrValue = newAttrValues[i];
710		int32 valueSize = strlen(attrValue) + 1;
711		CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer,
712									  sizeof(buffer)) == valueSize );
713		CPPUNIT_ASSERT( strcmp(buffer, attrValue) == 0 );
714	}
715	// bad args
716	CPPUNIT_ASSERT( equals(node.ReadAttr(NULL, B_STRING_TYPE, 0, buffer,
717										 sizeof(buffer)),
718						   B_BAD_ADDRESS, B_BAD_VALUE) );
719	CPPUNIT_ASSERT( equals(node.ReadAttr(attrNames[0], B_STRING_TYPE, 0, NULL,
720										 sizeof(buffer)),
721						   B_BAD_ADDRESS, B_BAD_VALUE) );
722	CPPUNIT_ASSERT( equals(node.ReadAttr(NULL, B_STRING_TYPE, 0, NULL,
723										 sizeof(buffer)),
724						   B_BAD_ADDRESS, B_BAD_VALUE) );
725	CPPUNIT_ASSERT( equals(node.WriteAttr(NULL, B_STRING_TYPE, 0, buffer,
726										  sizeof(buffer)),
727						   B_BAD_ADDRESS, B_BAD_VALUE) );
728	CPPUNIT_ASSERT( equals(node.WriteAttr(attrNames[0], B_STRING_TYPE, 0, NULL,
729										  sizeof(buffer)),
730						   B_BAD_ADDRESS, B_BAD_VALUE) );
731	CPPUNIT_ASSERT( equals(node.WriteAttr(NULL, B_STRING_TYPE, 0, NULL,
732										  sizeof(buffer)),
733						   B_BAD_ADDRESS, B_BAD_VALUE) );
734	CPPUNIT_ASSERT( equals(node.RemoveAttr(NULL), B_BAD_ADDRESS, B_BAD_VALUE) );
735	// too long attribute name
736	// R5: Read/RemoveAttr() do not return B_NAME_TOO_LONG, but B_ENTRY_NOT_FOUND
737	// R5: WriteAttr() does not return B_NAME_TOO_LONG, but B_BAD_VALUE
738	// R5: Haiku has a max attribute size of 256, while R5's was 255, exclusive
739	//     of the null terminator. See changeset 4069e1f30.
740	char tooLongAttrName[B_ATTR_NAME_LENGTH + 3];
741	memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH + 1);
742	tooLongAttrName[B_ATTR_NAME_LENGTH + 2] = '\0';
743	CPPUNIT_ASSERT_EQUAL(
744		node.WriteAttr(tooLongAttrName, B_STRING_TYPE, 0, buffer,
745			sizeof(buffer)),
746		B_NAME_TOO_LONG);
747	CPPUNIT_ASSERT_EQUAL(
748		node.ReadAttr(tooLongAttrName, B_STRING_TYPE, 0, buffer,
749			sizeof(buffer)),
750		B_NAME_TOO_LONG);
751	CPPUNIT_ASSERT_EQUAL(node.RemoveAttr(tooLongAttrName), B_NAME_TOO_LONG);
752
753	// remove the attributes and try to read them
754	for (int32 i = 0; i < attrCount; i++) {
755		const char *attrName = attrNames[i];
756		CPPUNIT_ASSERT( node.RemoveAttr(attrName) == B_OK );
757		CPPUNIT_ASSERT( node.ReadAttr(attrName, B_STRING_TYPE, 0, buffer,
758									  sizeof(buffer)) == B_ENTRY_NOT_FOUND );
759	}
760	// try to remove a non-existing attribute
761	CPPUNIT_ASSERT( node.RemoveAttr("non existing attribute")
762					== B_ENTRY_NOT_FOUND );
763}
764
765// AttrTest
766void
767NodeTest::AttrTest()
768{
769	// uninitialized objects
770	NextSubTest();
771	TestNodes testEntries;
772	CreateUninitializedNodes(testEntries);
773	BNode *node;
774	string nodeName;
775	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
776		char buffer[1024];
777		CPPUNIT_ASSERT( node->ReadAttr("attr1", B_STRING_TYPE, 0, buffer,
778									   sizeof(buffer)) == B_FILE_ERROR );
779		CPPUNIT_ASSERT( node->WriteAttr("attr1", B_STRING_TYPE, 0, buffer,
780										sizeof(buffer)) == B_FILE_ERROR );
781		CPPUNIT_ASSERT( node->RemoveAttr("attr1") == B_FILE_ERROR );
782	}
783	testEntries.delete_all();
784	// existing entries
785	NextSubTest();
786	CreateRWNodes(testEntries);
787	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
788		AttrTest(*node);
789	}
790	testEntries.delete_all();
791}
792
793// AttrRenameTest
794void
795NodeTest::AttrRenameTest(BNode &node)
796{
797	const char attr1[] = "StorageKit::SomeAttribute";
798	const char attr2[] = "StorageKit::AnotherAttribute";
799
800	CPPUNIT_ASSERT( node.SetTo("./") == B_OK );
801
802	// Test the case of the first attribute not existing
803	node.RemoveAttr(attr1);
804
805#if 1
806	// The actual tests in the else block below are disabled because as of
807	// right now, BFS doesn't support attribute rename. bfs_rename_attr()
808	// always reutrns B_NOT_SUPPORTED, which means BNode::RenameAttr() will
809	// also always return that result.
810	//
811	// So until that is implemented, we'll just test for B_NOT_SUPPORTED here.
812	// Once that functionality is implemented, this test will pass and someone
813	// can remove this section.
814	CPPUNIT_ASSERT_EQUAL(node.RenameAttr(attr1, attr2), B_NOT_SUPPORTED);
815#else
816	const char str[] = "This is my testing string and it rules your world.";
817	const int strLen = strlen(str) + 1;
818	const int dataLen = 1024;
819	char data[dataLen];
820
821	CPPUNIT_ASSERT( node.RenameAttr(attr1, attr2) == B_BAD_VALUE );
822
823	// Write an attribute, read it to verify it, rename it, read the
824	// new attribute, read the old (which fails), and then remove the new.
825	CPPUNIT_ASSERT( node.WriteAttr(attr1, B_STRING_TYPE, 0, str, strLen) == strLen );
826	CPPUNIT_ASSERT( node.ReadAttr(attr1, B_STRING_TYPE, 0, data, dataLen) == strLen );
827	CPPUNIT_ASSERT( strcmp(data, str) == 0 );
828	CPPUNIT_ASSERT( node.RenameAttr(attr1, attr2) == B_OK ); // <<< This fails with R5::BNode
829	CPPUNIT_ASSERT( node.ReadAttr(attr1, B_STRING_TYPE, 0, data, dataLen) == B_ENTRY_NOT_FOUND );
830	CPPUNIT_ASSERT( node.ReadAttr(attr2, B_STRING_TYPE, 0, data, dataLen) == strLen );
831	CPPUNIT_ASSERT( strcmp(data, str) == 0 );
832	CPPUNIT_ASSERT( node.RemoveAttr(attr2) == B_OK );
833
834	// bad args
835	CPPUNIT_ASSERT( equals(node.RenameAttr(attr1, NULL), B_BAD_ADDRESS,
836						   B_BAD_VALUE) );
837	CPPUNIT_ASSERT( equals(node.RenameAttr(NULL, attr2), B_BAD_ADDRESS,
838						   B_BAD_VALUE) );
839	CPPUNIT_ASSERT( equals(node.RenameAttr(NULL, NULL), B_BAD_ADDRESS,
840						   B_BAD_VALUE) );
841	// too long attribute name
842// R5: RenameAttr() returns B_BAD_VALUE instead of B_NAME_TOO_LONG
843	char tooLongAttrName[B_ATTR_NAME_LENGTH + 2];
844	memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH);
845	tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = '\0';
846	CPPUNIT_ASSERT( node.RenameAttr(attr1, tooLongAttrName)
847					== B_BAD_VALUE );
848	CPPUNIT_ASSERT( node.RenameAttr(tooLongAttrName, attr1)
849					== B_BAD_VALUE );
850#endif
851}
852
853
854// AttrRenameTest
855void
856NodeTest::AttrRenameTest()
857{
858	// uninitialized objects
859	NextSubTest();
860	TestNodes testEntries;
861	CreateUninitializedNodes(testEntries);
862	BNode *node;
863	string nodeName;
864	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
865		CPPUNIT_ASSERT( node->RenameAttr("attr1", "attr2") == B_FILE_ERROR );
866	}
867	testEntries.delete_all();
868	// existing entries
869	NextSubTest();
870	CreateRWNodes(testEntries);
871	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
872		AttrRenameTest(*node);
873	}
874	testEntries.delete_all();
875}
876
877// AttrInfoTest
878void
879NodeTest::AttrInfoTest(BNode &node)
880{
881	// add some attributes
882	const char *attrNames[] = {
883		"attr1", "attr2", "attr3", "attr4", "attr5"
884	};
885	const int32 attrCount = sizeof(attrNames) / sizeof(const char*);
886	const char attrValue1[] = "This is the greatest string ever.";
887	int32 attrValue2 = 17;
888	uint64 attrValue3 = 42;
889	double attrValue4 = 435.5;
890	struct flat_entry_ref { dev_t device; ino_t directory; char name[256]; }
891		attrValue5 = { 9, 16, "Hello world!" };
892	const void *attrValues[] = {
893		attrValue1, &attrValue2, &attrValue3, &attrValue4, &attrValue5
894	};
895	attr_info attrInfos[] = {
896		{ B_STRING_TYPE, sizeof(attrValue1) },
897		{ B_INT32_TYPE, sizeof(attrValue2) },
898		{ B_UINT64_TYPE, sizeof(attrValue3) },
899		{ B_DOUBLE_TYPE, sizeof(attrValue4) },
900		{ B_REF_TYPE, sizeof(attrValue5) }
901	};
902	for (int32 i = 0; i < attrCount; i++) {
903		const char *attrName = attrNames[i];
904		const void *attrValue = attrValues[i];
905		int32 valueSize = attrInfos[i].size;
906		uint32 attrType = attrInfos[i].type;
907		CPPUNIT_ASSERT( node.WriteAttr(attrName, attrType, 0, attrValue,
908									   valueSize) == valueSize );
909	}
910	// get the attribute infos
911	for (int32 i = 0; i < attrCount; i++) {
912		const char *attrName = attrNames[i];
913		attr_info info;
914		CPPUNIT_ASSERT( node.GetAttrInfo(attrName, &info) == B_OK );
915		CPPUNIT_ASSERT( info == attrInfos[i] );
916	}
917	// try get an info for a non-existing attribute
918	attr_info info;
919	CPPUNIT_ASSERT( node.GetAttrInfo("non-existing attribute", &info)
920					== B_ENTRY_NOT_FOUND );
921	// bad values
922	CPPUNIT_ASSERT( equals(node.GetAttrInfo(NULL, &info), B_BAD_ADDRESS,
923						   B_BAD_VALUE) );
924	CPPUNIT_ASSERT( equals(node.GetAttrInfo(attrNames[0], NULL), B_BAD_ADDRESS,
925						   B_BAD_VALUE) );
926	CPPUNIT_ASSERT( equals(node.GetAttrInfo(NULL, NULL), B_BAD_ADDRESS,
927						   B_BAD_VALUE) );
928	// too long attribute name
929// R5: GetAttrInfo() does not return B_NAME_TOO_LONG
930	char tooLongAttrName[B_ATTR_NAME_LENGTH + 2];
931	memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH);
932	tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = '\0';
933	CPPUNIT_ASSERT( node.GetAttrInfo(tooLongAttrName, &info)
934					== B_ENTRY_NOT_FOUND );
935}
936
937// AttrInfoTest
938void
939NodeTest::AttrInfoTest()
940{
941	// uninitialized objects
942	NextSubTest();
943	TestNodes testEntries;
944	CreateUninitializedNodes(testEntries);
945	BNode *node;
946	string nodeName;
947	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
948		attr_info info;
949		CPPUNIT_ASSERT( node->GetAttrInfo("attr1", &info) == B_FILE_ERROR );
950	}
951	testEntries.delete_all();
952	// existing entries
953	NextSubTest();
954	CreateRWNodes(testEntries);
955	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
956		AttrInfoTest(*node);
957	}
958	testEntries.delete_all();
959}
960
961// AttrBStringTest
962void
963NodeTest::AttrBStringTest(BNode &node)
964{
965	// add some attributes
966	const char *attrNames[] = {
967		"attr1", "attr2", "attr3", "attr4", "attr5"
968	};
969	const char *attrValues[] = {
970		"value1", "value2", "value3", "value4", "value5"
971	};
972	const char *newAttrValues[] = {
973		"fd", "kkgkjsdhfgkjhsd", "lihuhuh", "", "alkfgnakdfjgn"
974	};
975	int32 attrCount = sizeof(attrNames) / sizeof(const char *);
976	for (int32 i = 0; i < attrCount; i++) {
977		const char *attrName = attrNames[i];
978		BString attrValue(attrValues[i]);
979		CPPUNIT_ASSERT( node.WriteAttrString(attrName, &attrValue) == B_OK );
980	}
981	// read and check them
982	for (int32 i = 0; i < attrCount; i++) {
983		const char *attrName = attrNames[i];
984		const char *attrValue = attrValues[i];
985		BString readValue;
986		CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue) == B_OK );
987		CPPUNIT_ASSERT( readValue == attrValue );
988	}
989	// write a new value for each attribute
990	for (int32 i = 0; i < attrCount; i++) {
991		const char *attrName = attrNames[i];
992		BString attrValue(newAttrValues[i]);
993		CPPUNIT_ASSERT( node.WriteAttrString(attrName, &attrValue) == B_OK );
994	}
995	// read and check them
996	for (int32 i = 0; i < attrCount; i++) {
997		const char *attrName = attrNames[i];
998		const char *attrValue = newAttrValues[i];
999		BString readValue;
1000		CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue) == B_OK );
1001		CPPUNIT_ASSERT( readValue == attrValue );
1002	}
1003	// bad args
1004	BString readValue;
1005	BString writeValue("test");
1006// R5: crashes, if supplying a NULL BString
1007#if !TEST_R5
1008	CPPUNIT_ASSERT( node.WriteAttrString(attrNames[0], NULL) == B_BAD_VALUE );
1009	CPPUNIT_ASSERT( node.ReadAttrString(attrNames[0], NULL) == B_BAD_VALUE );
1010#endif
1011	CPPUNIT_ASSERT( equals(node.WriteAttrString(NULL, &writeValue),
1012						   B_BAD_ADDRESS, B_BAD_VALUE) );
1013	CPPUNIT_ASSERT( equals(node.ReadAttrString(NULL, &readValue),
1014						   B_BAD_ADDRESS, B_BAD_VALUE) );
1015#if !TEST_R5
1016	CPPUNIT_ASSERT( node.WriteAttrString(NULL, NULL) == B_BAD_VALUE );
1017#endif
1018	CPPUNIT_ASSERT( equals(node.ReadAttrString(NULL, NULL),
1019						   B_BAD_ADDRESS, B_BAD_VALUE) );
1020	// remove the attributes and try to read them
1021	for (int32 i = 0; i < attrCount; i++) {
1022		const char *attrName = attrNames[i];
1023		CPPUNIT_ASSERT( node.RemoveAttr(attrName) == B_OK );
1024		CPPUNIT_ASSERT( node.ReadAttrString(attrName, &readValue)
1025						== B_ENTRY_NOT_FOUND );
1026	}
1027	// too long attribute name
1028// R5: Read/WriteAttrString() do not return B_NAME_TOO_LONG
1029	char tooLongAttrName[B_ATTR_NAME_LENGTH + 2];
1030	memset(tooLongAttrName, 'a', B_ATTR_NAME_LENGTH);
1031	tooLongAttrName[B_ATTR_NAME_LENGTH + 1] = '\0';
1032	CPPUNIT_ASSERT( node.WriteAttrString(tooLongAttrName, &writeValue)
1033					== B_BAD_VALUE );
1034	CPPUNIT_ASSERT( node.ReadAttrString(tooLongAttrName, &readValue)
1035					== B_ENTRY_NOT_FOUND );
1036}
1037
1038// AttrBStringTest
1039void
1040NodeTest::AttrBStringTest()
1041{
1042	// uninitialized objects
1043	NextSubTest();
1044	TestNodes testEntries;
1045	CreateUninitializedNodes(testEntries);
1046	BNode *node;
1047	string nodeName;
1048	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1049		BString value("test");
1050		CPPUNIT_ASSERT( node->WriteAttrString("attr1", &value)
1051						== B_FILE_ERROR );
1052		CPPUNIT_ASSERT( node->ReadAttrString("attr1", &value)
1053						== B_FILE_ERROR );
1054	}
1055	testEntries.delete_all();
1056	// existing entries
1057	NextSubTest();
1058	CreateRWNodes(testEntries);
1059	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1060		AttrBStringTest(*node);
1061	}
1062	testEntries.delete_all();
1063}
1064
1065// This doesn't actually verify synching is occuring; just
1066// checks for a B_OK return value.
1067void
1068NodeTest::SyncTest() {
1069	const char attr[] = "StorageKit::SomeAttribute";
1070	const char str[] = "This string rules your world.";
1071	const int len = strlen(str) + 1;
1072	// uninitialized objects
1073	NextSubTest();
1074	TestNodes testEntries;
1075	CreateUninitializedNodes(testEntries);
1076	BNode *node;
1077	string nodeName;
1078	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1079		CPPUNIT_ASSERT( node->Sync() == B_FILE_ERROR );
1080	}
1081	testEntries.delete_all();
1082	// existing entries
1083	NextSubTest();
1084	CreateRWNodes(testEntries);
1085	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1086		CPPUNIT_ASSERT( node->WriteAttr(attr, B_STRING_TYPE, 0, str, len)
1087						== len );
1088		CPPUNIT_ASSERT( node->Sync() == B_OK );
1089	}
1090	testEntries.delete_all();
1091}
1092
1093// DupTest
1094void
1095NodeTest::DupTest(BNode &node)
1096{
1097	int fd = node.Dup();
1098	CPPUNIT_ASSERT( fd != -1 );
1099	::close(fd);
1100}
1101
1102// DupTest
1103void
1104NodeTest::DupTest()
1105{
1106	// uninitialized objects
1107	NextSubTest();
1108	TestNodes testEntries;
1109	CreateUninitializedNodes(testEntries);
1110	BNode *node;
1111	string nodeName;
1112	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1113		CPPUNIT_ASSERT( node->Dup() == -1 );
1114	}
1115	testEntries.delete_all();
1116	// existing entries
1117	NextSubTest();
1118	CreateRWNodes(testEntries);
1119	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1120		DupTest(*node);
1121	}
1122	testEntries.delete_all();
1123}
1124
1125// n1 and n2 should both be uninitialized. y1a and y1b should be initialized
1126// to the same node, y2 should be initialized to a different node
1127void
1128NodeTest::EqualityTest(BNode &n1, BNode &n2, BNode &y1a, BNode &y1b, BNode &y2) {
1129	CPPUNIT_ASSERT( n1 == n2 );
1130	CPPUNIT_ASSERT( !(n1 != n2) );
1131	CPPUNIT_ASSERT( n1 != y2 );
1132	CPPUNIT_ASSERT( !(n1 == y2) );
1133
1134	CPPUNIT_ASSERT( y1a != n2 );
1135	CPPUNIT_ASSERT( !(y1a == n2) );
1136	CPPUNIT_ASSERT( y1a == y1b );
1137	CPPUNIT_ASSERT( !(y1a != y1b) );
1138	CPPUNIT_ASSERT( y1a != y2 );
1139	CPPUNIT_ASSERT( !(y1a == y2) );
1140
1141	CPPUNIT_ASSERT( n1 == n1 );
1142	CPPUNIT_ASSERT( !(n1 != n1) );
1143	CPPUNIT_ASSERT( y2 == y2 );
1144	CPPUNIT_ASSERT( !(y2 != y2) );
1145}
1146
1147// EqualityTest
1148void
1149NodeTest::EqualityTest()
1150{
1151	BNode n1, n2, y1a("/boot"), y1b("/boot"), y2("/");
1152
1153	EqualityTest(n1, n2, y1a, y1b, y2);
1154}
1155
1156// AssignmentTest
1157void
1158NodeTest::AssignmentTest()
1159{
1160	BNode n1, n2, y1a("/boot"), y1b("/boot"), y2("/");
1161
1162	n1 = n1;		// self n
1163	y1a = y1b;		// psuedo self y
1164	y1a = y1a;		// self y
1165	n2 = y2;		// n = y
1166	y1b = n1;		// y = n
1167	y2 = y1a;		// y1 = y2
1168
1169	EqualityTest(n1, y1b, y1a, y2, n2);
1170}
1171
1172// Locking isn't really implemented yet...
1173void
1174NodeTest::LockTest(BNode &node, const char *entryName)
1175{
1176	CPPUNIT_ASSERT( node.Lock() == B_OK );
1177	BNode node2(entryName);
1178	CPPUNIT_ASSERT( node2.InitCheck() == B_BUSY );
1179	CPPUNIT_ASSERT( node.Unlock() == B_OK );
1180	CPPUNIT_ASSERT( node.Unlock() == B_BAD_VALUE );
1181	CPPUNIT_ASSERT( node2.SetTo(entryName) == B_OK );
1182// R5: Since two file descriptors exist at this point, locking is supposed
1183// to fail according to the BeBook, but it succeeds!
1184	CPPUNIT_ASSERT( node2.Lock() == B_OK );
1185	CPPUNIT_ASSERT( node.Lock() == B_BUSY );
1186//
1187	CPPUNIT_ASSERT( node2.Unlock() == B_OK );
1188}
1189
1190// Locking isn't really implemented yet...
1191void
1192NodeTest::LockTest()
1193{
1194	// uninitialized objects
1195	NextSubTest();
1196	TestNodes testEntries;
1197	CreateUninitializedNodes(testEntries);
1198	BNode *node;
1199	string nodeName;
1200	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1201		CPPUNIT_ASSERT( node->Dup() == -1 );
1202	}
1203	testEntries.delete_all();
1204	// existing entries
1205	NextSubTest();
1206	CreateRWNodes(testEntries);
1207	for (testEntries.rewind(); testEntries.getNext(node, nodeName); ) {
1208		LockTest(*node, nodeName.c_str());
1209	}
1210	testEntries.delete_all();
1211}
1212
1213// entry names used in tests
1214const char *NodeTest::existingFilename			= "/tmp/existing-file";
1215const char *NodeTest::existingSuperFilename		= "/tmp";
1216const char *NodeTest::existingRelFilename		= "existing-file";
1217const char *NodeTest::existingDirname			= "/tmp/existing-dir";
1218const char *NodeTest::existingSuperDirname		= "/tmp";
1219const char *NodeTest::existingRelDirname		= "existing-dir";
1220const char *NodeTest::existingSubDirname
1221	= "/tmp/existing-dir/existing-subdir";
1222const char *NodeTest::existingRelSubDirname		= "existing-subdir";
1223const char *NodeTest::nonExistingFilename		= "/tmp/non-existing-file";
1224const char *NodeTest::nonExistingDirname		= "/tmp/non-existing-dir";
1225const char *NodeTest::nonExistingSuperDirname	= "/tmp";
1226const char *NodeTest::nonExistingRelDirname		= "non-existing-dir";
1227const char *NodeTest::testFilename1				= "/tmp/test-file1";
1228const char *NodeTest::testDirname1				= "/tmp/test-dir1";
1229const char *NodeTest::tooLongEntryname			=
1230	"/tmp/This is an awfully long name for an entry. It is that kind of entry "
1231	"that just can't exist due to its long name. In fact its path name is not "
1232	"too long -- a path name can contain 1024 characters -- but the name of "
1233	"the entry itself is restricted to 256 characters, which this entry's "
1234	"name does exceed.";
1235const char *NodeTest::tooLongSuperEntryname		= "/tmp";
1236const char *NodeTest::tooLongRelEntryname		=
1237	"This is an awfully long name for an entry. It is that kind of entry "
1238	"that just can't exist due to its long name. In fact its path name is not "
1239	"too long -- a path name can contain 1024 characters -- but the name of "
1240	"the entry itself is restricted to 256 characters, which this entry's "
1241	"name does exceed.";
1242const char *NodeTest::fileDirname				= "/tmp/test-file1/some-dir";
1243const char *NodeTest::fileSuperDirname			= "/tmp";
1244const char *NodeTest::fileRelDirname			= "test-file1/some-dir";
1245const char *NodeTest::dirLinkname				= "/tmp/link-to-dir1";
1246const char *NodeTest::dirSuperLinkname			= "/tmp";
1247const char *NodeTest::dirRelLinkname			= "link-to-dir1";
1248const char *NodeTest::fileLinkname				= "/tmp/link-to-file1";
1249const char *NodeTest::fileSuperLinkname			= "/tmp";
1250const char *NodeTest::fileRelLinkname			= "link-to-file1";
1251const char *NodeTest::relDirLinkname			= "/tmp/rel-link-to-dir1";
1252const char *NodeTest::relFileLinkname			= "/tmp/rel-link-to-file1";
1253const char *NodeTest::badLinkname				= "/tmp/link-to-void";
1254const char *NodeTest::cyclicLinkname1			= "/tmp/cyclic-link1";
1255const char *NodeTest::cyclicLinkname2			= "/tmp/cyclic-link2";
1256
1257const char *NodeTest::allFilenames[] = {
1258	existingFilename,
1259	existingDirname,
1260	nonExistingFilename,
1261	nonExistingDirname,
1262	testFilename1,
1263	testDirname1,
1264	dirLinkname,
1265	fileLinkname,
1266	relDirLinkname,
1267	relFileLinkname,
1268	badLinkname,
1269	cyclicLinkname1,
1270	cyclicLinkname2,
1271};
1272const int32 NodeTest::allFilenameCount
1273	= sizeof(allFilenames) / sizeof(const char*);
1274
1275