1// NodeInfoTest.cpp
2
3#include <stdio.h>
4#include <string.h>
5#include <unistd.h>
6
7#include <string>
8using std::string;
9
10#include <Application.h>
11#include <Bitmap.h>
12#include <Directory.h>
13#include <Entry.h>
14#include <fs_attr.h>
15#include <Node.h>
16#include <NodeInfo.h>
17#include <Path.h>
18#include <TypeConstants.h>
19#include <MimeTypes.h>
20
21#include <cppunit/Test.h>
22#include <cppunit/TestCaller.h>
23#include <cppunit/TestSuite.h>
24#include <TestShell.h>
25#include <TestUtils.h>
26#include <cppunit/TestAssert.h>
27
28#include "NodeInfoTest.h"
29#include "../app/bmessenger/Helpers.h"
30
31// test dirs/files/types
32static const char *testDir			= "/tmp/testDir";
33static const char *testFile1		= "/tmp/testDir/file1";
34static const char *testFile2		= "/tmp/testDir/file2";
35static const char *testFile3		= "/tmp/testDir/file3";
36static const char *testFile4		= "/tmp/testDir/file4";
37static const char *abstractTestEntry = "/tmp/testDir/abstract-entry";
38static const char *testType1		= "application/x-vnd.obos.node-info-test1";
39static const char *testType2		= "application/x-vnd.obos.node-info-test2";
40static const char *invalidTestType	= "invalid-mime-type";
41static const char *tooLongTestType	=
42"0123456789012345678901234567890123456789012345678901234567890123456789"
43"0123456789012345678901234567890123456789012345678901234567890123456789"
44"0123456789012345678901234567890123456789012345678901234567890123456789"
45"0123456789012345678901234567890123456789012345678901234567890123456789"
46;
47static const char *testAppSignature1
48	= "application/x-vnd.obos.node-info-test-app1";
49static const char *testAppSignature2
50	= "application/x-vnd.obos.node-info-test-app2";
51
52
53// attributes
54static const char *kTypeAttribute			= "BEOS:TYPE";
55static const char *kMiniIconAttribute		= "BEOS:M:STD_ICON";
56static const char *kLargeIconAttribute		= "BEOS:L:STD_ICON";
57static const char *kPreferredAppAttribute	= "BEOS:PREF_APP";
58static const char *kAppHintAttribute		= "BEOS:PPATH";
59
60enum {
61	MINI_ICON_TYPE	= 'MICN',
62	LARGE_ICON_TYPE	= 'ICON',
63};
64
65// create_test_icon
66static
67BBitmap *
68create_test_icon(icon_size size, int fill)
69{
70	BBitmap *icon = NULL;
71	// create
72	switch (size) {
73		case B_MINI_ICON:
74			icon = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
75			break;
76		case B_LARGE_ICON:
77			icon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
78			break;
79	}
80	// fill
81	if (icon)
82		memset(icon->Bits(), fill, icon->BitsLength());
83	return icon;
84}
85
86// icon_equal
87static
88bool
89icon_equal(const BBitmap *icon1, const BBitmap *icon2)
90{
91	return (icon1->Bounds() == icon2->Bounds()
92			&& icon1->BitsLength() == icon2->BitsLength()
93			&& memcmp(icon1->Bits(), icon2->Bits(), icon1->BitsLength()) == 0);
94}
95
96
97// Suite
98CppUnit::Test*
99NodeInfoTest::Suite() {
100	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
101	typedef CppUnit::TestCaller<NodeInfoTest> TC;
102
103	suite->addTest( new TC("BNodeInfo::Init Test1", &NodeInfoTest::InitTest1) );
104	suite->addTest( new TC("BNodeInfo::Init Test2", &NodeInfoTest::InitTest2) );
105	suite->addTest( new TC("BNodeInfo::Type Test", &NodeInfoTest::TypeTest) );
106	suite->addTest( new TC("BNodeInfo::Icon Test", &NodeInfoTest::IconTest) );
107	suite->addTest( new TC("BNodeInfo::Preferred App Test",
108						   &NodeInfoTest::PreferredAppTest) );
109	suite->addTest( new TC("BNodeInfo::App Hint Test",
110						   &NodeInfoTest::AppHintTest) );
111	suite->addTest( new TC("BNodeInfo::Tracker Icon Test",
112						   &NodeInfoTest::TrackerIconTest) );
113
114	return suite;
115}
116
117// setUp
118void
119NodeInfoTest::setUp()
120{
121	BasicTest::setUp();
122	// create test dir and files
123	execCommand(
124		string("mkdir ") + testDir
125		+ "; touch " + testFile1
126			   + " " + testFile2
127			   + " " + testFile3
128			   + " " + testFile4
129	);
130	// create app
131	fApplication = new BApplication("application/x-vnd.obos.node-info-test");
132	// create icons
133	fIconM1 = create_test_icon(B_MINI_ICON, 1);
134	fIconM2 = create_test_icon(B_MINI_ICON, 2);
135	fIconM3 = create_test_icon(B_MINI_ICON, 3);
136	fIconM4 = create_test_icon(B_MINI_ICON, 4);
137	fIconL1 = create_test_icon(B_LARGE_ICON, 1);
138	fIconL2 = create_test_icon(B_LARGE_ICON, 2);
139	fIconL3 = create_test_icon(B_LARGE_ICON, 3);
140	fIconL4 = create_test_icon(B_LARGE_ICON, 4);
141}
142
143// tearDown
144void
145NodeInfoTest::tearDown()
146{
147	// delete the icons
148	delete fIconM1;
149	delete fIconM2;
150	delete fIconM3;
151	delete fIconM4;
152	delete fIconL1;
153	delete fIconL2;
154	delete fIconL3;
155	delete fIconL4;
156	fIconM1 = fIconM2 = fIconL1 = fIconL2 = NULL;
157	// delete the application
158	delete fApplication;
159	fApplication = NULL;
160	// remove the types we've added
161	const char * const testTypes[] = {
162		testType1, testType2, testAppSignature1, testAppSignature2
163	};
164	for (uint32 i = 0; i < sizeof(testTypes) / sizeof(const char*); i++) {
165		BMimeType type(testTypes[i]);
166		type.Delete();
167	}
168
169	// delete the test dir
170	execCommand(string("rm -rf ") + testDir);
171
172	BasicTest::tearDown();
173}
174
175// InitTest1
176void
177NodeInfoTest::InitTest1()
178{
179	// BNodeInfo()
180	// * InitCheck() == B_NO_INIT
181	NextSubTest();
182	{
183		BNodeInfo nodeInfo;
184		CHK(nodeInfo.InitCheck() == B_NO_INIT);
185	}
186
187	// BNodeInfo(BNode *node)
188	// * NULL node => InitCheck() == B_BAD_VALUE
189	NextSubTest();
190	{
191		BNodeInfo nodeInfo(NULL);
192		CHK(nodeInfo.InitCheck() == B_BAD_VALUE);
193	}
194	// * invalid node => InitCheck() == B_BAD_VALUE
195	NextSubTest();
196	{
197		BNode node;
198		BNodeInfo nodeInfo(&node);
199		CHK(nodeInfo.InitCheck() == B_BAD_VALUE);
200	}
201	// * valid node => InitCheck() == B_OK
202	NextSubTest();
203	{
204		BNode node(testFile1);
205		BNodeInfo nodeInfo(&node);
206		CHK(nodeInfo.InitCheck() == B_OK);
207	}
208}
209
210// InitTest2
211void
212NodeInfoTest::InitTest2()
213{
214	// status_t SetTo(BNode *node)
215	// * NULL node => InitCheck() == B_NO_INIT
216	NextSubTest();
217	{
218		BNodeInfo nodeInfo;
219		CHK(nodeInfo.SetTo(NULL) == B_BAD_VALUE);
220		CHK(nodeInfo.InitCheck() == B_BAD_VALUE);
221	}
222	// * invalid node => InitCheck() == B_BAD_VALUE
223	NextSubTest();
224	{
225		BNode node;
226		BNodeInfo nodeInfo;
227		CHK(nodeInfo.SetTo(&node) == B_BAD_VALUE);
228		CHK(nodeInfo.InitCheck() == B_BAD_VALUE);
229	}
230	// * valid node => InitCheck() == B_OK
231	// * reinitialize invalid/valid => InitCheck() == B_BAD_VALUE/B_OK
232	NextSubTest();
233	{
234		BNode node(testFile1);
235		BNodeInfo nodeInfo;
236		CHK(nodeInfo.SetTo(&node) == B_OK);
237		CHK(nodeInfo.InitCheck() == B_OK);
238		// reinit with NULL node
239		CHK(nodeInfo.SetTo(NULL) == B_BAD_VALUE);
240		CHK(nodeInfo.InitCheck() == B_BAD_VALUE);
241		// reinit with valid node
242		BNode node2(testFile2);
243		CHK(nodeInfo.SetTo(&node2) == B_OK);
244		CHK(nodeInfo.InitCheck() == B_OK);
245	}
246}
247
248// CheckAttr
249static
250void
251CheckAttr(BNode &node, const char *name, type_code type, const void *data,
252		  int32 dataSize)
253{
254	attr_info info;
255	CHK(node.GetAttrInfo(name, &info) == B_OK);
256	CHK(info.type == type);
257	CHK(info.size == dataSize);
258	char *buffer = new char[dataSize];
259	AutoDeleter<char> deleter(buffer, true);
260	CHK(node.ReadAttr(name, type, 0, buffer, dataSize) == dataSize);
261	CHK(memcmp(buffer, data, dataSize) == 0);
262}
263
264// CheckNoAttr
265static
266void
267CheckNoAttr(BNode &node, const char *name)
268{
269	attr_info info;
270	CHK(node.GetAttrInfo(name, &info) == B_ENTRY_NOT_FOUND);
271}
272
273// CheckStringAttr
274/*static
275void
276CheckStringAttr(BNode &node, const char *name, const char *data)
277{
278	CheckAttr(node, name, B_STRING_TYPE, data, strlen(data) + 1);
279}*/
280
281// CheckTypeAttr
282static
283void
284CheckTypeAttr(BNode &node, const char *data)
285{
286	CheckAttr(node, kTypeAttribute, B_MIME_STRING_TYPE, data,
287			  strlen(data) + 1);
288}
289
290// CheckIconAttr
291static
292void
293CheckIconAttr(BNode &node, BBitmap *data)
294{
295	const char *attribute = NULL;
296	uint32 type = 0;
297	switch (data->Bounds().IntegerWidth()) {
298		case 15:
299			attribute = kMiniIconAttribute;
300			type = MINI_ICON_TYPE;
301			break;
302		case 31:
303			attribute = kLargeIconAttribute;
304			type = LARGE_ICON_TYPE;
305			break;
306		default:
307			CHK(false);
308			break;
309	}
310	CheckAttr(node, attribute, type, data->Bits(), data->BitsLength());
311}
312
313// CheckPreferredAppAttr
314static
315void
316CheckPreferredAppAttr(BNode &node, const char *data)
317{
318	CheckAttr(node, kPreferredAppAttribute, B_MIME_STRING_TYPE, data,
319			  strlen(data) + 1);
320}
321
322// CheckAppHintAttr
323static
324void
325CheckAppHintAttr(BNode &node, const entry_ref *ref)
326{
327	BPath path;
328	CHK(path.SetTo(ref) == B_OK);
329	const char *data = path.Path();
330// R5: Attribute is of type B_MIME_STRING_TYPE though it contains a path name!
331	CheckAttr(node, kAppHintAttribute, B_MIME_STRING_TYPE, data,
332			  strlen(data) + 1);
333}
334
335// TypeTest
336void
337NodeInfoTest::TypeTest()
338{
339	// status_t GetType(char *type) const
340	// * NULL type => B_BAD_ADDRESS/B_BAD_VALUE
341	NextSubTest();
342	{
343		BNode node(testFile1);
344		BNodeInfo nodeInfo;
345		CHK(nodeInfo.SetTo(&node) == B_OK);
346		CHK(equals(nodeInfo.GetType(NULL), B_BAD_ADDRESS, B_BAD_VALUE));
347	}
348	// * uninitialized => B_NO_INIT
349	NextSubTest();
350	{
351		BNodeInfo nodeInfo;
352		char type[B_MIME_TYPE_LENGTH];
353		CHK(nodeInfo.GetType(type) == B_NO_INIT);
354	}
355	// * has no type => B_ENTRY_NOT_FOUND
356	NextSubTest();
357	{
358		BNode node(testFile1);
359		BNodeInfo nodeInfo;
360		CHK(nodeInfo.SetTo(&node) == B_OK);
361		char type[B_MIME_TYPE_LENGTH];
362		CHK(nodeInfo.GetType(type) == B_ENTRY_NOT_FOUND);
363	}
364	// * set, get, reset, get
365	NextSubTest();
366	{
367		BNode node(testFile1);
368		BNodeInfo nodeInfo;
369		CHK(nodeInfo.SetTo(&node) == B_OK);
370		// set
371		CHK(nodeInfo.SetType(testType1) == B_OK);
372		// get
373		char type[B_MIME_TYPE_LENGTH];
374		CHK(nodeInfo.GetType(type) == B_OK);
375		CHK(strcmp(testType1, type) == 0);
376		CheckTypeAttr(node, testType1);
377		// reset
378		CHK(nodeInfo.SetType(testType2) == B_OK);
379		// get
380		CHK(nodeInfo.GetType(type) == B_OK);
381		CHK(strcmp(testType2, type) == 0);
382		CheckTypeAttr(node, testType2);
383	}
384
385	// status_t SetType(const char *type)
386	// * NULL type => B_OK, unsets the type
387	NextSubTest();
388	{
389		BNode node(testFile1);
390		BNodeInfo nodeInfo;
391		CHK(nodeInfo.SetTo(&node) == B_OK);
392		CHK(nodeInfo.SetType(NULL) == B_OK);
393		// get
394		char type[B_MIME_TYPE_LENGTH];
395		CHK(nodeInfo.GetType(type) == B_ENTRY_NOT_FOUND);
396		CheckNoAttr(node, kTypeAttribute);
397	}
398	// * uninitialized => B_NO_INIT
399	NextSubTest();
400	{
401		BNodeInfo nodeInfo;
402		CHK(nodeInfo.SetType(testType1) == B_NO_INIT);
403	}
404	// * invalid MIME type => B_OK
405	NextSubTest();
406	{
407		BNode node(testFile1);
408		BNodeInfo nodeInfo;
409		CHK(nodeInfo.SetTo(&node) == B_OK);
410		CHK(nodeInfo.SetType(invalidTestType) == B_OK);
411		// get
412		char type[B_MIME_TYPE_LENGTH];
413		CHK(nodeInfo.GetType(type) == B_OK);
414		CHK(strcmp(invalidTestType, type) == 0);
415		CheckTypeAttr(node, invalidTestType);
416	}
417	// * type string too long => B_OK/B_BAD_VALUE
418	NextSubTest();
419	{
420		BNode node(testFile1);
421		BNodeInfo nodeInfo;
422		CHK(nodeInfo.SetTo(&node) == B_OK);
423		// remove attr first
424		CHK(nodeInfo.SetType(NULL) == B_OK);
425// R5: Doesn't complain when setting a too long string.
426// Haiku: Handles this as an error case.
427#ifdef TEST_R5
428		CHK(nodeInfo.SetType(tooLongTestType) == B_OK);
429		// get
430		char type[1024];
431		CHK(nodeInfo.GetType(type) == B_OK);
432// R5: Returns a string one character shorter than the original string
433//		CHK(strcmp(tooLongTestType, type) == 0);
434		CheckTypeAttr(node, tooLongTestType);
435#else
436		CHK(nodeInfo.SetType(tooLongTestType) == B_BAD_VALUE);
437		CheckNoAttr(node, kTypeAttribute);
438#endif
439	}
440}
441
442// IconTest
443void
444NodeInfoTest::IconTest()
445{
446	// status_t GetIcon(BBitmap *icon, icon_size k) const
447	// * NULL icon => B_BAD_VALUE
448// R5: Crashes when passing a NULL icon.
449#ifndef TEST_R5
450	NextSubTest();
451	{
452		BNode node(testFile1);
453		BNodeInfo nodeInfo;
454		CHK(nodeInfo.SetTo(&node) == B_OK);
455		CHK(nodeInfo.GetIcon(NULL, B_MINI_ICON) == B_BAD_VALUE);
456		CHK(nodeInfo.GetIcon(NULL, B_LARGE_ICON) == B_BAD_VALUE);
457	}
458#endif
459	// * uninitialized => B_NO_INIT
460	NextSubTest();
461	{
462		BNodeInfo nodeInfo;
463		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
464		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_NO_INIT);
465		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
466		CHK(nodeInfo.GetIcon(&icon2, B_LARGE_ICON) == B_NO_INIT);
467	}
468	// * icon dimensions != icon size => B_BAD_VALUE
469	NextSubTest();
470	{
471		BNode node(testFile1);
472		BNodeInfo nodeInfo;
473		CHK(nodeInfo.SetTo(&node) == B_OK);
474		BBitmap icon(BRect(0, 0, 31, 31), B_CMAP8);
475		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_BAD_VALUE);
476		BBitmap icon2(BRect(0, 0, 15, 15), B_CMAP8);
477		CHK(nodeInfo.GetIcon(&icon2, B_LARGE_ICON) == B_BAD_VALUE);
478	}
479	// * has no icon => B_ENTRY_NOT_FOUND
480	NextSubTest();
481	{
482		BNode node(testFile1);
483		BNodeInfo nodeInfo;
484		CHK(nodeInfo.SetTo(&node) == B_OK);
485		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
486		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_ENTRY_NOT_FOUND);
487	}
488	// * set, get, reset, get
489	NextSubTest();
490	{
491		BNode node(testFile1);
492		BNodeInfo nodeInfo;
493		CHK(nodeInfo.SetTo(&node) == B_OK);
494		// mini
495		// set
496		CHK(nodeInfo.SetIcon(fIconM1, B_MINI_ICON) == B_OK);
497		// get
498		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
499		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_OK);
500		CHK(icon_equal(fIconM1, &icon));
501		CheckIconAttr(node, fIconM1);
502		// reset
503		CHK(nodeInfo.SetIcon(fIconM2, B_MINI_ICON) == B_OK);
504		// get
505		BBitmap icon2(BRect(0, 0, 15, 15), B_CMAP8);
506		CHK(nodeInfo.GetIcon(&icon2, B_MINI_ICON) == B_OK);
507		CHK(icon_equal(fIconM2, &icon2));
508		CheckIconAttr(node, fIconM2);
509		// large
510		// set
511		CHK(nodeInfo.SetIcon(fIconL1, B_LARGE_ICON) == B_OK);
512		// get
513		BBitmap icon3(BRect(0, 0, 31, 31), B_CMAP8);
514		CHK(nodeInfo.GetIcon(&icon3, B_LARGE_ICON) == B_OK);
515		CHK(icon_equal(fIconL1, &icon3));
516		CheckIconAttr(node, fIconL1);
517		// reset
518		CHK(nodeInfo.SetIcon(fIconL2, B_LARGE_ICON) == B_OK);
519		// get
520		BBitmap icon4(BRect(0, 0, 31, 31), B_CMAP8);
521		CHK(nodeInfo.GetIcon(&icon4, B_LARGE_ICON) == B_OK);
522		CHK(icon_equal(fIconL2, &icon4));
523		CheckIconAttr(node, fIconL2);
524	}
525	// * bitmap color_space != B_CMAP8 => B_OK
526	NextSubTest();
527	{
528		BNode node(testFile1);
529		BNodeInfo nodeInfo;
530		CHK(nodeInfo.SetTo(&node) == B_OK);
531		// mini
532		BBitmap icon(BRect(0, 0, 15, 15), B_RGB32);
533		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_OK);
534		BBitmap icon2(BRect(0, 0, 15, 15), B_RGB32);
535		// SetBits() can be used, since there's no row padding for 16x16.
536		icon2.SetBits(fIconM2->Bits(), fIconM2->BitsLength(), 0, B_CMAP8);
537		CHK(icon_equal(&icon, &icon2));
538		// large
539// R5: Crashes for some weird reason in GetIcon().
540#ifndef TEST_R5
541		BBitmap icon3(BRect(0, 0, 31, 31), B_RGB32);
542		CHK(nodeInfo.GetIcon(&icon3, B_LARGE_ICON) == B_OK);
543		BBitmap icon4(BRect(0, 0, 31, 31), B_RGB32);
544		// SetBits() can be used, since there's no row padding for 32x32.
545		icon4.SetBits(fIconL2->Bits(), fIconL2->BitsLength(), 0, B_CMAP8);
546		CHK(icon_equal(&icon3, &icon4));
547#endif
548	}
549
550	// status_t SetIcon(const BBitmap *icon, icon_size k)
551	// * NULL icon => unsets icon, B_OK
552	NextSubTest();
553	{
554		BNode node(testFile1);
555		BNodeInfo nodeInfo;
556		CHK(nodeInfo.SetTo(&node) == B_OK);
557		// mini
558		// set
559		CHK(nodeInfo.SetIcon(NULL, B_MINI_ICON) == B_OK);
560		// get
561		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
562		CHK(nodeInfo.GetIcon(&icon, B_MINI_ICON) == B_ENTRY_NOT_FOUND);
563		CheckNoAttr(node, kMiniIconAttribute);
564		// large
565		// set
566		CHK(nodeInfo.SetIcon(NULL, B_LARGE_ICON) == B_OK);
567		// get
568		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
569		CHK(nodeInfo.GetIcon(&icon2, B_LARGE_ICON) == B_ENTRY_NOT_FOUND);
570		CheckNoAttr(node, kLargeIconAttribute);
571	}
572	// * uninitialized => B_NO_INIT
573	NextSubTest();
574	{
575		BNodeInfo nodeInfo;
576		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
577		CHK(nodeInfo.SetIcon(&icon, B_MINI_ICON) == B_NO_INIT);
578		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
579		CHK(nodeInfo.SetIcon(&icon2, B_LARGE_ICON) == B_NO_INIT);
580	}
581	// * icon dimensions != icon size => B_BAD_VALUE
582	NextSubTest();
583	{
584		BNode node(testFile1);
585		BNodeInfo nodeInfo;
586		CHK(nodeInfo.SetTo(&node) == B_OK);
587		BBitmap icon(BRect(0, 0, 31, 31), B_CMAP8);
588		CHK(nodeInfo.SetIcon(&icon, B_MINI_ICON) == B_BAD_VALUE);
589		BBitmap icon2(BRect(0, 0, 15, 15), B_CMAP8);
590		CHK(nodeInfo.SetIcon(&icon2, B_LARGE_ICON) == B_BAD_VALUE);
591	}
592}
593
594// PreferredAppTest
595void
596NodeInfoTest::PreferredAppTest()
597{
598	// status_t GetPreferredApp(char *signature, app_verb verb = B_OPEN) const
599	// * NULL signature => B_BAD_ADDRESS/B_BAD_VALUE
600	NextSubTest();
601	{
602		BNode node(testFile1);
603		BNodeInfo nodeInfo;
604		CHK(nodeInfo.SetTo(&node) == B_OK);
605		CHK(equals(nodeInfo.GetPreferredApp(NULL), B_BAD_ADDRESS,
606				   B_BAD_VALUE));
607	}
608	// * uninitialized => B_NO_INIT
609	NextSubTest();
610	{
611		BNodeInfo nodeInfo;
612		char signature[B_MIME_TYPE_LENGTH];
613		CHK(nodeInfo.GetPreferredApp(signature) == B_NO_INIT);
614	}
615	// * has no preferred app => B_ENTRY_NOT_FOUND
616	NextSubTest();
617	{
618		BNode node(testFile1);
619		BNodeInfo nodeInfo;
620		CHK(nodeInfo.SetTo(&node) == B_OK);
621		char signature[B_MIME_TYPE_LENGTH];
622		CHK(nodeInfo.GetPreferredApp(signature) == B_ENTRY_NOT_FOUND);
623	}
624	// * set, get, reset, get
625	NextSubTest();
626	{
627		BNode node(testFile1);
628		BNodeInfo nodeInfo;
629		CHK(nodeInfo.SetTo(&node) == B_OK);
630		// set
631		CHK(nodeInfo.SetPreferredApp(testAppSignature1) == B_OK);
632		// get
633		char signature[B_MIME_TYPE_LENGTH];
634		CHK(nodeInfo.GetPreferredApp(signature) == B_OK);
635		CHK(strcmp(testAppSignature1, signature) == 0);
636		CheckPreferredAppAttr(node, testAppSignature1);
637		// reset
638		CHK(nodeInfo.SetPreferredApp(testAppSignature2) == B_OK);
639		// get
640		CHK(nodeInfo.GetPreferredApp(signature) == B_OK);
641		CHK(strcmp(testAppSignature2, signature) == 0);
642		CheckPreferredAppAttr(node, testAppSignature2);
643	}
644
645	// status_t SetPreferredApp(const char *signature, app_verb verb = B_OPEN)
646	// * NULL signature => unsets the preferred app
647	NextSubTest();
648	{
649		BNode node(testFile1);
650		BNodeInfo nodeInfo;
651		CHK(nodeInfo.SetTo(&node) == B_OK);
652		CHK(nodeInfo.SetPreferredApp(NULL) == B_OK);
653		// get
654		char signature[B_MIME_TYPE_LENGTH];
655		CHK(nodeInfo.GetPreferredApp(signature) == B_ENTRY_NOT_FOUND);
656		CheckNoAttr(node, kPreferredAppAttribute);
657	}
658	// * uninitialized => B_NO_INIT
659	NextSubTest();
660	{
661		BNodeInfo nodeInfo;
662		CHK(nodeInfo.SetPreferredApp(testAppSignature1) == B_NO_INIT);
663	}
664	// * invalid MIME type => B_OK
665	NextSubTest();
666	{
667		BNode node(testFile1);
668		BNodeInfo nodeInfo;
669		CHK(nodeInfo.SetTo(&node) == B_OK);
670		CHK(nodeInfo.SetPreferredApp(invalidTestType) == B_OK);
671		// get
672		char signature[B_MIME_TYPE_LENGTH];
673		CHK(nodeInfo.GetPreferredApp(signature) == B_OK);
674		CHK(strcmp(invalidTestType, signature) == 0);
675		CheckPreferredAppAttr(node, invalidTestType);
676	}
677	// * signature string too long => B_BAD_VALUE
678	NextSubTest();
679	{
680		BNode node(testFile1);
681		BNodeInfo nodeInfo;
682		CHK(nodeInfo.SetTo(&node) == B_OK);
683		// unset
684		CHK(nodeInfo.SetPreferredApp(NULL) == B_OK);
685		// try to set
686		CHK(nodeInfo.SetPreferredApp(tooLongTestType) == B_BAD_VALUE);
687		// get
688		char signature[1024];
689		CHK(nodeInfo.GetPreferredApp(signature) == B_ENTRY_NOT_FOUND);
690		CheckNoAttr(node, kPreferredAppAttribute);
691	}
692}
693
694// AppHintTest
695void
696NodeInfoTest::AppHintTest()
697{
698	// init test refs
699	entry_ref testRef1, testRef2, abstractRef;
700	CHK(get_ref_for_path(testFile3, &testRef1) == B_OK);
701	CHK(get_ref_for_path(testFile4, &testRef2) == B_OK);
702	CHK(get_ref_for_path(abstractTestEntry, &abstractRef) == B_OK);
703
704	// status_t GetAppHint(entry_ref *ref) const
705	// * NULL ref => B_BAD_VALUE
706	NextSubTest();
707	{
708		BNode node(testFile1);
709		BNodeInfo nodeInfo;
710		CHK(nodeInfo.SetTo(&node) == B_OK);
711		CHK(nodeInfo.GetAppHint(NULL) == B_BAD_VALUE);
712	}
713	// * uninitialized => B_NO_INIT
714	NextSubTest();
715	{
716		BNodeInfo nodeInfo;
717		entry_ref ref;
718		CHK(nodeInfo.GetAppHint(&ref) == B_NO_INIT);
719	}
720	// * has no app hint => B_ENTRY_NOT_FOUND
721	NextSubTest();
722	{
723		BNode node(testFile1);
724		BNodeInfo nodeInfo;
725		CHK(nodeInfo.SetTo(&node) == B_OK);
726		entry_ref ref;
727		CHK(nodeInfo.GetAppHint(&ref) == B_ENTRY_NOT_FOUND);
728	}
729	// * set, get, reset, get
730	NextSubTest();
731	{
732		BNode node(testFile1);
733		BNodeInfo nodeInfo;
734		CHK(nodeInfo.SetTo(&node) == B_OK);
735		// set
736		CHK(nodeInfo.SetAppHint(&testRef1) == B_OK);
737		// get
738		entry_ref ref;
739		CHK(nodeInfo.GetAppHint(&ref) == B_OK);
740		CHK(ref == testRef1);
741		CheckAppHintAttr(node, &testRef1);
742		// reset
743		CHK(nodeInfo.SetAppHint(&testRef2) == B_OK);
744		// get
745		CHK(nodeInfo.GetAppHint(&ref) == B_OK);
746		CHK(ref == testRef2);
747		CheckAppHintAttr(node, &testRef2);
748	}
749
750	// status_t SetAppHint(const entry_ref *ref)
751	// * NULL ref => B_OK
752	NextSubTest();
753	{
754		BNode node(testFile1);
755		BNodeInfo nodeInfo;
756		CHK(nodeInfo.SetTo(&node) == B_OK);
757		CHK(nodeInfo.SetAppHint(NULL) == B_OK);
758		// get
759		entry_ref ref;
760		CHK(nodeInfo.GetAppHint(&ref) == B_ENTRY_NOT_FOUND);
761		CheckNoAttr(node, kAppHintAttribute);
762	}
763	// * uninitialized => B_NO_INIT
764	NextSubTest();
765	{
766		BNodeInfo nodeInfo;
767		CHK(nodeInfo.SetAppHint(&testRef1) == B_NO_INIT);
768	}
769	// * invalid/abstract ref => != B_OK
770	NextSubTest();
771	{
772		BNode node(testFile1);
773		BNodeInfo nodeInfo;
774		CHK(nodeInfo.SetTo(&node) == B_OK);
775		// invalid ref
776		entry_ref invalidRef;
777		CHK(nodeInfo.SetAppHint(&invalidRef) != B_OK);
778		// abstract ref
779		CHK(nodeInfo.SetAppHint(&abstractRef) == B_OK);
780		// get
781		entry_ref ref;
782		CHK(nodeInfo.GetAppHint(&ref) == B_OK);
783		CHK(ref == abstractRef);
784		CheckAppHintAttr(node, &abstractRef);
785	}
786}
787
788// TestTrackerIcon
789static
790void
791TestTrackerIcon(BNodeInfo &nodeInfo, entry_ref *ref, icon_size size,
792				BBitmap *expectedIcon)
793{
794	// mini
795	if (size == B_MINI_ICON) {
796		// non-static
797		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
798		CHK(nodeInfo.GetTrackerIcon(&icon, B_MINI_ICON) == B_OK);
799		CHK(icon_equal(expectedIcon, &icon));
800		// static
801		BBitmap icon1(BRect(0, 0, 15, 15), B_CMAP8);
802		CHK(BNodeInfo::GetTrackerIcon(ref, &icon1, B_MINI_ICON) == B_OK);
803		CHK(icon_equal(expectedIcon, &icon1));
804	} else {
805		// large
806		// non-static
807		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
808		CHK(nodeInfo.GetTrackerIcon(&icon2, B_LARGE_ICON) == B_OK);
809		CHK(icon_equal(expectedIcon, &icon2));
810		// static
811		BBitmap icon3(BRect(0, 0, 31, 31), B_CMAP8);
812		CHK(BNodeInfo::GetTrackerIcon(ref, &icon3, B_LARGE_ICON) == B_OK);
813		CHK(icon_equal(expectedIcon, &icon3));
814	}
815}
816
817
818static void
819TestTrackerIcon(const char *path, const char *type)
820{
821	// preparation for next tests: get icons for specified type
822	BBitmap miniIcon(BRect(0, 0, 15, 15), B_CMAP8);
823	BBitmap largeIcon(BRect(0, 0, 31, 31), B_CMAP8);
824	BMimeType mimeType(type);
825	CHK(mimeType.GetIcon(&miniIcon, B_MINI_ICON) == B_OK);
826	CHK(mimeType.GetIcon(&largeIcon, B_LARGE_ICON) == B_OK);
827
828	BNode node(path);
829	CHK(node.InitCheck() == B_OK);
830	BEntry entry(path);
831	CHK(entry.InitCheck() == B_OK);
832	entry_ref ref;
833	CHK(entry.GetRef(&ref) == B_OK);
834	BNodeInfo info(&node);
835	CHK(info.InitCheck() == B_OK);
836
837	// test GetTrackerIcon()
838	TestTrackerIcon(info, &ref, B_MINI_ICON, &miniIcon);
839	TestTrackerIcon(info, &ref, B_LARGE_ICON, &largeIcon);
840}
841
842
843// TrackerIconTest
844void
845NodeInfoTest::TrackerIconTest()
846{
847	entry_ref testRef1;
848	CHK(get_ref_for_path(testFile1, &testRef1) == B_OK);
849	BBitmap octetMIcon(BRect(0, 0, 15, 15), B_CMAP8);
850	BBitmap octetLIcon(BRect(0, 0, 31, 31), B_CMAP8);
851	BMimeType octetType(B_FILE_MIME_TYPE);
852	CHK(octetType.GetIcon(&octetMIcon, B_MINI_ICON) == B_OK);
853	CHK(octetType.GetIcon(&octetLIcon, B_LARGE_ICON) == B_OK);
854
855	// static status_t GetTrackerIcon(const entry_ref *ref, BBitmap *icon,
856	//								  icon_size k = B_LARGE_ICON)
857	// * NULL ref => B_BAD_VALUE
858	NextSubTest();
859	{
860		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
861		CHK(BNodeInfo::GetTrackerIcon(NULL, &icon, B_MINI_ICON)
862			== B_BAD_VALUE);
863		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
864		CHK(BNodeInfo::GetTrackerIcon(NULL, &icon2, B_LARGE_ICON)
865			== B_BAD_VALUE);
866	}
867
868	// status_t GetTrackerIcon(BBitmap *icon, icon_size k = B_LARGE_ICON) const
869	// * uninitialized => B_NO_INIT
870	NextSubTest();
871	{
872		BNodeInfo nodeInfo;
873		BBitmap icon(BRect(0, 0, 15, 15), B_CMAP8);
874		CHK(nodeInfo.GetTrackerIcon(&icon, B_MINI_ICON) == B_NO_INIT);
875		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
876		CHK(nodeInfo.GetTrackerIcon(&icon2, B_LARGE_ICON) == B_NO_INIT);
877	}
878
879	// status_t GetTrackerIcon(BBitmap *icon, icon_size k = B_LARGE_ICON) const
880	// static status_t GetTrackerIcon(const entry_ref *ref, BBitmap *icon,
881	//								  icon_size k = B_LARGE_ICON)
882	// * NULL icon => B_BAD_VALUE
883	NextSubTest();
884	{
885		// non-static
886		BNode node(testFile1);
887		BNodeInfo nodeInfo;
888		CHK(nodeInfo.SetTo(&node) == B_OK);
889		CHK(nodeInfo.GetTrackerIcon(NULL, B_MINI_ICON) == B_BAD_VALUE);
890		CHK(nodeInfo.GetTrackerIcon(NULL, B_LARGE_ICON) == B_BAD_VALUE);
891		// static
892		CHK(BNodeInfo::GetTrackerIcon(&testRef1, NULL, B_MINI_ICON)
893			== B_BAD_VALUE);
894		BBitmap icon2(BRect(0, 0, 31, 31), B_CMAP8);
895		CHK(BNodeInfo::GetTrackerIcon(&testRef1, NULL, B_LARGE_ICON)
896			== B_BAD_VALUE);
897	}
898	// * icon dimensions != icon size => B_BAD_VALUE
899	NextSubTest();
900	{
901		// non-static
902		BNode node(testFile1);
903		BNodeInfo nodeInfo;
904		CHK(nodeInfo.SetTo(&node) == B_OK);
905		BBitmap icon(BRect(0, 0, 31, 31), B_CMAP8);
906		CHK(nodeInfo.GetTrackerIcon(&icon, B_MINI_ICON) == B_BAD_VALUE);
907		BBitmap icon2(BRect(0, 0, 15, 15), B_CMAP8);
908		CHK(nodeInfo.GetTrackerIcon(&icon2, B_LARGE_ICON) == B_BAD_VALUE);
909		// static
910		CHK(BNodeInfo::GetTrackerIcon(&testRef1, &icon, B_MINI_ICON)
911			== B_BAD_VALUE);
912		CHK(BNodeInfo::GetTrackerIcon(&testRef1, &icon2, B_LARGE_ICON)
913			== B_BAD_VALUE);
914	}
915
916	// initialization for further tests
917	BNode node(testFile1);
918	BNodeInfo nodeInfo;
919	CHK(nodeInfo.SetTo(&node) == B_OK);
920	// install file type
921	BMimeType type(testType1);
922	CHK(type.Install() == B_OK);
923	// set icons for file
924	CHK(nodeInfo.SetIcon(fIconM1, B_MINI_ICON) == B_OK);
925	CHK(nodeInfo.SetIcon(fIconL1, B_LARGE_ICON) == B_OK);
926	// install application type with icons for type, and make it the file's
927	// preferred application
928	BMimeType appType(testAppSignature1);
929	CHK(appType.Install() == B_OK);
930	CHK(appType.SetIconForType(testType1, fIconM2, B_MINI_ICON) == B_OK);
931	CHK(appType.SetIconForType(testType1, fIconL2, B_LARGE_ICON) == B_OK);
932	CHK(nodeInfo.SetPreferredApp(testAppSignature1) == B_OK);
933	// set icons for type in MIME database
934	CHK(type.SetIcon(fIconM3, B_MINI_ICON) == B_OK);
935	CHK(type.SetIcon(fIconL3, B_LARGE_ICON) == B_OK);
936	// install application type with icons for type, and make it the type's
937	// preferred application
938	BMimeType appType2(testAppSignature2);
939	CHK(appType2.Install() == B_OK);
940	CHK(appType2.SetIconForType(testType1, fIconM4, B_MINI_ICON) == B_OK);
941	CHK(appType2.SetIconForType(testType1, fIconL4, B_LARGE_ICON) == B_OK);
942	CHK(type.SetPreferredApp(testAppSignature2) == B_OK);
943
944	// * has icon, but not type => B_OK,
945	//   returns the "application/octet-stream" icon
946	NextSubTest();
947	{
948		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, &octetMIcon);
949		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, &octetLIcon);
950	}
951	// set invalid file type
952	CHK(nodeInfo.SetType(invalidTestType) == B_OK);
953	// * has icon, but invalid type => B_OK, returns file icon
954	NextSubTest();
955	{
956		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM1);
957		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL1);
958	}
959	// set file type
960	CHK(nodeInfo.SetType(testType1) == B_OK);
961	// * has icon => B_OK
962	NextSubTest();
963	{
964		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM1);
965		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL1);
966	}
967	// unset icons
968	CHK(nodeInfo.SetIcon(NULL, B_MINI_ICON) == B_OK);
969	CHK(nodeInfo.SetIcon(NULL, B_LARGE_ICON) == B_OK);
970	// * has no icon, but preferred app with icon for type => B_OK
971	NextSubTest();
972	{
973		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM2);
974		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL2);
975	}
976	// unset icons for type for preferred app
977	CHK(appType.SetIconForType(testType1, NULL, B_MINI_ICON) == B_OK);
978	CHK(appType.SetIconForType(testType1, NULL, B_LARGE_ICON) == B_OK);
979	// * no icon, preferred app without icon for type,
980	//   but icon for type in MIME data base => B_OK
981	NextSubTest();
982	{
983		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM3);
984		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL3);
985	}
986	// unset preferred app
987	CHK(nodeInfo.SetPreferredApp(NULL) == B_OK);
988	// * no icon, no preferred app,
989	//   but icon for type in MIME data base => B_OK
990	NextSubTest();
991	{
992		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM3);
993		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL3);
994	}
995	// unset icons for type
996	CHK(type.SetIcon(NULL, B_MINI_ICON) == B_OK);
997	CHK(type.SetIcon(NULL, B_LARGE_ICON) == B_OK);
998	// * no icon, no preferred app, no icon for type in MIME data base, but
999	//   preferred app for type in MIME database and app has icon for type
1000	//   => B_OK
1001	NextSubTest();
1002	{
1003		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, fIconM4);
1004		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, fIconL4);
1005	}
1006	// unset icons for type for preferred app
1007	CHK(appType2.SetIconForType(testType1, NULL, B_MINI_ICON) == B_OK);
1008	CHK(appType2.SetIconForType(testType1, NULL, B_LARGE_ICON) == B_OK);
1009	// * no icon, no preferred app, no icon for type in MIME data base,
1010	//   preferred app for type in MIME database and app has no icon for type
1011	//   => B_OK, returns the "application/octet-stream" icon
1012	NextSubTest();
1013	{
1014		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, &octetMIcon);
1015		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, &octetLIcon);
1016	}
1017	// unset preferred application
1018	CHK(type.SetPreferredApp(NULL) == B_OK);
1019	// * no icon, no preferred app, no icon for type in MIME data base,
1020	//   no preferred app for type in MIME database => B_OK,
1021	//   returns the "application/octet-stream" icon
1022	NextSubTest();
1023	{
1024		TestTrackerIcon(nodeInfo, &testRef1, B_MINI_ICON, &octetMIcon);
1025		TestTrackerIcon(nodeInfo, &testRef1, B_LARGE_ICON, &octetLIcon);
1026	}
1027
1028	// Test GetTrackerIcon() for different types (without type set)
1029	NextSubTest();
1030	{
1031		TestTrackerIcon(testDir, B_DIRECTORY_MIME_TYPE);
1032		TestTrackerIcon("/", B_VOLUME_MIME_TYPE);
1033		TestTrackerIcon("/system", B_SYMLINK_MIME_TYPE);
1034
1035		chmod(testFile4, 0755);
1036		TestTrackerIcon(testFile4, B_APP_MIME_TYPE);
1037		chmod(testFile4, 0644);
1038	}
1039}
1040
1041