xref: /haiku/src/tests/kits/app/broster/FindAppTester.cpp (revision 5d9e40fe9252c8f9c5e5e41594545bfa4419fcc7)
1 //------------------------------------------------------------------------------
2 //	FindAppTester.cpp
3 //
4 //------------------------------------------------------------------------------
5 
6 // Standard Includes -----------------------------------------------------------
7 #include <stdio.h>
8 #include <utime.h>
9 
10 // System Includes -------------------------------------------------------------
11 #include <Message.h>
12 #include <OS.h>
13 #include <AppFileInfo.h>
14 #include <Application.h>
15 #include <File.h>
16 #include <FindDirectory.h>
17 #include <Handler.h>
18 #include <Looper.h>
19 #include <Path.h>
20 #include <Roster.h>
21 #include <String.h>
22 
23 // Project Includes ------------------------------------------------------------
24 #include <TestShell.h>
25 #include <TestUtils.h>
26 #include <cppunit/TestAssert.h>
27 
28 // Local Includes --------------------------------------------------------------
29 #include "AppRunner.h"
30 #include "FindAppTester.h"
31 
32 // Local Defines ---------------------------------------------------------------
33 
34 // Globals ---------------------------------------------------------------------
35 
36 //------------------------------------------------------------------------------
37 
38 static const char *uninstalledType
39 	= "application/x-vnd.obos-roster-findapp-uninstalled";
40 static const char *appType1	= "application/x-vnd.obos-roster-findapp-app1";
41 static const char *appType2	= "application/x-vnd.obos-roster-findapp-app2";
42 static const char *fileType1 = "application/x-vnd.obos-roster-findapp-file1";
43 static const char *fileType2 = "application/x-vnd.obos-roster-findapp-file2";
44 static const char *textTestType = "text/x-vnd.obos-roster-findapp";
45 
46 static const char *testDir		= "/tmp/testdir";
47 static const char *appFile1		= "/tmp/testdir/app1";
48 static const char *appFile2		= "/tmp/testdir/app2";
49 static const char *testFile1	= "/tmp/testdir/testFile1";
50 static const char *testLink1	= "/tmp/testdir/testLink1";
51 static const char *trashAppName	= "roster-findapp-app";
52 
53 // get_trash_app_file
54 static
55 const char*
56 get_trash_app_file()
57 {
58 	static char trashAppFile[B_PATH_NAME_LENGTH];
59 	static bool initialized = false;
60 	if (!initialized) {
61 		BPath path;
62 		CHK(find_directory(B_TRASH_DIRECTORY, &path) == B_OK);
63 		CHK(path.Append(trashAppName) == B_OK);
64 		strcpy(trashAppFile, path.Path());
65 		initialized = true;
66 	}
67 	return trashAppFile;
68 }
69 
70 // install_type
71 static
72 void
73 install_type(const char *type, const char *preferredApp = NULL,
74 			 const char *snifferRule = NULL)
75 {
76 	BMimeType mimeType(type);
77 	if (!mimeType.IsInstalled())
78 		CHK(mimeType.Install() == B_OK);
79 	if (preferredApp)
80 		CHK(mimeType.SetPreferredApp(preferredApp) == B_OK);
81 	if (snifferRule)
82 		CHK(mimeType.SetSnifferRule(snifferRule) == B_OK);
83 }
84 
85 // ref_for_path
86 static
87 entry_ref
88 ref_for_path(const char *filename, bool traverse = true)
89 {
90 	entry_ref ref;
91 	BEntry entry;
92 	CHK(entry.SetTo(filename, traverse) == B_OK);
93 	CHK(entry.GetRef(&ref) == B_OK);
94 	return ref;
95 }
96 
97 // create_app
98 static
99 void
100 create_app(const char *filename, const char *signature = NULL,
101 		   bool install = false, bool makeExecutable = true)
102 {
103 	system((string("touch ") + filename).c_str());
104 	if (makeExecutable)
105 		system((string("chmod a+x ") + filename).c_str());
106 	if (signature) {
107 		BFile file;
108 		CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
109 		BAppFileInfo appFileInfo;
110 		CHK(appFileInfo.SetTo(&file) == B_OK);
111 		CHK(appFileInfo.SetSignature(signature) == B_OK);
112 		if (install)
113 			CHK(BMimeType(signature).Install() == B_OK);
114 	}
115 }
116 
117 // create_file
118 static
119 entry_ref
120 create_file(const char *filename, const char *type,
121 			const char *preferredApp = NULL, const char *appHintPath = NULL,
122 			const char *contents = NULL)
123 {
124 	if (contents)
125 		system((string("echo -n \"") + contents + "\" > " + filename).c_str());
126 	else
127 		system((string("touch ") + filename).c_str());
128 	if (type || preferredApp || appHintPath) {
129 		BFile file;
130 		CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
131 		BNodeInfo nodeInfo;
132 		CHK(nodeInfo.SetTo(&file) == B_OK);
133 		if (type)
134 			CHK(nodeInfo.SetType(type) == B_OK);
135 		if (preferredApp)
136 			CHK(nodeInfo.SetPreferredApp(preferredApp) == B_OK);
137 		if (appHintPath) {
138 			entry_ref appHint(ref_for_path(appHintPath));
139 			CHK(nodeInfo.SetAppHint(&appHint) == B_OK);
140 		}
141 	}
142 	return ref_for_path(filename);
143 }
144 
145 // check_app_type
146 static
147 void
148 check_app_type(const char *signature, const char *filename)
149 {
150 	BMimeType type(signature);
151 	CHK(type.IsInstalled() == true);
152 	if (filename) {
153 		entry_ref appHint;
154 		CHK(type.GetAppHint(&appHint) == B_OK);
155 		CHK(ref_for_path(filename) == appHint);
156 	}
157 }
158 
159 // set_file_time
160 static
161 void
162 set_file_time(const char *filename, time_t time)
163 {
164 	utimbuf buffer;
165 	buffer.actime = time;
166 	buffer.modtime = time;
167 	CHK(utime(filename, &buffer) == 0);
168 }
169 
170 // set_version
171 static
172 void
173 set_version(const char *filename, uint32 version)
174 {
175 	version_info versionInfo = { 1, 1, 1, 1, version, "short1", "long1" };
176 	BFile file;
177 	CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
178 	BAppFileInfo appFileInfo;
179 	CHK(appFileInfo.SetTo(&file) == B_OK);
180 	CHK(appFileInfo.SetVersionInfo(&versionInfo, B_APP_VERSION_KIND) == B_OK);
181 }
182 
183 // set_type_app_hint
184 static
185 void
186 set_type_app_hint(const char *signature, const char *filename)
187 {
188 	BMimeType type(signature);
189 	if (!type.IsInstalled());
190 		CHK(type.Install() == B_OK);
191 	entry_ref fileRef(ref_for_path(filename));
192 	CHK(type.SetAppHint(&fileRef) == B_OK);
193 }
194 
195 // setUp
196 void
197 FindAppTester::setUp()
198 {
199 	fApplication = new BApplication("application/x-vnd.obos-roster-findapp");
200 	system((string("mkdir ") + testDir).c_str());
201 }
202 
203 // tearDown
204 void
205 FindAppTester::tearDown()
206 {
207 	BMimeType(uninstalledType).Delete();
208 	BMimeType(appType1).Delete();
209 	BMimeType(appType2).Delete();
210 	BMimeType(fileType1).Delete();
211 	BMimeType(fileType2).Delete();
212 	BMimeType(textTestType).Delete();
213 	delete fApplication;
214 	system((string("rm -rf ") + testDir).c_str());
215 	system((string("rm -f ") + get_trash_app_file()).c_str());
216 }
217 
218 // FindAppCaller
219 class FindAppCaller {
220 public:
221 	virtual status_t operator()(const char *type, entry_ref *ref) = 0;
222 };
223 
224 /*
225 	@case 1			uninstalled type mimeType
226 	@results		Should return B_LAUNCH_FAILED_APP_NOT_FOUND.
227 */
228 static
229 void
230 CommonFindAppTest1(FindAppCaller &caller)
231 {
232 	BRoster roster;
233 	entry_ref ref;
234 	CHK(caller(uninstalledType, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
235 }
236 
237 /*
238 	@case 2			installed type mimeType, no preferred app
239 	@results		Should return B_LAUNCH_FAILED_NO_PREFERRED_APP.
240 */
241 static
242 void
243 CommonFindAppTest2(FindAppCaller &caller)
244 {
245 	BRoster roster;
246 	install_type(fileType1);
247 	entry_ref ref;
248 	CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_NO_PREFERRED_APP);
249 }
250 
251 /*
252 	@case 3			installed type mimeType, preferred app, app type not
253 					installed, app has no signature
254 	@results		Should return B_LAUNCH_FAILED_APP_NOT_FOUND.
255 */
256 static
257 void
258 CommonFindAppTest3(FindAppCaller &caller)
259 {
260 	BRoster roster;
261 	install_type(fileType1, appType1);
262 	entry_ref ref;
263 	CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
264 }
265 
266 /*
267 	@case 4			installed type mimeType, preferred app, app type not
268 					installed, app has signature
269 	@results		Should return B_OK and set the ref to refer to the
270 					application's executable. Should install the app type and
271 					set the app hint on it.
272 */
273 static
274 void
275 CommonFindAppTest4(FindAppCaller &caller)
276 {
277 	BRoster roster;
278 	create_app(appFile1, appType1);
279 	install_type(fileType1, appType1);
280 	entry_ref ref;
281 	CHK(caller(fileType1, &ref) == B_OK);
282 	CHK(ref_for_path(appFile1) == ref);
283 	check_app_type(appType1, appFile1);
284 }
285 
286 /*
287 	@case 5			installed type mimeType, preferred app, app type installed,
288 					app has signature
289 	@results		Should return B_OK and set the ref to refer to the
290 					application'sexecutable. Should set the app hint on the
291 					app type.
292 */
293 static
294 void
295 CommonFindAppTest5(FindAppCaller &caller)
296 {
297 	BRoster roster;
298 	create_app(appFile1, appType1, true);
299 	install_type(fileType1, appType1);
300 	entry_ref ref;
301 	CHK(caller(fileType1, &ref) == B_OK);
302 	CHK(ref_for_path(appFile1) == ref);
303 	check_app_type(appType1, appFile1);
304 }
305 
306 /*
307 	@case 6			installed type mimeType, preferred app, app type installed,
308 					app has signature, app has no execute permission
309 	@results		Should return B_OK and set the ref to refer to the
310 					application's executable. Should set the app hint on the
311 					app type.
312 */
313 static
314 void
315 CommonFindAppTest6(FindAppCaller &caller)
316 {
317 	BRoster roster;
318 	create_app(appFile1, appType1, true, false);
319 	install_type(fileType1, appType1);
320 	entry_ref ref;
321 	CHK(caller(fileType1, &ref) == B_OK);
322 	CHK(ref_for_path(appFile1) == ref);
323 	check_app_type(appType1, appFile1);
324 }
325 
326 /*
327 	@case 7			installed type mimeType, preferred app, app type installed,
328 					two apps have the signature
329 	@results		Should return B_OK and set the ref to refer to the
330 					application executable with the most recent modification
331 					time. Should set the app hint on the app type.
332 */
333 static
334 void
335 CommonFindAppTest7(FindAppCaller &caller)
336 {
337 	BRoster roster;
338 	create_app(appFile1, appType1);
339 	create_app(appFile2, appType1, true);
340 	set_file_time(appFile2, time(NULL) + 1);
341 	install_type(fileType1, appType1);
342 	entry_ref ref;
343 	CHK(caller(fileType1, &ref) == B_OK);
344 	CHK(ref_for_path(appFile2) == ref);
345 	check_app_type(appType1, appFile2);
346 }
347 
348 /*
349 	@case 8			installed type mimeType, preferred app, app type installed,
350 					two apps have the signature, one has a version info, the
351 					other one is newer
352 	@results		Should return B_OK and set the ref to refer to the
353 					application executable with version info. Should set the
354 					app hint on the app type.
355 */
356 static
357 void
358 CommonFindAppTest8(FindAppCaller &caller)
359 {
360 	BRoster roster;
361 	create_app(appFile1, appType1);
362 	set_version(appFile1, 1);
363 	create_app(appFile2, appType1, true);
364 	set_file_time(appFile2, time(NULL) + 1);
365 	install_type(fileType1, appType1);
366 	entry_ref ref;
367 	CHK(caller(fileType1, &ref) == B_OK);
368 	CHK(ref_for_path(appFile1) == ref);
369 	check_app_type(appType1, appFile1);
370 }
371 
372 /*
373 	@case 9			installed type mimeType, preferred app, app type installed,
374 					two apps have the signature, both apps have a version info
375 	@results		Should return B_OK and set the ref to refer to the
376 					application executable with the greater version. Should
377 					set the app hint on the app type.
378 */
379 static
380 void
381 CommonFindAppTest9(FindAppCaller &caller)
382 {
383 	BRoster roster;
384 	create_app(appFile1, appType1);
385 	set_version(appFile1, 2);
386 	create_app(appFile2, appType1, true);
387 	set_version(appFile1, 1);
388 	set_file_time(appFile2, time(NULL) + 1);
389 	install_type(fileType1, appType1);
390 	entry_ref ref;
391 	CHK(caller(fileType1, &ref) == B_OK);
392 	CHK(ref_for_path(appFile1) == ref);
393 	check_app_type(appType1, appFile1);
394 }
395 
396 /*
397 	@case 10		installed type mimeType, preferred app, app type installed,
398 					preferred app type has an app hint that points to an app
399 					with a different signature
400 	@results		Should return B_OK and set the ref to refer to the
401 					application's executable. Should remove the incorrect app
402 					hint on the app type. (OBOS: Should set the correct app
403 					hint. Don't even return the wrong app?)
404 */
405 static
406 void
407 CommonFindAppTest10(FindAppCaller &caller)
408 {
409 	BRoster roster;
410 	create_app(appFile1, appType2);
411 	set_type_app_hint(appType1, appFile1);
412 	entry_ref appHint;
413 	CHK(BMimeType(appType1).GetAppHint(&appHint) == B_OK);
414 	install_type(fileType1, appType1);
415 	entry_ref ref;
416 	CHK(caller(fileType1, &ref) == B_OK);
417 	CHK(ref_for_path(appFile1) == ref);
418 	CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
419 // OBOS: We set the app hint for app type 2. There's no reason not to do it.
420 #ifdef TEST_R5
421 	CHK(BMimeType(appType2).IsInstalled() == false);
422 #else
423 	check_app_type(appType2, appFile1);
424 #endif
425 }
426 
427 /*
428 	@case 11		installed type mimeType, preferred app, app type installed,
429 					preferred app type has an app hint pointing to void,
430 					a differently named app with this signature exists
431 	@results		Should return B_OK and set the ref to refer to the
432 					application's executable. Should update the app
433 					hint on the app type.
434 */
435 static
436 void
437 CommonFindAppTest11(FindAppCaller &caller)
438 {
439 	BRoster roster;
440 	create_app(appFile1, appType1);
441 	set_type_app_hint(appType1, appFile2);
442 	install_type(fileType1, appType1);
443 	entry_ref ref;
444 	CHK(caller(fileType1, &ref) == B_OK);
445 	CHK(ref_for_path(appFile1) == ref);
446 	check_app_type(appType1, appFile1);
447 }
448 
449 /*
450 	@case 12		mimeType is app signature, not installed
451 	@results		Should return B_OK and set the ref to refer to the
452 					application executable. Should set the app hint on the
453 					app type.
454 */
455 static
456 void
457 CommonFindAppTest12(FindAppCaller &caller)
458 {
459 	BRoster roster;
460 	create_app(appFile1, appType1);
461 	entry_ref ref;
462 	CHK(caller(appType1, &ref) == B_OK);
463 	CHK(ref_for_path(appFile1) == ref);
464 	check_app_type(appType1, appFile1);
465 }
466 
467 /*
468 	@case 13		mimeType is installed, but has no preferred application,
469 					super type has preferred application
470 	@results		Should return B_OK and set the ref to refer to the
471 					application executable associated with the preferred app
472 					of the supertype. Should set the app hint on the app type.
473 */
474 static
475 void
476 CommonFindAppTest13(FindAppCaller &caller)
477 {
478 	BRoster roster;
479 	// make sure, the original preferred app for the "text" supertype is
480 	// re-installed
481 	struct TextTypeSaver {
482 		TextTypeSaver()
483 		{
484 			BMimeType textType("text");
485 			hasPreferredApp
486 				= (textType.GetPreferredApp(preferredApp) == B_OK);
487 		}
488 
489 		~TextTypeSaver()
490 		{
491 			BMimeType textType("text");
492 			textType.SetPreferredApp(hasPreferredApp ? preferredApp : NULL);
493 		}
494 
495 		bool	hasPreferredApp;
496 		char	preferredApp[B_MIME_TYPE_LENGTH];
497 	} _saver;
498 
499 	create_app(appFile1, appType1);
500 	CHK(BMimeType("text").SetPreferredApp(appType1) == B_OK);
501 	install_type(textTestType);
502 	entry_ref ref;
503 	CHK(caller(textTestType, &ref) == B_OK);
504 	CHK(ref_for_path(appFile1) == ref);
505 	check_app_type(appType1, appFile1);
506 }
507 
508 /*
509 	@case 14		installed type mimeType, preferred app, app type not installed,
510 					app has signature, app is trash
511 	@results		Should return B_LAUNCH_FAILED_APP_IN_TRASH.
512 */
513 static
514 void
515 CommonFindAppTest14(FindAppCaller &caller)
516 {
517 	BRoster roster;
518 	create_app(get_trash_app_file(), appType1);
519 	install_type(fileType1, appType1);
520 	entry_ref ref;
521 	CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_IN_TRASH);
522 }
523 
524 /*
525 	@case 15		installed type mimeType, preferred app, app type installed,
526 					preferred app type has an app hint pointing to void,
527 					no app with this signature exists
528 	@results		Should return B_LAUNCH_FAILED_APP_NOT_FOUND and unset the
529 					app type's app hint.
530 */
531 static
532 void
533 CommonFindAppTest15(FindAppCaller &caller)
534 {
535 	BRoster roster;
536 	set_type_app_hint(appType1, appFile1);
537 	install_type(fileType1, appType1);
538 	entry_ref ref;
539 	CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
540 	entry_ref appHint;
541 	CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
542 }
543 
544 /*
545 	@case 16		installed type mimeType, preferred app, app type installed,
546 					preferred app type has an app hint pointing to a cyclic
547 					link, no app with this signature exists
548 	@results		R5: Should return B_OK and set the ref to refer to the
549 					link.
550 					OBOS: Should return B_LAUNCH_FAILED_APP_NOT_FOUND and
551 					unset the app type's app hint.
552 */
553 static
554 void
555 CommonFindAppTest16(FindAppCaller &caller)
556 {
557 	BRoster roster;
558 	set_type_app_hint(appType1, appFile1);
559 	install_type(fileType1, appType1);
560 	system((string("ln -s ") + appFile1 + " " + appFile1).c_str());
561 	entry_ref ref;
562 	entry_ref appHint;
563 #ifdef TEST_R5
564 	CHK(caller(fileType1, &ref) == B_OK);
565 	CHK(ref_for_path(appFile1, false) == ref);
566 	CHK(BMimeType(appType1).GetAppHint(&appHint) == B_OK);
567 	CHK(appHint == ref);
568 #else
569 	CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
570 	CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
571 #endif
572 }
573 
574 typedef void commonTestFunction(FindAppCaller &caller);
575 static commonTestFunction *commonTestFunctions[] = {
576 	CommonFindAppTest1, CommonFindAppTest2, CommonFindAppTest3,
577 	CommonFindAppTest4, CommonFindAppTest5, CommonFindAppTest6,
578 	CommonFindAppTest7, CommonFindAppTest8, CommonFindAppTest9,
579 	CommonFindAppTest10, CommonFindAppTest11, CommonFindAppTest12,
580 	CommonFindAppTest13, CommonFindAppTest14, CommonFindAppTest15,
581 	CommonFindAppTest16
582 };
583 static int32 commonTestFunctionCount
584 	= sizeof(commonTestFunctions) / sizeof(commonTestFunction*);
585 
586 /*
587 	status_t FindApp(const char *mimeType, entry_ref *app) const
588 	@case 1			mimeType or app are NULL
589 	@results		Should return B_BAD_VALUE.
590 */
591 void FindAppTester::FindAppTestA1()
592 {
593 	BRoster roster;
594 	CHK(roster.FindApp((const char*)NULL, NULL) == B_BAD_VALUE);
595 // R5: crashes when passing a non-NULL type, but a NULL ref.
596 #ifndef TEST_R5
597 	CHK(roster.FindApp("image/gif", NULL) == B_BAD_VALUE);
598 #endif
599 	entry_ref ref;
600 	CHK(roster.FindApp((const char*)NULL, &ref) == B_BAD_VALUE);
601 }
602 
603 /*
604 	status_t FindApp(const char *mimeType, entry_ref *app) const
605 	@case 2			mimeType is invalid
606 	@results		Should return B_BAD_VALUE.
607 */
608 void FindAppTester::FindAppTestA2()
609 {
610 	BRoster roster;
611 	entry_ref ref;
612 	CHK(roster.FindApp("invalid/mine/type", &ref) == B_BAD_VALUE);
613 }
614 
615 // FindAppTypeCaller
616 class FindAppTypeCaller : public FindAppCaller {
617 public:
618 	virtual status_t operator()(const char *type, entry_ref *ref)
619 	{
620 		BRoster roster;
621 		return roster.FindApp(type, ref);
622 	}
623 };
624 
625 /*
626 	status_t FindApp(const char *mimeType, entry_ref *app) const
627 	@case 3			FindApp(const char*, entry_ref*) cases 3-16
628 					(== common cases 1-14)
629 */
630 void FindAppTester::FindAppTestA3()
631 {
632 	FindAppTypeCaller caller;
633 	for (int32 i = 0; i < commonTestFunctionCount; i++) {
634 		NextSubTest();
635 		(*commonTestFunctions[i])(caller);
636 		tearDown();
637 		setUp();
638 	}
639 }
640 
641 /*
642 	status_t FindApp(entry_ref *ref, entry_ref *app) const
643 	@case 1			ref or app are NULL
644 	@results		Should return B_BAD_VALUE.
645 */
646 void FindAppTester::FindAppTestB1()
647 {
648 	BRoster roster;
649 	CHK(roster.FindApp((entry_ref*)NULL, NULL) == B_BAD_VALUE);
650 // R5: Crashes when passing a NULL (app) ref.
651 #ifndef TEST_R5
652 	create_app(appFile1, appType1);
653 	entry_ref fileRef(create_file(testFile1, fileType1, appType1));
654 	CHK(roster.FindApp(&fileRef, NULL) == B_BAD_VALUE);
655 #endif
656 	entry_ref ref;
657 	CHK(roster.FindApp((entry_ref*)NULL, &ref) == B_BAD_VALUE);
658 }
659 
660 /*
661 	status_t FindApp(entry_ref *ref, entry_ref *app) const
662 	@case 2			ref doesn't refer to an existing entry =>
663 	@results		Should return B_ENTRY_NOT_FOUND.
664 */
665 void FindAppTester::FindAppTestB2()
666 {
667 	BRoster roster;
668 	entry_ref fileRef(ref_for_path(testFile1));
669 	entry_ref ref;
670 	CHK(roster.FindApp(&fileRef, &ref) == B_ENTRY_NOT_FOUND);
671 }
672 
673 /*
674 	status_t FindApp(entry_ref *ref, entry_ref *app) const
675 	@case 3			ref is valid, file has type and preferred app, preferred
676 					app is in trash
677 	@results		Should return B_LAUNCH_FAILED_APP_IN_TRASH.
678 */
679 void FindAppTester::FindAppTestB3()
680 {
681 	BRoster roster;
682 	create_app(get_trash_app_file(), appType1);
683 	entry_ref fileRef(create_file(testFile1, fileType1, appType1));
684 	entry_ref ref;
685 	CHK(roster.FindApp(&fileRef, &ref) == B_LAUNCH_FAILED_APP_IN_TRASH);
686 }
687 
688 /*
689 	status_t FindApp(entry_ref *ref, entry_ref *app) const
690 	@case 4			ref is valid, file has type and preferred app, app type is
691 					not installed, app exists and has signature
692 	@results		Should return B_OK and set the ref to refer to the file's
693 					(not the file type's) preferred application's executable.
694 					Should install the app type and set the app hint on it.
695 */
696 void FindAppTester::FindAppTestB4()
697 {
698 	BRoster roster;
699 	create_app(appFile1, appType1);
700 	create_app(appFile2, appType2);
701 	install_type(fileType1, appType1);
702 	entry_ref fileRef(create_file(testFile1, fileType1, appType2));
703 	entry_ref ref;
704 	CHK(roster.FindApp(&fileRef, &ref) == B_OK);
705 	CHK(ref_for_path(appFile2) == ref);
706 	check_app_type(appType2, appFile2);
707 }
708 
709 /*
710 	status_t FindApp(entry_ref *ref, entry_ref *app) const
711 	@case 5			ref is valid, file has no type, but preferred app,
712 					app type is not installed, app exists and has signature
713 	@results		Should return B_OK and set the ref to refer to the
714 					application's executable. Should install the app type and
715 					set the app hint on it.
716 */
717 void FindAppTester::FindAppTestB5()
718 {
719 	BRoster roster;
720 	create_app(appFile1, appType1);
721 	entry_ref fileRef(create_file(testFile1, NULL, appType1));
722 	entry_ref ref;
723 	CHK(roster.FindApp(&fileRef, &ref) == B_OK);
724 	CHK(ref_for_path(appFile1) == ref);
725 	check_app_type(appType1, appFile1);
726 }
727 
728 /*
729 	status_t FindApp(entry_ref *ref, entry_ref *app) const
730 	@case 6			ref is valid, file has type and app hint, the type's
731 					preferred app type is not installed, app exists and has
732 					signature
733 	@results		Should return B_OK and set the ref to refer to the file
734 					type's preferred application's executable. Should install
735 					the app type and set the app hint on it.
736 */
737 void FindAppTester::FindAppTestB6()
738 {
739 	BRoster roster;
740 	create_app(appFile1, appType1);
741 	create_app(appFile2, appType2);
742 	install_type(fileType1, appType1);
743 	entry_ref fileRef(create_file(testFile1, fileType1, NULL, appFile2));
744 	entry_ref ref;
745 	CHK(roster.FindApp(&fileRef, &ref) == B_OK);
746 	CHK(ref_for_path(appFile1) == ref);
747 	check_app_type(appType1, appFile1);
748 }
749 
750 /*
751 	status_t FindApp(entry_ref *ref, entry_ref *app) const
752 	@case 7			ref is valid, file has type, the type's preferred app
753 					type is not installed, app exists and has signature,
754 					file is executable
755 	@results		Should return B_OK and set the ref to refer to the file.
756 					Should not set the app hint on the app or file type (Why?).
757 */
758 void FindAppTester::FindAppTestB7()
759 {
760 	BRoster roster;
761 	create_app(appFile1, appType1);
762 	install_type(fileType1, appType1);
763 	entry_ref fileRef(create_file(testFile1, fileType1));
764 	system((string("chmod a+x ") + testFile1).c_str());
765 	entry_ref ref;
766 	CHK(roster.FindApp(&fileRef, &ref) == B_OK);
767 	CHK(ref_for_path(testFile1) == ref);
768 	CHK(BMimeType(appType1).IsInstalled() == false);
769 	CHK(BMimeType(fileType1).GetAppHint(&ref) == B_ENTRY_NOT_FOUND);
770 }
771 
772 /*
773 	status_t FindApp(entry_ref *ref, entry_ref *app) const
774 	@case 8			ref is valid and refers to a link to a file, file has type,
775 					the type's preferred app type is not installed,
776 					app exists and has signature
777 	@results		Should return B_OK and set the ref to refer to the file
778 					type's preferred application's executable. Should install
779 					the app type and set the app hint on it.
780 */
781 void FindAppTester::FindAppTestB8()
782 {
783 	BRoster roster;
784 	create_app(appFile1, appType1);
785 	install_type(fileType1, appType1);
786 	create_file(testFile1, fileType1);
787 	system((string("ln -s ") + testFile1 + " " + testLink1).c_str());
788 	entry_ref linkRef(ref_for_path(testLink1, false));
789 	entry_ref ref;
790 	CHK(roster.FindApp(&linkRef, &ref) == B_OK);
791 	CHK(ref_for_path(appFile1) == ref);
792 	check_app_type(appType1, appFile1);
793 }
794 
795 // FileWithTypeCaller
796 class FileWithTypeCaller : public FindAppCaller {
797 public:
798 	virtual status_t operator()(const char *type, entry_ref *ref)
799 	{
800 		BRoster roster;
801 		entry_ref fileRef(create_file(testFile1, type));
802 		return roster.FindApp(&fileRef, ref);
803 	}
804 };
805 
806 /*
807 	status_t FindApp(entry_ref *ref, entry_ref *app) const
808 	@case 9			ref is valid, file has no type, sniffing results in a type,
809 					type is set on file,
810 					FindApp(const char*, entry_ref*) cases 4-16
811 					(== common cases 2-14)
812 */
813 void FindAppTester::FindAppTestB9()
814 {
815 	FileWithTypeCaller caller;
816 	for (int32 i = 0; i < commonTestFunctionCount; i++) {
817 		NextSubTest();
818 		(*commonTestFunctions[i])(caller);
819 		tearDown();
820 		setUp();
821 	}
822 }
823 
824 // SniffFileTypeCaller
825 class SniffFileTypeCaller : public FindAppCaller {
826 public:
827 	virtual status_t operator()(const char *type, entry_ref *ref)
828 	{
829 		BRoster roster;
830 		entry_ref fileRef(create_file(testFile1, type, NULL, NULL,
831 						  "UnIQe pAtTeRn"));
832 		install_type(fileType1, NULL, "1.0 [0] ('UnIQe pAtTeRn')");
833 		return roster.FindApp(&fileRef, ref);
834 	}
835 };
836 
837 /*
838 	status_t FindApp(entry_ref *ref, entry_ref *app) const
839 	@case 10		ref is valid, file has no type, sniffing results in a type,
840 					type is set on file,
841 					FindApp(const char*, entry_ref*) cases 3-16
842 					(== common cases 1-14)
843 */
844 void FindAppTester::FindAppTestB10()
845 {
846 	SniffFileTypeCaller caller;
847 	for (int32 i = 1; i < commonTestFunctionCount; i++) {
848 		NextSubTest();
849 		(*commonTestFunctions[i])(caller);
850 		tearDown();
851 		setUp();
852 	}
853 }
854 
855 /*
856 	status_t FindApp(entry_ref *ref, entry_ref *app) const
857 	@case 11		ref is valid and refers to a cyclic link
858 	@results		Should return B_LAUNCH_FAILED_NO_RESOLVE_LINK.
859 */
860 void FindAppTester::FindAppTestB11()
861 {
862 	BRoster roster;
863 	system((string("ln -s ") + testLink1 + " " + testLink1).c_str());
864 	entry_ref linkRef(ref_for_path(testLink1, false));
865 	entry_ref ref;
866 	CHK(roster.FindApp(&linkRef, &ref) == B_LAUNCH_FAILED_NO_RESOLVE_LINK);
867 }
868 
869 /*
870 	status_t FindApp(entry_ref *ref, entry_ref *app) const
871 	@case 12		ref is valid and refers to a link to void
872 	@results		Should return B_LAUNCH_FAILED_NO_RESOLVE_LINK.
873 */
874 void FindAppTester::FindAppTestB12()
875 {
876 	BRoster roster;
877 	system((string("ln -s ") + testFile1 + " " + testLink1).c_str());
878 	entry_ref linkRef(ref_for_path(testLink1, false));
879 	entry_ref ref;
880 	CHK(roster.FindApp(&linkRef, &ref) == B_LAUNCH_FAILED_NO_RESOLVE_LINK);
881 }
882 
883 
884 Test* FindAppTester::Suite()
885 {
886 	TestSuite* SuiteOfTests = new TestSuite;
887 
888 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestA1);
889 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestA2);
890 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestA3);
891 
892 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB1);
893 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB2);
894 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB3);
895 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB4);
896 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB5);
897 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB6);
898 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB7);
899 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB8);
900 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB9);
901 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB10);
902 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB11);
903 	ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB12);
904 
905 	return SuiteOfTests;
906 }
907 
908