BApplication tests:

* Added constructor tests.
* Added Run() tests.
* AppRunner -> PipedAppRunner + some improvements
* New AppRunner using ports for data transfer.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@562 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2002-08-03 16:07:02 +00:00
parent 28cdc245d3
commit c9640d94a3
33 changed files with 1915 additions and 110 deletions

View File

@ -13,7 +13,9 @@ CommonTestLib libapptest.so
# BApplication
ApplicationTest.cpp
AppRunner.cpp
AppRunTester.cpp
BApplicationTester.cpp
PipedAppRunner.cpp
# BHandler
HandlerTest.cpp

View File

@ -0,0 +1,819 @@
//------------------------------------------------------------------------------
// AppRunTester.cpp
//
//------------------------------------------------------------------------------
// Standard Includes -----------------------------------------------------------
#include <stdio.h>
// System Includes -------------------------------------------------------------
#include <be/app/Message.h>
#include <be/kernel/OS.h>
#include <Application.h>
#include <Handler.h>
#include <Looper.h>
#include <String.h>
// Project Includes ------------------------------------------------------------
#include <TestShell.h>
#include <TestUtils.h>
#include <cppunit/TestAssert.h>
// Local Includes --------------------------------------------------------------
#include "AppRunner.h"
#include "AppRunTester.h"
// Local Defines ---------------------------------------------------------------
// Globals ---------------------------------------------------------------------
//------------------------------------------------------------------------------
// check_output
static
void
check_output(AppRunner &runner, const char *expectedOutput)
{
BString buffer;
CHK(runner.GetOutput(&buffer) == B_OK);
if (buffer != expectedOutput)
printf("result is `%s', but should be `%s'\n", buffer.String(),
expectedOutput);
CHK(buffer == expectedOutput);
}
/*
thread_id Run()
@case 1 launch the app two times: B_MULTIPLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of
them
@results first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest1()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 = output1;
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp1") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp1") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 2 launch the app two times: B_MULTIPLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of
them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest2()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp1", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp1", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 3 launch the app two times: B_MULTIPLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest3()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 = output1;
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp2") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp2") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 4 launch the app two times: B_MULTIPLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest4()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp2", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp2", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 5 launch the app two times: B_SINGLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest5()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp3") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp3") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 6 launch the app two times: B_SINGLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest6()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp3", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp3", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 7 launch the app two times: B_SINGLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest7()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp4") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp4") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 8 launch the app two times: B_SINGLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
*/
void AppRunTester::RunTest8()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp4", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp4", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 9 launch two apps with the same signature:
B_SINGLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest9()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 = output1;
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp3") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp3a") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 10 launch two apps with the same signature:
B_SINGLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest10()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp3", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp3a", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 11 launch two apps with the same signature:
B_SINGLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest11()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 = output1;
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp4") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp4a") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 12 launch two apps with the same signature:
B_SINGLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
*/
void AppRunTester::RunTest12()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp4", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp4a", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 13 launch the app two times: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest13()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp5") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp5") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 14 launch the app two times: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest14()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp5", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp5", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 15 launch the app two times: B_EXCLUSIVE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest15()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp6") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp6") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 16 launch the app two times: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
*/
void AppRunTester::RunTest16()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp6", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp6", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 17 launch two apps with the same signature:
B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest17()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp5") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp5a") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 18 launch two apps with the same signature:
B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest18()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp5", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp5a", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 19 launch two apps with the same signature: B_EXCLUSIVE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them
@results first app: ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest19()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp6") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp6a") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 20 launch two apps with the same signature: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
*/
void AppRunTester::RunTest20()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp6", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp6a", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 21 launch the app two times: first: B_EXCLUSIVE_LAUNCH,
second: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
*/
void AppRunTester::RunTest21()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::ArgvReceived()\n"
"args: c d e\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp6", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp5", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
/*
thread_id Run()
@case 22 launch the app two times:
first: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
second: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them
@results first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
*/
void AppRunTester::RunTest22()
{
BApplication app("application/x-vnd.obos-app-run-test");
const char *output1 =
"error: 0\n"
"InitCheck(): 0\n"
"BApplication::ArgvReceived()\n"
"args: a b\n"
"BApplication::ReadyToRun()\n"
"BApplication::QuitRequested()\n"
"BApplication::Run() done: 1\n";
const char *output2 =
"error: 80002004\n"
"InitCheck(): 80002004\n";
// run the apps
AppRunner runner1, runner2;
CHK(runner1.Run("AppRunTestApp5", "a b") == B_OK);
runner1.Team();
CHK(runner2.Run("AppRunTestApp6", "c d e") == B_OK);
runner1.WaitFor(true);
runner2.WaitFor(true);
// get the outputs and compare the results
check_output(runner1, output1);
check_output(runner2, output2);
}
Test* AppRunTester::Suite()
{
TestSuite* SuiteOfTests = new TestSuite;
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest1);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest2);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest3);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest4);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest5);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest6);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest7);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest8);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest9);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest10);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest11);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest12);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest13);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest14);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest15);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest16);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest17);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest18);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest19);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest20);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest21);
ADD_TEST4(BApplication, SuiteOfTests, AppRunTester, RunTest22);
return SuiteOfTests;
}

View File

@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
// AppRunTester.h
//
//------------------------------------------------------------------------------
#ifndef APP_RUN_TESTER_H
#define APP_RUN_TESTER_H
// Standard Includes -----------------------------------------------------------
// System Includes -------------------------------------------------------------
// Project Includes ------------------------------------------------------------
// Local Includes --------------------------------------------------------------
#include "../common.h"
// Local Defines ---------------------------------------------------------------
// Globals ---------------------------------------------------------------------
class AppRunTester : public TestCase
{
public:
AppRunTester() {;}
AppRunTester(std::string name) : TestCase(name) {;}
void RunTest1();
void RunTest2();
void RunTest3();
void RunTest4();
void RunTest5();
void RunTest6();
void RunTest7();
void RunTest8();
void RunTest9();
void RunTest10();
void RunTest11();
void RunTest12();
void RunTest13();
void RunTest14();
void RunTest15();
void RunTest16();
void RunTest17();
void RunTest18();
void RunTest19();
void RunTest20();
void RunTest21();
void RunTest22();
static Test* Suite();
};
#endif // APP_RUN_TESTER_H

View File

@ -4,15 +4,25 @@
#include <unistd.h>
#include <Autolock.h>
#include <Messenger.h>
#include <String.h>
#include <TestShell.h>
#include <TestUtils.h>
#include <cppunit/TestAssert.h>
#include "AppRunner.h"
static const char *kAppRunnerTeamPort = "app runner team port";
// constructor
AppRunner::AppRunner()
: fOutputLock(),
fPipe(NULL),
fRemotePort(-1),
fOutput(),
fReader(-1)
fReader(-1),
fTeam(-1),
fMessenger()
{
}
@ -20,7 +30,6 @@ AppRunner::AppRunner()
AppRunner::~AppRunner()
{
if (fReader >= 0) {
_ClosePipe();
int32 result;
wait_for_thread(fReader, &result);
}
@ -28,15 +37,55 @@ AppRunner::~AppRunner()
// Run
status_t
AppRunner::Run(const char *command)
AppRunner::Run(const char *command, const char *args, bool findCommand)
{
status_t error = (HasQuitted() ? B_OK : B_ERROR);
// get the app path
BString appPath;
if (findCommand) {
appPath = BTestShell::GlobalTestDir();
appPath.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\');
appPath += "/kits/app/";
appPath += command;
#ifdef TEST_R5
appPath += "_r5";
#endif
command = appPath.String();
}
// add args, i.e. compose the command line
BString cmdLine(command);
if (args) {
cmdLine += " ";
cmdLine += args;
}
// lock the team port
bool teamPortLocked = false;
if (error == B_OK) {
teamPortLocked = _LockTeamPort();
if (!teamPortLocked)
error = B_ERROR;
}
// run the command
if (error == B_OK) {
fPipe = popen(command, "r");
if (!fPipe)
cmdLine += " &";
if (system(cmdLine.String()) != 0)
error = errno;
}
// read the port ID
if (error == B_OK) {
fRemotePort = _ReadPortID(fMessenger);
if (fRemotePort < 0)
error = fRemotePort;
}
// unlock the team port
if (teamPortLocked)
_UnlockTeamPort();
// get the team ID
if (error == B_OK) {
port_info info;
error = get_port_info(fRemotePort, &info);
fTeam = info.team;
}
// spawn the reader thread
if (error == B_OK) {
fReader = spawn_thread(&_ReaderEntry, "AppRunner reader",
@ -52,10 +101,6 @@ AppRunner::Run(const char *command)
kill_thread(fReader);
fReader = -1;
}
if (fPipe) {
pclose(fPipe);
fPipe = NULL;
}
}
return error;
}
@ -64,8 +109,55 @@ AppRunner::Run(const char *command)
bool
AppRunner::HasQuitted()
{
BAutolock locker(fOutputLock);
return !fPipe;
port_info info;
return (get_port_info(fRemotePort, &info) != B_OK);
}
// WaitFor
void
AppRunner::WaitFor(bool requestQuit)
{
if (!HasQuitted() && requestQuit)
RequestQuit();
while (!HasQuitted())
snooze(10000);
}
// Team
team_id
AppRunner::Team()
{
return fTeam;
}
// RequestQuit
status_t
AppRunner::RequestQuit()
{
status_t error = B_OK;
if (fTeam >= 0) {
BMessenger messenger(fMessenger);
error = messenger.SendMessage(B_QUIT_REQUESTED);
} else
error = fTeam;
return error;
}
// GetOutput
status_t
AppRunner::GetOutput(BString *buffer)
{
status_t error = (buffer ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BAutolock locker(fOutputLock);
size_t size = fOutput.BufferLength();
const void *output = fOutput.Buffer();
if (size > 0)
buffer->SetTo((const char*)output, size);
else
*buffer = "";
}
return error;
}
// ReadOutput
@ -99,32 +191,62 @@ int32
AppRunner::_ReaderLoop()
{
char buffer[10240];
fOutputLock.Lock();
FILE *pipe = fPipe;
fOutputLock.Unlock();
while (!feof(pipe)) {
size_t bytes = fread(buffer, 1, sizeof(buffer), pipe);
port_id port = fRemotePort;
status_t error = B_OK;
while (error == B_OK) {
int32 code;
ssize_t bytes = read_port(port, &code, buffer, sizeof(buffer) - 1);
if (bytes > 0) {
// write the buffer
BAutolock locker(fOutputLock);
off_t oldPosition = fOutput.Seek(0, SEEK_END);
fOutput.Write(buffer, bytes);
fOutput.Seek(oldPosition, SEEK_SET);
}
} else if (bytes < 0)
error = bytes;
}
_ClosePipe();
fRemotePort = -1;
return 0;
}
// _ClosePipe
void
AppRunner::_ClosePipe()
// _LockTeamPort
bool
AppRunner::_LockTeamPort()
{
if (fOutputLock.Lock()) {
if (fPipe) {
pclose(fPipe);
fPipe = NULL;
bool result = fTeamPortLock.Lock();
// lazy port creation
if (result && fTeamPort < 0) {
fTeamPort = create_port(5, kAppRunnerTeamPort);
if (fTeamPort < 0) {
fTeamPortLock.Unlock();
result = false;
}
fOutputLock.Unlock();
}
return result;
}
// _UnlockTeamPort
void
AppRunner::_UnlockTeamPort()
{
fTeamPortLock.Unlock();
}
// _ReadPortID
port_id
AppRunner::_ReadPortID(BMessenger &messenger)
{
port_id port = -1;
ssize_t size = read_port(fTeamPort, &port, &messenger, sizeof(BMessenger));
if (size < 0)
port = size;
return port;
}
// fTeamPort
port_id AppRunner::fTeamPort = -1;
// fTeamPortLock
BLocker AppRunner::fTeamPortLock;

View File

@ -13,22 +13,35 @@ public:
AppRunner();
~AppRunner();
status_t Run(const char *command);
status_t Run(const char *command, const char *args = NULL,
bool findCommand = true);
bool HasQuitted();
void WaitFor(bool requestQuit = false);
team_id Team();
status_t RequestQuit();
status_t GetOutput(BString *buffer);
ssize_t ReadOutput(void *buffer, size_t size);
ssize_t ReadOutputAt(off_t position, void *buffer, size_t size);
private:
static int32 _ReaderEntry(void *data);
int32 _ReaderLoop();
void _ClosePipe();
static bool _LockTeamPort();
static void _UnlockTeamPort();
static port_id _ReadPortID(BMessenger &messenger);
private:
BLocker fOutputLock;
FILE *fPipe;
port_id fRemotePort;
BMallocIO fOutput;
thread_id fReader;
team_id fTeam;
BMessenger fMessenger;
static port_id fTeamPort;
static BLocker fTeamPortLock;
};
#endif // APP_RUNNER_H

View File

@ -1,10 +1,12 @@
#include "../common.h"
#include "AppRunTester.h"
#include "BApplicationTester.h"
CppUnit::Test* ApplicationTestSuite()
{
CppUnit::TestSuite *testSuite = new CppUnit::TestSuite();
testSuite->addTest(AppRunTester::Suite());
testSuite->addTest(TBApplicationTester::Suite());
return testSuite;

View File

@ -15,8 +15,116 @@ case 5: signature is a valid MIME string with "application" supertype,
Shouldn't print anything at all and continue.
InitCheck() should return B_OK.
BApplication(const char *signature, status_t *error)
cases similar to those of BApplication(const char *), if error is NULL,
otherwise error is set to the same value as returned by InitCheck()
otherwise the app does not quit and error is set to the same value as
returned by InitCheck(), which is B_BAD_VALUE on error.
thread_id Run()
case 1: launch the app two times: B_MULTIPLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
case 2: launch the app two times: B_MULTIPLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
case 3: launch the app two times: B_MULTIPLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
case 4: launch the app two times: B_MULTIPLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
case 5: launch the app two times: B_SINGLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 6: launch the app two times: B_SINGLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
case 7: launch the app two times: B_SINGLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 8: launch the app two times: B_SINGLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
case 9: launch two apps with the same signature: B_SINGLE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
case 10:launch two apps with the same signature: B_SINGLE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
case 11:launch two apps with the same signature: B_SINGLE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: ReadyToRun(), QuitRequested()
case 12:launch two apps with the same signature: B_SINGLE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: ArgvReceived(), ReadyToRun(), QuitRequested()
case 13:launch the app two times: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 14:launch the app two times: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
case 15:launch the app two times: B_EXCLUSIVE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 16:launch the app two times: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
case 17:launch two apps with the same signature:
B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 18:launch two apps with the same signature:
B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
case 19:launch two apps with the same signature: B_EXCLUSIVE_LAUNCH,
no command line args, send B_QUIT_REQUESTED to both of them =>
first app: ReadyToRun(), QuitRequested()
second app: quits
case 20:launch two apps with the same signature: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
case 21:launch the app two times: first: B_EXCLUSIVE_LAUNCH,
second: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), ArgvReceived(),
QuitRequested()
second app: quits
case 22:launch the app two times: first: B_EXCLUSIVE_LAUNCH | B_ARGV_ONLY,
second: B_EXCLUSIVE_LAUNCH,
command line args, send B_QUIT_REQUESTED to both of them =>
first app: ArgvReceived(), ReadyToRun(), QuitRequested()
second app: quits
void Quit()
TODO
bool QuitRequested()
TODO

View File

@ -21,7 +21,7 @@
#include <cppunit/TestAssert.h>
// Local Includes --------------------------------------------------------------
#include "AppRunner.h"
#include "PipedAppRunner.h"
#include "BApplicationTester.h"
// Local Defines ---------------------------------------------------------------
@ -35,27 +35,17 @@ static
void
test_app(const char *app, const char *expectedResult)
{
// construct an absolute path to the app
BString appPath(BTestShell::GlobalTestDir());
appPath.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\');
appPath += "/kits/app/";
appPath += app;
#ifdef TEST_R5
appPath += "_r5";
#endif
// run the app
AppRunner runner;
CHK(runner.Run(appPath.String()) == B_OK);
while (!runner.HasQuitted())
snooze(10000);
// read the output and compare the result
char buffer[1024];
ssize_t read = runner.ReadOutput(buffer, sizeof(buffer) - 1);
CHK(read >= 0);
buffer[read] = '\0';
if (strcmp(buffer, expectedResult))
printf("result is `%s', but should be `%s'\n", buffer, expectedResult);
CHK(!strcmp(buffer, expectedResult));
PipedAppRunner runner;
CHK(runner.Run(app) == B_OK);
runner.WaitFor();
// get the output and compare the result
BString buffer;
CHK(runner.GetOutput(&buffer) == B_OK);
if (buffer != expectedResult)
printf("result is `%s', but should be `%s'\n", buffer.String(),
expectedResult);
CHK(buffer == expectedResult);
}
@ -66,10 +56,19 @@ printf("result is `%s', but should be `%s'\n", buffer, expectedResult);
*/
void TBApplicationTester::BApplication1()
{
test_app("BApplicationTestApp1",
"bad signature ((null)), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n");
const char *output1 =
"bad signature ((null)), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n";
const char *output2 =
"bad signature ((null)), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n"
"error: 80000005\n"
"InitCheck(): 80000005\n";
test_app("BApplicationTestApp1", output1);
test_app("BApplicationTestApp1a", output1);
test_app("BApplicationTestApp1b", output2);
}
/*
@ -79,10 +78,19 @@ void TBApplicationTester::BApplication1()
*/
void TBApplicationTester::BApplication2()
{
test_app("BApplicationTestApp2",
"bad signature (no valid MIME string), must begin with "
"\"application/\" and can't conflict with existing registered "
"mime types inside the \"application\" media type.\n");
const char *output1 =
"bad signature (no valid MIME string), must begin with "
"\"application/\" and can't conflict with existing registered "
"mime types inside the \"application\" media type.\n";
const char *output2 =
"bad signature (no valid MIME string), must begin with "
"\"application/\" and can't conflict with existing registered "
"mime types inside the \"application\" media type.\n"
"error: 80000005\n"
"InitCheck(): 80000005\n";
test_app("BApplicationTestApp2", output1);
test_app("BApplicationTestApp2a", output1);
test_app("BApplicationTestApp2b", output2);
}
/*
@ -93,10 +101,19 @@ void TBApplicationTester::BApplication2()
*/
void TBApplicationTester::BApplication3()
{
test_app("BApplicationTestApp3",
"bad signature (image/gif), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n");
const char *output1 =
"bad signature (image/gif), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n";
const char *output2 =
"bad signature (image/gif), must begin with \"application/\" and "
"can't conflict with existing registered mime types inside "
"the \"application\" media type.\n"
"error: 80000005\n"
"InitCheck(): 80000005\n";
test_app("BApplicationTestApp3", output1);
test_app("BApplicationTestApp3a", output1);
test_app("BApplicationTestApp3b", output2);
}
/*
@ -109,12 +126,20 @@ void TBApplicationTester::BApplication3()
*/
void TBApplicationTester::BApplication4()
{
test_app("BApplicationTestApp4",
"Signature in rsrc doesn't match constructor arg. "
"(application/x-vnd.obos-bapplication-testapp4,"
"application/x-vnd.obos-bapplication-testapp4-or-not)\n"
"InitCheck(): 0\n");
const char *output1 =
"Signature in rsrc doesn't match constructor arg. "
"(application/x-vnd.obos-bapplication-testapp4,"
"application/x-vnd.obos-bapplication-testapp4-or-not)\n"
"InitCheck(): 0\n";
const char *output2 =
"Signature in rsrc doesn't match constructor arg. "
"(application/x-vnd.obos-bapplication-testapp4,"
"application/x-vnd.obos-bapplication-testapp4-or-not)\n"
"error: 0\n"
"InitCheck(): 0\n";
test_app("BApplicationTestApp4", output1);
test_app("BApplicationTestApp4a", output1);
test_app("BApplicationTestApp4b", output2);
}
/*
@ -126,7 +151,13 @@ void TBApplicationTester::BApplication4()
*/
void TBApplicationTester::BApplication5()
{
test_app("BApplicationTestApp5", "InitCheck(): 0\n");
const char *output1 = "InitCheck(): 0\n";
const char *output2 =
"error: 0\n"
"InitCheck(): 0\n";
test_app("BApplicationTestApp5", output1);
test_app("BApplicationTestApp5a", output1);
test_app("BApplicationTestApp5b", output2);
}

View File

@ -0,0 +1,178 @@
// PipedAppRunner.cpp
#include <errno.h>
#include <unistd.h>
#include <Autolock.h>
#include <String.h>
#include <TestShell.h>
#include <TestUtils.h>
#include <cppunit/TestAssert.h>
#include "PipedAppRunner.h"
// constructor
PipedAppRunner::PipedAppRunner()
: fOutputLock(),
fPipe(NULL),
fOutput(),
fReader(-1)
{
}
// destructor
PipedAppRunner::~PipedAppRunner()
{
if (fReader >= 0) {
_ClosePipe();
int32 result;
wait_for_thread(fReader, &result);
}
}
// Run
status_t
PipedAppRunner::Run(const char *command, const char *args, bool findCommand)
{
status_t error = (HasQuitted() ? B_OK : B_ERROR);
// get the app path
BString appPath;
if (findCommand) {
appPath = BTestShell::GlobalTestDir();
appPath.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\');
appPath += "/kits/app/";
appPath += command;
#ifdef TEST_R5
appPath += "_r5";
#endif
command = appPath.String();
}
// add args, i.e. compose the command line
BString cmdLine(command);
if (args) {
cmdLine += " ";
cmdLine += args;
}
// run the command
if (error == B_OK) {
fPipe = popen(cmdLine.String(), "r");
if (!fPipe)
error = errno;
}
// spawn the reader thread
if (error == B_OK) {
fReader = spawn_thread(&_ReaderEntry, "PipedAppRunner reader",
B_NORMAL_PRIORITY, (void*)this);
if (fReader >= 0)
error = resume_thread(fReader);
else
error = fReader;
}
// cleanup on error
if (error != B_OK) {
if (fReader >= 0) {
kill_thread(fReader);
fReader = -1;
}
if (fPipe) {
pclose(fPipe);
fPipe = NULL;
}
}
return error;
}
// HasQuitted
bool
PipedAppRunner::HasQuitted()
{
BAutolock locker(fOutputLock);
return !fPipe;
}
// WaitFor
void
PipedAppRunner::WaitFor()
{
while (!HasQuitted())
snooze(10000);
}
// GetOutput
status_t
PipedAppRunner::GetOutput(BString *buffer)
{
status_t error = (buffer ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
BAutolock locker(fOutputLock);
size_t size = fOutput.BufferLength();
const void *output = fOutput.Buffer();
if (size > 0)
buffer->SetTo((const char*)output, size);
else
*buffer = "";
}
return error;
}
// ReadOutput
ssize_t
PipedAppRunner::ReadOutput(void *buffer, size_t size)
{
BAutolock locker(fOutputLock);
return fOutput.Read(buffer, size);
}
// ReadOutputAt
ssize_t
PipedAppRunner::ReadOutputAt(off_t position, void *buffer, size_t size)
{
BAutolock locker(fOutputLock);
return fOutput.ReadAt(position, buffer, size);
}
// _ReaderEntry
int32
PipedAppRunner::_ReaderEntry(void *data)
{
int32 result = 0;
if (PipedAppRunner *me = (PipedAppRunner*)data)
result = me->_ReaderLoop();
return result;
}
// _ReaderLoop
int32
PipedAppRunner::_ReaderLoop()
{
char buffer[10240];
fOutputLock.Lock();
FILE *pipe = fPipe;
fOutputLock.Unlock();
while (!feof(pipe)) {
size_t bytes = fread(buffer, 1, sizeof(buffer), pipe);
if (bytes > 0) {
BAutolock locker(fOutputLock);
off_t oldPosition = fOutput.Seek(0, SEEK_END);
fOutput.Write(buffer, bytes);
fOutput.Seek(oldPosition, SEEK_SET);
}
}
_ClosePipe();
return 0;
}
// _ClosePipe
void
PipedAppRunner::_ClosePipe()
{
if (fOutputLock.Lock()) {
if (fPipe) {
pclose(fPipe);
fPipe = NULL;
}
fOutputLock.Unlock();
}
}

View File

@ -0,0 +1,37 @@
// PipedAppRunner.h
#ifndef PIPED_APP_RUNNER_H
#define PIPED_APP_RUNNER_H
#include <stdio.h>
#include <DataIO.h>
#include <Locker.h>
class PipedAppRunner {
public:
PipedAppRunner();
~PipedAppRunner();
status_t Run(const char *command, const char *args = NULL,
bool findCommand = true);
bool HasQuitted();
void WaitFor();
status_t GetOutput(BString *buffer);
ssize_t ReadOutput(void *buffer, size_t size);
ssize_t ReadOutputAt(off_t position, void *buffer, size_t size);
private:
static int32 _ReaderEntry(void *data);
int32 _ReaderLoop();
void _ClosePipe();
private:
BLocker fOutputLock;
FILE *fPipe;
BMallocIO fOutput;
thread_id fReader;
};
#endif // PIPED_APP_RUNNER_H

View File

@ -0,0 +1,26 @@
// AppRunTestApp1.cpp
#include <stdio.h>
#include <OS.h>
#include "CommonTestApp.h"
int
main()
{
// R5: doesn't set the error variable in case of success
#ifdef TEST_R5
status_t error = B_OK;
#else
status_t error = B_ERROR;
#endif
CommonTestApp app("application/x-vnd.obos-app-run-testapp1", &error);
init_connection();
report("error: %lx\n", error);
report("InitCheck(): %lx\n", app.InitCheck());
if (error == B_OK)
app.Run();
return 0;
}

View File

@ -1,11 +1,14 @@
// BApplicationTestApp1.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app((const char*)NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,14 @@
// BApplicationTestApp1a.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app((const char*)NULL, NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,16 @@
// BApplicationTestApp1b.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
status_t error = B_OK;
BApplication app((const char*)NULL, &error);
printf("error: %lx\n", error);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -1,11 +1,14 @@
// BApplicationTestApp2.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("no valid MIME string");
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,14 @@
// BApplicationTestApp2a.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("no valid MIME string", NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,16 @@
// BApplicationTestApp2b.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
status_t error = B_OK;
BApplication app("no valid MIME string", &error);
printf("error: %lx\n", error);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -1,11 +1,14 @@
// BApplicationTestApp3.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("image/gif");
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,14 @@
// BApplicationTestApp3a.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("image/gif", NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,16 @@
// BApplicationTestApp3b.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
status_t error = B_OK;
BApplication app("image/gif", &error);
printf("error: %lx\n", error);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,14 @@
// BApplicationTestApp4a.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("application/x-vnd.obos-bapplication-testapp4", NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,16 @@
// BApplicationTestApp4b.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
status_t error = B_OK;
BApplication app("application/x-vnd.obos-bapplication-testapp4", &error);
printf("error: %lx\n", error);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,14 @@
// BApplicationTestApp5a.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
BApplication app("application/x-vnd.obos-bapplication-testapp5", NULL);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,16 @@
// BApplicationTestApp5b.cpp
#include <stdio.h>
#include <Application.h>
int
main()
{
status_t error = B_OK;
BApplication app("application/x-vnd.obos-bapplication-testapp5", &error);
printf("error: %lx\n", error);
printf("InitCheck(): %lx\n", app.InitCheck());
return 0;
}

View File

@ -0,0 +1,175 @@
// CommonTestApp.cpp
#include <stdio.h>
#include <OS.h>
#include "CommonTestApp.h"
// constructor
CommonTestApp::CommonTestApp(const char *signature)
: BApplication(signature),
fQuitOnSecondTry(false),
fQuitter(-1),
fQuittingDelay(0),
fQuittingTries(1)
{
}
// constructor
CommonTestApp::CommonTestApp(const char *signature, status_t *result)
: BApplication(signature, result)
{
}
// destructor
CommonTestApp::~CommonTestApp()
{
if (fQuitter >= 0) {
int32 result;
wait_for_thread(fQuitter, &result);
}
}
// ArgvReceived
void
CommonTestApp::ArgvReceived(int32 argc, char **argv)
{
report("BApplication::ArgvReceived()\n");
if (argc > 1) {
report("args:");
for (int32 i = 1; i < argc; i++)
report(" %s", argv[i]);
report("\n");
}
}
// QuitRequested
bool
CommonTestApp::QuitRequested()
{
report("BApplication::QuitRequested()\n");
static bool firstTry = true;
if (firstTry && fQuitOnSecondTry) {
firstTry = false;
return false;
}
return BApplication::QuitRequested();
}
// ReadyToRun
void
CommonTestApp::ReadyToRun()
{
report("BApplication::ReadyToRun()\n");
}
// Run
thread_id
CommonTestApp::Run()
{
thread_id result = BApplication::Run();
report("BApplication::Run() done: %d\n", (result == find_thread(NULL)));
return result;
}
// SetQuittingPolicy
void
CommonTestApp::SetQuittingPolicy(bool onSecondTry)
{
fQuitOnSecondTry = onSecondTry;
}
// RunQuitterThread
status_t
CommonTestApp::RunQuitterThread(bigtime_t delay, int32 tries)
{
status_t error = B_OK;
fQuittingDelay = delay;
fQuittingTries = tries;
// spawn the thread
fQuitter = spawn_thread(&_QuitterEntry, "quitter thread",
B_NORMAL_PRIORITY, this);
if (fQuitter < 0)
error = fQuitter;
if (error == B_OK)
error = resume_thread(fQuitter);
// cleanup on error
if (error != B_OK && fQuitter >= 0) {
kill_thread(fQuitter);
fQuitter = -1;
}
return error;
}
// _QuitterEntry
int32
CommonTestApp::_QuitterEntry(void *data)
{
int32 result = 0;
if (CommonTestApp *app = (CommonTestApp*)data)
result = app->_QuitterLoop();
return result;
}
// _QuitterLoop
int32
CommonTestApp::_QuitterLoop()
{
for (; fQuittingTries > 0; fQuittingTries--) {
snooze(fQuittingDelay);
PostMessage(B_QUIT_REQUESTED, this);
}
return 0;
}
static const char *kAppRunnerTeamPort = "app runner team port";
static port_id outputPort = -1;
// init_connection
status_t
init_connection()
{
status_t error = B_OK;
// create a port
outputPort = create_port(10, "common test app port");
if (outputPort < 0)
error = outputPort;
// find the remote port
port_id port = -1;
if (error == B_OK) {
port = find_port(kAppRunnerTeamPort);
if (port < 0)
error = port;
}
// send the port ID
if (error == B_OK) {
ssize_t written = write_port(port, outputPort, &be_app_messenger,
sizeof(BMessenger));
if (written < 0)
error = written;
}
return error;
}
// report
void
report(const char *format,...)
{
va_list args;
va_start(args, format);
vreport(format, args);
va_end(args);
}
// vreport
void
vreport(const char *format, va_list args)
{
char buffer[10240];
vsprintf(buffer, format, args);
int32 length = strlen(buffer);
write_port(outputPort, 0, buffer, length);
}

View File

@ -0,0 +1,40 @@
// CommonTestApp.h
#ifndef COMMON_TEST_APP_H
#define COMMON_TEST_APP_H
#include <stdarg.h>
#include <Application.h>
class CommonTestApp : public BApplication {
public:
CommonTestApp(const char *signature);
CommonTestApp(const char *signature, status_t *result);
virtual ~CommonTestApp();
virtual void ArgvReceived(int32 argc, char **argv);
virtual bool QuitRequested();
virtual void ReadyToRun();
thread_id Run();
void SetQuittingPolicy(bool onSecondTry);
status_t RunQuitterThread(bigtime_t delay, int32 tries);
private:
static int32 _QuitterEntry(void *data);
int32 _QuitterLoop();
private:
bool fQuitOnSecondTry;
thread_id fQuitter;
bigtime_t fQuittingDelay;
int32 fQuittingTries;
};
status_t init_connection();
void report(const char *format,...);
void vreport(const char *format, va_list args);
#endif // COMMON_TEST_APP_H

View File

@ -1,45 +1,83 @@
SubDir OBOS_TOP src tests kits app bapplication testapps ;
CommonUnitTest BApplicationTestApp1
: BApplicationTestApp1.cpp
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
rule SimpleBAppTestApp
{
# SimpleBAppTestApp <sources> : <resources> ;
local sources = $(1) ;
local resources = $(2) ;
local name = $(sources[1]) ;
name = $(name:B) ;
SimpleBAppTestApp2 $(name) : $(sources) : $(resources) ;
}
CommonUnitTest BApplicationTestApp2
: BApplicationTestApp2.cpp
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
rule SimpleBAppTestApp2
{
# SimpleBAppTestApp <name> : <sources> : <resources> ;
local name = $(1) ;
local sources = $(2) ;
local resources = $(3) ;
local r5name = $(name)_r5 ;
CommonUnitTest BApplicationTestApp3
: BApplicationTestApp3.cpp
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
if $(resources) {
AddResources $(name) : $(resources) ;
AddResources $(r5name) : $(resources) ;
}
CommonUnitTest $(name)
: $(sources)
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
}
AddResources BApplicationTestApp4 : BApplicationTestApp4.rsrc ;
AddResources BApplicationTestApp4_r5 : BApplicationTestApp4.rsrc ;
CommonUnitTest BApplicationTestApp4
: BApplicationTestApp4.cpp
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
rule CopyBAppTestApp
{
# CopyBAppTestApp <target> : <source> ;
local target = $(1) ;
local source = $(2) ;
local r5target = $(target)_r5 ;
local r5source = $(source)_r5 ;
MakeLocate $(target) : [ FDirName $(OBOS_TEST_DIR) kits app ] ;
MakeLocate $(r5target) : [ FDirName $(OBOS_TEST_DIR) kits app ] ;
File $(target) : $(source) ;
File $(r5target) : $(r5source) ;
local file ;
for file in $(target) $(r5target) {
MODE on $(file) = $(EXEMODE) ;
MimeSet $(file) ;
}
}
AddResources BApplicationTestApp5 : BApplicationTestApp5.rsrc ;
AddResources BApplicationTestApp5_r5 : BApplicationTestApp5.rsrc ;
CommonUnitTest BApplicationTestApp5
: BApplicationTestApp5.cpp
: kits app
: <boot!home!config!lib>libopenbeos.so be stdc++.r4
: be stdc++.r4
: app support
;
SimpleBAppTestApp BApplicationTestApp1.cpp ;
SimpleBAppTestApp BApplicationTestApp1a.cpp ;
SimpleBAppTestApp BApplicationTestApp1b.cpp ;
SimpleBAppTestApp BApplicationTestApp2.cpp ;
SimpleBAppTestApp BApplicationTestApp2a.cpp ;
SimpleBAppTestApp BApplicationTestApp2b.cpp ;
SimpleBAppTestApp BApplicationTestApp3.cpp ;
SimpleBAppTestApp BApplicationTestApp3a.cpp ;
SimpleBAppTestApp BApplicationTestApp3b.cpp ;
SimpleBAppTestApp BApplicationTestApp4.cpp : BApplicationTestApp4.rsrc ;
SimpleBAppTestApp BApplicationTestApp4a.cpp : BApplicationTestApp4.rsrc ;
SimpleBAppTestApp BApplicationTestApp4b.cpp : BApplicationTestApp4.rsrc ;
SimpleBAppTestApp BApplicationTestApp5.cpp : BApplicationTestApp5.rsrc ;
SimpleBAppTestApp BApplicationTestApp5a.cpp : BApplicationTestApp5.rsrc ;
SimpleBAppTestApp BApplicationTestApp5b.cpp : BApplicationTestApp5.rsrc ;
SimpleBAppTestApp AppRunTestApp1.cpp CommonTestApp.cpp : AppRunTestApp1.rsrc ;
SimpleBAppTestApp2 AppRunTestApp2 : AppRunTestApp1.o CommonTestApp.o
: AppRunTestApp2.rsrc ;
SimpleBAppTestApp2 AppRunTestApp3 : AppRunTestApp1.o CommonTestApp.o
: AppRunTestApp3.rsrc ;
SimpleBAppTestApp2 AppRunTestApp4 : AppRunTestApp1.o CommonTestApp.o
: AppRunTestApp4.rsrc ;
SimpleBAppTestApp2 AppRunTestApp5 : AppRunTestApp1.o CommonTestApp.o
: AppRunTestApp5.rsrc ;
SimpleBAppTestApp2 AppRunTestApp6 : AppRunTestApp1.o CommonTestApp.o
: AppRunTestApp6.rsrc ;
CopyBAppTestApp AppRunTestApp3a : AppRunTestApp3 ;
CopyBAppTestApp AppRunTestApp4a : AppRunTestApp4 ;
CopyBAppTestApp AppRunTestApp5a : AppRunTestApp5 ;
CopyBAppTestApp AppRunTestApp6a : AppRunTestApp6 ;