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