#include <stdio.h>
#include <stdlib.h>
#include <utime.h>
#include <Message.h>
#include <OS.h>
#include <AppFileInfo.h>
#include <Application.h>
#include <File.h>
#include <FindDirectory.h>
#include <Handler.h>
#include <Looper.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <TestShell.h>
#include <TestUtils.h>
#include <cppunit/TestAssert.h>
#include "AppRunner.h"
#include "FindAppTester.h"
static const char *uninstalledType
= "application/x-vnd.obos-roster-findapp-uninstalled";
static const char *appType1 = "application/x-vnd.obos-roster-findapp-app1";
static const char *appType2 = "application/x-vnd.obos-roster-findapp-app2";
static const char *fileType1 = "application/x-vnd.obos-roster-findapp-file1";
static const char *fileType2 = "application/x-vnd.obos-roster-findapp-file2";
static const char *textTestType = "text/x-vnd.obos-roster-findapp";
static const char *testDir = "/tmp/testdir";
static const char *appFile1 = "/tmp/testdir/app1";
static const char *appFile2 = "/tmp/testdir/app2";
static const char *testFile1 = "/tmp/testdir/testFile1";
static const char *testLink1 = "/tmp/testdir/testLink1";
static const char *trashAppName = "roster-findapp-app";
static
const char*
get_trash_app_file()
{
static char trashAppFile[B_PATH_NAME_LENGTH];
static bool initialized = false;
if (!initialized) {
BPath path;
CHK(find_directory(B_TRASH_DIRECTORY, &path) == B_OK);
CHK(path.Append(trashAppName) == B_OK);
strcpy(trashAppFile, path.Path());
initialized = true;
}
return trashAppFile;
}
static
void
install_type(const char *type, const char *preferredApp = NULL,
const char *snifferRule = NULL)
{
BMimeType mimeType(type);
if (!mimeType.IsInstalled())
CHK(mimeType.Install() == B_OK);
if (preferredApp)
CHK(mimeType.SetPreferredApp(preferredApp) == B_OK);
if (snifferRule)
CHK(mimeType.SetSnifferRule(snifferRule) == B_OK);
}
static
entry_ref
ref_for_path(const char *filename, bool traverse = true)
{
entry_ref ref;
BEntry entry;
CHK(entry.SetTo(filename, traverse) == B_OK);
CHK(entry.GetRef(&ref) == B_OK);
return ref;
}
static
void
create_app(const char *filename, const char *signature = NULL,
bool install = false, bool makeExecutable = true)
{
system((string("touch ") + filename).c_str());
if (makeExecutable)
system((string("chmod a+x ") + filename).c_str());
if (signature) {
BFile file;
CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
BAppFileInfo appFileInfo;
CHK(appFileInfo.SetTo(&file) == B_OK);
CHK(appFileInfo.SetSignature(signature) == B_OK);
if (install)
CHK(BMimeType(signature).Install() == B_OK);
}
}
static
entry_ref
create_file(const char *filename, const char *type,
const char *preferredApp = NULL, const char *appHintPath = NULL,
const char *contents = NULL)
{
if (contents)
system((string("echo -n \"") + contents + "\" > " + filename).c_str());
else
system((string("touch ") + filename).c_str());
if (type || preferredApp || appHintPath) {
BFile file;
CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
BNodeInfo nodeInfo;
CHK(nodeInfo.SetTo(&file) == B_OK);
if (type)
CHK(nodeInfo.SetType(type) == B_OK);
if (preferredApp)
CHK(nodeInfo.SetPreferredApp(preferredApp) == B_OK);
if (appHintPath) {
entry_ref appHint(ref_for_path(appHintPath));
CHK(nodeInfo.SetAppHint(&appHint) == B_OK);
}
}
return ref_for_path(filename);
}
static
void
check_app_type(const char *signature, const char *filename)
{
BMimeType type(signature);
CHK(type.IsInstalled() == true);
if (filename) {
entry_ref appHint;
CHK(type.GetAppHint(&appHint) == B_OK);
CHK(ref_for_path(filename) == appHint);
}
}
static
void
set_file_time(const char *filename, time_t time)
{
utimbuf buffer;
buffer.actime = time;
buffer.modtime = time;
CHK(utime(filename, &buffer) == 0);
}
static
void
set_version(const char *filename, uint32 version)
{
version_info versionInfo = { 1, 1, 1, 1, version, "short1", "long1" };
BFile file;
CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
BAppFileInfo appFileInfo;
CHK(appFileInfo.SetTo(&file) == B_OK);
CHK(appFileInfo.SetVersionInfo(&versionInfo, B_APP_VERSION_KIND) == B_OK);
}
static
void
set_type_app_hint(const char *signature, const char *filename)
{
BMimeType type(signature);
if (!type.IsInstalled());
CHK(type.Install() == B_OK);
entry_ref fileRef(ref_for_path(filename));
CHK(type.SetAppHint(&fileRef) == B_OK);
}
void
FindAppTester::setUp()
{
fApplication = new BApplication("application/x-vnd.obos-roster-findapp");
system((string("mkdir ") + testDir).c_str());
}
void
FindAppTester::tearDown()
{
BMimeType(uninstalledType).Delete();
BMimeType(appType1).Delete();
BMimeType(appType2).Delete();
BMimeType(fileType1).Delete();
BMimeType(fileType2).Delete();
BMimeType(textTestType).Delete();
delete fApplication;
system((string("rm -rf ") + testDir).c_str());
system((string("rm -f ") + get_trash_app_file()).c_str());
}
class FindAppCaller {
public:
virtual status_t operator()(const char *type, entry_ref *ref) = 0;
};
static
void
CommonFindAppTest1(FindAppCaller &caller)
{
BRoster roster;
entry_ref ref;
CHK(caller(uninstalledType, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
}
static
void
CommonFindAppTest2(FindAppCaller &caller)
{
BRoster roster;
install_type(fileType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_NO_PREFERRED_APP);
}
static
void
CommonFindAppTest3(FindAppCaller &caller)
{
BRoster roster;
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
}
static
void
CommonFindAppTest4(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest5(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1, true);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest6(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1, true, false);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest7(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
create_app(appFile2, appType1, true);
set_file_time(appFile2, time(NULL) + 1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile2) == ref);
check_app_type(appType1, appFile2);
}
static
void
CommonFindAppTest8(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
set_version(appFile1, 1);
create_app(appFile2, appType1, true);
set_file_time(appFile2, time(NULL) + 1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest9(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
set_version(appFile1, 2);
create_app(appFile2, appType1, true);
set_version(appFile1, 1);
set_file_time(appFile2, time(NULL) + 1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest10(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType2);
set_type_app_hint(appType1, appFile1);
entry_ref appHint;
CHK(BMimeType(appType1).GetAppHint(&appHint) == B_OK);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
#ifdef TEST_R5
CHK(BMimeType(appType2).IsInstalled() == false);
#else
check_app_type(appType2, appFile1);
#endif
}
static
void
CommonFindAppTest11(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
set_type_app_hint(appType1, appFile2);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest12(FindAppCaller &caller)
{
BRoster roster;
create_app(appFile1, appType1);
entry_ref ref;
CHK(caller(appType1, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest13(FindAppCaller &caller)
{
BRoster roster;
struct TextTypeSaver {
TextTypeSaver()
{
BMimeType textType("text");
hasPreferredApp
= (textType.GetPreferredApp(preferredApp) == B_OK);
}
~TextTypeSaver()
{
BMimeType textType("text");
textType.SetPreferredApp(hasPreferredApp ? preferredApp : NULL);
}
bool hasPreferredApp;
char preferredApp[B_MIME_TYPE_LENGTH];
} _saver;
create_app(appFile1, appType1);
CHK(BMimeType("text").SetPreferredApp(appType1) == B_OK);
install_type(textTestType);
entry_ref ref;
CHK(caller(textTestType, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
static
void
CommonFindAppTest14(FindAppCaller &caller)
{
BRoster roster;
create_app(get_trash_app_file(), appType1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_IN_TRASH);
}
static
void
CommonFindAppTest15(FindAppCaller &caller)
{
BRoster roster;
set_type_app_hint(appType1, appFile1);
install_type(fileType1, appType1);
entry_ref ref;
CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
entry_ref appHint;
CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
}
static
void
CommonFindAppTest16(FindAppCaller &caller)
{
BRoster roster;
set_type_app_hint(appType1, appFile1);
install_type(fileType1, appType1);
system((string("ln -s ") + appFile1 + " " + appFile1).c_str());
entry_ref ref;
entry_ref appHint;
#ifdef TEST_R5
CHK(caller(fileType1, &ref) == B_OK);
CHK(ref_for_path(appFile1, false) == ref);
CHK(BMimeType(appType1).GetAppHint(&appHint) == B_OK);
CHK(appHint == ref);
#else
CHK(caller(fileType1, &ref) == B_LAUNCH_FAILED_APP_NOT_FOUND);
CHK(BMimeType(appType1).GetAppHint(&appHint) == B_ENTRY_NOT_FOUND);
#endif
}
typedef void commonTestFunction(FindAppCaller &caller);
static commonTestFunction *commonTestFunctions[] = {
CommonFindAppTest1, CommonFindAppTest2, CommonFindAppTest3,
CommonFindAppTest4, CommonFindAppTest5, CommonFindAppTest6,
CommonFindAppTest7, CommonFindAppTest8, CommonFindAppTest9,
CommonFindAppTest10, CommonFindAppTest11, CommonFindAppTest12,
CommonFindAppTest13, CommonFindAppTest14, CommonFindAppTest15,
CommonFindAppTest16
};
static int32 commonTestFunctionCount
= sizeof(commonTestFunctions) / sizeof(commonTestFunction*);
void FindAppTester::FindAppTestA1()
{
BRoster roster;
CHK(roster.FindApp((const char*)NULL, NULL) == B_BAD_VALUE);
#ifndef TEST_R5
CHK(roster.FindApp("image/gif", NULL) == B_BAD_VALUE);
#endif
entry_ref ref;
CHK(roster.FindApp((const char*)NULL, &ref) == B_BAD_VALUE);
}
void FindAppTester::FindAppTestA2()
{
BRoster roster;
entry_ref ref;
CHK(roster.FindApp("invalid/mine/type", &ref) == B_BAD_VALUE);
}
class FindAppTypeCaller : public FindAppCaller {
public:
virtual status_t operator()(const char *type, entry_ref *ref)
{
BRoster roster;
return roster.FindApp(type, ref);
}
};
void FindAppTester::FindAppTestA3()
{
FindAppTypeCaller caller;
for (int32 i = 0; i < commonTestFunctionCount; i++) {
NextSubTest();
(*commonTestFunctions[i])(caller);
tearDown();
setUp();
}
}
void FindAppTester::FindAppTestB1()
{
BRoster roster;
CHK(roster.FindApp((entry_ref*)NULL, NULL) == B_BAD_VALUE);
#ifndef TEST_R5
create_app(appFile1, appType1);
entry_ref fileRef(create_file(testFile1, fileType1, appType1));
CHK(roster.FindApp(&fileRef, NULL) == B_BAD_VALUE);
#endif
entry_ref ref;
CHK(roster.FindApp((entry_ref*)NULL, &ref) == B_BAD_VALUE);
}
void FindAppTester::FindAppTestB2()
{
BRoster roster;
entry_ref fileRef(ref_for_path(testFile1));
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_ENTRY_NOT_FOUND);
}
void FindAppTester::FindAppTestB3()
{
BRoster roster;
create_app(get_trash_app_file(), appType1);
entry_ref fileRef(create_file(testFile1, fileType1, appType1));
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_LAUNCH_FAILED_APP_IN_TRASH);
}
void FindAppTester::FindAppTestB4()
{
BRoster roster;
create_app(appFile1, appType1);
create_app(appFile2, appType2);
install_type(fileType1, appType1);
entry_ref fileRef(create_file(testFile1, fileType1, appType2));
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_OK);
CHK(ref_for_path(appFile2) == ref);
check_app_type(appType2, appFile2);
}
void FindAppTester::FindAppTestB5()
{
BRoster roster;
create_app(appFile1, appType1);
entry_ref fileRef(create_file(testFile1, NULL, appType1));
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
void FindAppTester::FindAppTestB6()
{
BRoster roster;
create_app(appFile1, appType1);
create_app(appFile2, appType2);
install_type(fileType1, appType1);
entry_ref fileRef(create_file(testFile1, fileType1, NULL, appFile2));
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
void FindAppTester::FindAppTestB7()
{
BRoster roster;
create_app(appFile1, appType1);
install_type(fileType1, appType1);
entry_ref fileRef(create_file(testFile1, fileType1));
system((string("chmod a+x ") + testFile1).c_str());
entry_ref ref;
CHK(roster.FindApp(&fileRef, &ref) == B_OK);
CHK(ref_for_path(testFile1) == ref);
CHK(BMimeType(appType1).IsInstalled() == false);
CHK(BMimeType(fileType1).GetAppHint(&ref) == B_ENTRY_NOT_FOUND);
}
void FindAppTester::FindAppTestB8()
{
BRoster roster;
create_app(appFile1, appType1);
install_type(fileType1, appType1);
create_file(testFile1, fileType1);
system((string("ln -s ") + testFile1 + " " + testLink1).c_str());
entry_ref linkRef(ref_for_path(testLink1, false));
entry_ref ref;
CHK(roster.FindApp(&linkRef, &ref) == B_OK);
CHK(ref_for_path(appFile1) == ref);
check_app_type(appType1, appFile1);
}
class FileWithTypeCaller : public FindAppCaller {
public:
virtual status_t operator()(const char *type, entry_ref *ref)
{
BRoster roster;
entry_ref fileRef(create_file(testFile1, type));
return roster.FindApp(&fileRef, ref);
}
};
void FindAppTester::FindAppTestB9()
{
FileWithTypeCaller caller;
for (int32 i = 0; i < commonTestFunctionCount; i++) {
NextSubTest();
(*commonTestFunctions[i])(caller);
tearDown();
setUp();
}
}
class SniffFileTypeCaller : public FindAppCaller {
public:
virtual status_t operator()(const char *type, entry_ref *ref)
{
BRoster roster;
entry_ref fileRef(create_file(testFile1, type, NULL, NULL,
"UnIQe pAtTeRn"));
install_type(fileType1, NULL, "1.0 [0] ('UnIQe pAtTeRn')");
return roster.FindApp(&fileRef, ref);
}
};
void FindAppTester::FindAppTestB10()
{
SniffFileTypeCaller caller;
for (int32 i = 1; i < commonTestFunctionCount; i++) {
NextSubTest();
(*commonTestFunctions[i])(caller);
tearDown();
setUp();
}
}
void FindAppTester::FindAppTestB11()
{
BRoster roster;
system((string("ln -s ") + testLink1 + " " + testLink1).c_str());
entry_ref linkRef(ref_for_path(testLink1, false));
entry_ref ref;
CHK(roster.FindApp(&linkRef, &ref) == B_LAUNCH_FAILED_NO_RESOLVE_LINK);
}
void FindAppTester::FindAppTestB12()
{
BRoster roster;
system((string("ln -s ") + testFile1 + " " + testLink1).c_str());
entry_ref linkRef(ref_for_path(testLink1, false));
entry_ref ref;
CHK(roster.FindApp(&linkRef, &ref) == B_LAUNCH_FAILED_NO_RESOLVE_LINK);
}
Test* FindAppTester::Suite()
{
TestSuite* SuiteOfTests = new TestSuite;
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestA1);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestA2);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB1);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB2);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB4);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB5);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB6);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB7);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB8);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB11);
ADD_TEST4(BRoster, SuiteOfTests, FindAppTester, FindAppTestB12);
return SuiteOfTests;
}