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
39static const char *uninstalledType
40	= "application/x-vnd.obos-roster-findapp-uninstalled";
41static const char *appType1	= "application/x-vnd.obos-roster-findapp-app1";
42static const char *appType2	= "application/x-vnd.obos-roster-findapp-app2";
43static const char *fileType1 = "application/x-vnd.obos-roster-findapp-file1";
44static const char *fileType2 = "application/x-vnd.obos-roster-findapp-file2";
45static const char *textTestType = "text/x-vnd.obos-roster-findapp";
46
47static const char *testDir		= "/tmp/testdir";
48static const char *appFile1		= "/tmp/testdir/app1";
49static const char *appFile2		= "/tmp/testdir/app2";
50static const char *testFile1	= "/tmp/testdir/testFile1";
51static const char *testLink1	= "/tmp/testdir/testLink1";
52static const char *trashAppName	= "roster-findapp-app";
53
54// get_trash_app_file
55static
56const char*
57get_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
72static
73void
74install_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
87static
88entry_ref
89ref_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
99static
100void
101create_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
119static
120entry_ref
121create_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
147static
148void
149check_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
161static
162void
163set_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
172static
173void
174set_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
185static
186void
187set_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
197void
198FindAppTester::setUp()
199{
200	fApplication = new BApplication("application/x-vnd.obos-roster-findapp");
201	system((string("mkdir ") + testDir).c_str());
202}
203
204// tearDown
205void
206FindAppTester::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
220class FindAppCaller {
221public:
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*/
229static
230void
231CommonFindAppTest1(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*/
242static
243void
244CommonFindAppTest2(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*/
257static
258void
259CommonFindAppTest3(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*/
274static
275void
276CommonFindAppTest4(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*/
294static
295void
296CommonFindAppTest5(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*/
314static
315void
316CommonFindAppTest6(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*/
334static
335void
336CommonFindAppTest7(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*/
357static
358void
359CommonFindAppTest8(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*/
380static
381void
382CommonFindAppTest9(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*/
406static
407void
408CommonFindAppTest10(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*/
436static
437void
438CommonFindAppTest11(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*/
456static
457void
458CommonFindAppTest12(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*/
475static
476void
477CommonFindAppTest13(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*/
514static
515void
516CommonFindAppTest14(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*/
532static
533void
534CommonFindAppTest15(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*/
554static
555void
556CommonFindAppTest16(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
575typedef void commonTestFunction(FindAppCaller &caller);
576static 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};
584static 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*/
592void 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*/
609void 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
617class FindAppTypeCaller : public FindAppCaller {
618public:
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*/
631void 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*/
647void 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*/
666void 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*/
680void 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*/
697void 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*/
718void 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*/
738void 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*/
759void 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*/
782void 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
797class FileWithTypeCaller : public FindAppCaller {
798public:
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*/
814void 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
826class SniffFileTypeCaller : public FindAppCaller {
827public:
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*/
845void 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*/
861void 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*/
875void 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
885Test* 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