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