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