xref: /haiku/src/tests/kits/storage/NodeTest.cpp (revision ee8cf35f07e207a2c17ba3c7d350a252c33e9497)
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
operator ==(const attr_info & info1,const attr_info & info2)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*
Suite()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 	// 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
64 static
65 void
ConvertTestStatablesToNodes(TestNodes & testNodes,TestStatables & testStatables)66 ConvertTestStatablesToNodes(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
76 void
CreateROStatables(TestStatables & testEntries)77 NodeTest::CreateROStatables(TestStatables& testEntries)
78 {
79 	TestNodes testNodes;
80 	CreateRONodes(testNodes);
81 	ConvertTestStatablesToNodes(testNodes, testEntries);
82 }
83 
84 // CreateRWStatables
85 void
CreateRWStatables(TestStatables & testEntries)86 NodeTest::CreateRWStatables(TestStatables& testEntries)
87 {
88 	TestNodes testNodes;
89 	CreateRWNodes(testNodes);
90 	ConvertTestStatablesToNodes(testNodes, testEntries);
91 }
92 
93 // CreateUninitializedStatables
94 void
CreateUninitializedStatables(TestStatables & testEntries)95 NodeTest::CreateUninitializedStatables(TestStatables& testEntries)
96 {
97 	TestNodes testNodes;
98 	CreateUninitializedNodes(testNodes);
99 	ConvertTestStatablesToNodes(testNodes, testEntries);
100 }
101 
102 // CreateRONodes
103 void
CreateRONodes(TestNodes & testEntries)104 NodeTest::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
126 void
CreateRWNodes(TestNodes & testEntries)127 NodeTest::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
149 void
CreateUninitializedNodes(TestNodes & testEntries)150 NodeTest::CreateUninitializedNodes(TestNodes& testEntries)
151 {
152 	testEntries.add(new BNode, "");
153 }
154 
155 // setUp
156 void
setUp()157 NodeTest::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
175 void
tearDown()176 NodeTest::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
188 void
InitTest1()189 NodeTest::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
419 void
InitTest2()420 NodeTest::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
592 static
593 void
WriteAttributes(BNode & node,const char ** attrNames,const char ** attrValues,int32 attrCount)594 WriteAttributes(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
607 void
AttrDirTest(BNode & node)608 NodeTest::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
654 void
AttrDirTest()655 NodeTest::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
679 void
AttrTest(BNode & node)680 NodeTest::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
766 void
AttrTest()767 NodeTest::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
794 void
AttrRenameTest(BNode & node)795 NodeTest::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
855 void
AttrRenameTest()856 NodeTest::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
878 void
AttrInfoTest(BNode & node)879 NodeTest::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
938 void
AttrInfoTest()939 NodeTest::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
962 void
AttrBStringTest(BNode & node)963 NodeTest::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
1039 void
AttrBStringTest()1040 NodeTest::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.
1067 void
SyncTest()1068 NodeTest::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
1094 void
DupTest(BNode & node)1095 NodeTest::DupTest(BNode &node)
1096 {
1097 	int fd = node.Dup();
1098 	CPPUNIT_ASSERT( fd != -1 );
1099 	::close(fd);
1100 }
1101 
1102 // DupTest
1103 void
DupTest()1104 NodeTest::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
1127 void
EqualityTest(BNode & n1,BNode & n2,BNode & y1a,BNode & y1b,BNode & y2)1128 NodeTest::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
1148 void
EqualityTest()1149 NodeTest::EqualityTest()
1150 {
1151 	BNode n1, n2, y1a("/boot"), y1b("/boot"), y2("/");
1152 
1153 	EqualityTest(n1, n2, y1a, y1b, y2);
1154 }
1155 
1156 // AssignmentTest
1157 void
AssignmentTest()1158 NodeTest::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...
1173 void
LockTest(BNode & node,const char * entryName)1174 NodeTest::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...
1191 void
LockTest()1192 NodeTest::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
1214 const char *NodeTest::existingFilename			= "/tmp/existing-file";
1215 const char *NodeTest::existingSuperFilename		= "/tmp";
1216 const char *NodeTest::existingRelFilename		= "existing-file";
1217 const char *NodeTest::existingDirname			= "/tmp/existing-dir";
1218 const char *NodeTest::existingSuperDirname		= "/tmp";
1219 const char *NodeTest::existingRelDirname		= "existing-dir";
1220 const char *NodeTest::existingSubDirname
1221 	= "/tmp/existing-dir/existing-subdir";
1222 const char *NodeTest::existingRelSubDirname		= "existing-subdir";
1223 const char *NodeTest::nonExistingFilename		= "/tmp/non-existing-file";
1224 const char *NodeTest::nonExistingDirname		= "/tmp/non-existing-dir";
1225 const char *NodeTest::nonExistingSuperDirname	= "/tmp";
1226 const char *NodeTest::nonExistingRelDirname		= "non-existing-dir";
1227 const char *NodeTest::testFilename1				= "/tmp/test-file1";
1228 const char *NodeTest::testDirname1				= "/tmp/test-dir1";
1229 const 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.";
1235 const char *NodeTest::tooLongSuperEntryname		= "/tmp";
1236 const 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.";
1242 const char *NodeTest::fileDirname				= "/tmp/test-file1/some-dir";
1243 const char *NodeTest::fileSuperDirname			= "/tmp";
1244 const char *NodeTest::fileRelDirname			= "test-file1/some-dir";
1245 const char *NodeTest::dirLinkname				= "/tmp/link-to-dir1";
1246 const char *NodeTest::dirSuperLinkname			= "/tmp";
1247 const char *NodeTest::dirRelLinkname			= "link-to-dir1";
1248 const char *NodeTest::fileLinkname				= "/tmp/link-to-file1";
1249 const char *NodeTest::fileSuperLinkname			= "/tmp";
1250 const char *NodeTest::fileRelLinkname			= "link-to-file1";
1251 const char *NodeTest::relDirLinkname			= "/tmp/rel-link-to-dir1";
1252 const char *NodeTest::relFileLinkname			= "/tmp/rel-link-to-file1";
1253 const char *NodeTest::badLinkname				= "/tmp/link-to-void";
1254 const char *NodeTest::cyclicLinkname1			= "/tmp/cyclic-link1";
1255 const char *NodeTest::cyclicLinkname2			= "/tmp/cyclic-link2";
1256 
1257 const 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 };
1272 const int32 NodeTest::allFilenameCount
1273 	= sizeof(allFilenames) / sizeof(const char*);
1274 
1275