1//------------------------------------------------------------------------------
2//	GetAppInfoTester.cpp
3//
4//------------------------------------------------------------------------------
5
6// Standard Includes -----------------------------------------------------------
7#include <stdio.h>
8
9// System Includes -------------------------------------------------------------
10#include <Message.h>
11#include <OS.h>
12#include <Handler.h>
13#include <Looper.h>
14#include <Roster.h>
15#include <String.h>
16
17// Project Includes ------------------------------------------------------------
18#include <TestShell.h>
19#include <TestUtils.h>
20#include <cppunit/TestAssert.h>
21
22// Local Includes --------------------------------------------------------------
23#include "AppRunner.h"
24#include "GetAppInfoTester.h"
25
26// Local Defines ---------------------------------------------------------------
27
28// Globals ---------------------------------------------------------------------
29
30//------------------------------------------------------------------------------
31
32// check_app_info
33static
34bool
35check_app_info(app_info &info, AppRunner &runner, const char *signature,
36			   uint32 flags)
37{
38	team_id team = runner.Team();
39	// get the thread
40	thread_id thread = -1;
41	int32 cookie = 0;
42	thread_info threadInfo;
43	while (get_next_thread_info(team, &cookie, &threadInfo) == B_OK) {
44		if (thread < 0 || threadInfo.thread < thread)
45			thread = threadInfo.thread;
46	}
47	// get port and ref
48	port_id port = runner.AppLooperPort();
49	entry_ref ref;
50	runner.GetRef(&ref);
51	// compare
52//printf("check_app_info(): "
53//"  thread:    %ld vs %ld\n"
54//"  team:      %ld vs %ld\n"
55//"  port:      %ld vs %ld\n"
56//"  flags:     %lx  vs %lx\n"
57//"  signature: `%s' vs `%s'\n", info.thread, thread, info.team, team,
58//info.port, port, info.flags, flags, info.signature, signature);
59//printf("  ref:       (%ld, %lld, `%s') vs (%ld, %lld, `%s')\n",
60//info.ref.device, info.ref.directory, info.ref.name,
61//ref.device, ref.directory, ref.name);
62	return (info.thread == thread && info.team == team && info.port == port
63			&& info.flags == flags && info.ref == ref
64			&& !strncmp(info.signature, signature, B_MIME_TYPE_LENGTH));
65}
66
67/*
68	status_t GetAppInfo(const char *signature, app_info *info) const
69	@case 1			signature is NULL or info is NULL
70	@results		Should return B_BAD_VALUE.
71*/
72void GetAppInfoTester::GetAppInfoTestA1()
73{
74	BRoster roster;
75	app_info info;
76	CHK(roster.GetAppInfo((const char*)NULL, NULL) == B_BAD_VALUE);
77	CHK(roster.GetAppInfo((const char*)NULL, &info) == B_BAD_VALUE);
78// R5: crashes when passing a NULL app_info
79#ifndef TEST_R5
80	CHK(roster.GetAppInfo("application/x-vnd.obos-app-run-testapp1",
81						  NULL) == B_BAD_VALUE);
82#endif
83}
84
85/*
86	status_t GetAppInfo(const char *signature, app_info *info) const
87	@case 2			signature/info are not NULL, but no app with this
88					signature is running
89	@results		Should return B_ERROR.
90*/
91void GetAppInfoTester::GetAppInfoTestA2()
92{
93	BRoster roster;
94	app_info info;
95	CHK(roster.GetAppInfo("application/x-vnd.obos-app-run-testapp1", &info)
96		== B_ERROR);
97}
98
99/*
100	status_t GetAppInfo(const char *signature, app_info *info) const
101	@case 3			signature/info are not NULL and an (two) app(s) with this
102					signature is (are) running; quit one; quit the second one
103	@results		Should
104					- fill the app info with the data of one of the apps and
105					  return B_OK;
106					- fill the app info with the data of the second apps and
107					  return B_OK;
108					- return B_ERROR.
109*/
110void GetAppInfoTester::GetAppInfoTestA3()
111{
112	const char *signature = "application/x-vnd.obos-app-run-testapp1";
113	uint32 flags = B_MULTIPLE_LAUNCH | B_ARGV_ONLY;
114	// run the remote apps
115	AppRunner runner1(true);
116	AppRunner runner2(true);
117	CHK(runner1.Run("AppRunTestApp1") == B_OK);
118	CHK(runner2.Run("AppRunTestApp1") == B_OK);
119	// create the BRoster and perform the tests
120	BRoster roster;
121	app_info info1;
122	CHK(roster.GetAppInfo(signature, &info1) == B_OK);
123	CHK(check_app_info(info1, runner1, signature, flags)
124		|| check_app_info(info1, runner2, signature, flags));
125	// quit app 1
126	runner1.WaitFor(true);
127	app_info info2;
128	CHK(roster.GetAppInfo(signature, &info2) == B_OK);
129	CHK(check_app_info(info2, runner2, signature, flags));
130	// quit app 2
131	runner2.WaitFor(true);
132	CHK(roster.GetAppInfo(signature, &info1) == B_ERROR);
133}
134
135/*
136	status_t GetAppInfo(entry_ref *ref, app_info *info) const
137	@case 1			ref is NULL or info is NULL
138	@results		Should return B_BAD_VALUE.
139*/
140void GetAppInfoTester::GetAppInfoTestB1()
141{
142	BRoster roster;
143	entry_ref ref;
144	CHK(find_test_app("AppRunTestApp1", &ref) == B_OK);
145	app_info info;
146	CHK(roster.GetAppInfo((entry_ref*)NULL, NULL) == B_BAD_VALUE);
147	CHK(roster.GetAppInfo((entry_ref*)NULL, &info) == B_BAD_VALUE);
148// R5: crashes when passing a NULL app_info
149#ifndef TEST_R5
150	CHK(roster.GetAppInfo(&ref, NULL) == B_BAD_VALUE);
151#endif
152}
153
154/*
155	status_t GetAppInfo(entry_ref *ref, app_info *info) const
156	@case 2			ref/info are not NULL, but no app with this ref is running
157	@results		Should return B_ERROR.
158*/
159void GetAppInfoTester::GetAppInfoTestB2()
160{
161	BRoster roster;
162	entry_ref ref;
163	CHK(find_test_app("AppRunTestApp1", &ref) == B_OK);
164	app_info info;
165	CHK(roster.GetAppInfo(&ref, &info) == B_ERROR);
166}
167
168/*
169	status_t GetAppInfo(entry_ref *ref, app_info *info) const
170	@case 3			ref/info are not NULL and an (two) app(s) with this ref
171					is (are) running; quit one; quit the second one
172	@results		Should
173					- fill the app info with the data of one of the apps and
174					  return B_OK;
175					- fill the app info with the data of the second apps and
176					  return B_OK;
177					- return B_ERROR.
178*/
179void GetAppInfoTester::GetAppInfoTestB3()
180{
181	const char *signature = "application/x-vnd.obos-app-run-testapp1";
182	uint32 flags = B_MULTIPLE_LAUNCH | B_ARGV_ONLY;
183	entry_ref ref;
184	CHK(find_test_app("AppRunTestApp1", &ref) == B_OK);
185	// run the remote apps
186	AppRunner runner1(true);
187	AppRunner runner2(true);
188	CHK(runner1.Run("AppRunTestApp1") == B_OK);
189	CHK(runner2.Run("AppRunTestApp1") == B_OK);
190	// create the BRoster and perform the tests
191	BRoster roster;
192	app_info info1;
193	CHK(roster.GetAppInfo(&ref, &info1) == B_OK);
194	CHK(check_app_info(info1, runner1, signature, flags)
195		|| check_app_info(info1, runner2, signature, flags));
196	// quit app 1
197	runner1.WaitFor(true);
198	app_info info2;
199	CHK(roster.GetAppInfo(&ref, &info2) == B_OK);
200	CHK(check_app_info(info2, runner2, signature, flags));
201	// quit app 2
202	runner2.WaitFor(true);
203	CHK(roster.GetAppInfo(&ref, &info1) == B_ERROR);
204}
205
206/*
207	status_t GetRunningAppInfo(team_id team, app_info *info) const
208	@case 1			info is NULL
209	@results		Should return B_BAD_VALUE.
210*/
211void GetAppInfoTester::GetRunningAppInfoTest1()
212{
213// R5: crashes when passing a NULL app_info
214#ifndef TEST_R5
215	BRoster roster;
216	// invalid team ID
217	CHK(roster.GetRunningAppInfo(-1, NULL) == B_BAD_VALUE);
218	// valid team ID
219	AppRunner runner(true);
220	CHK(runner.Run("AppRunTestApp1") == B_OK);
221	CHK(roster.GetRunningAppInfo(runner.Team(), NULL) == B_BAD_VALUE);
222	runner.WaitFor(true);
223#endif
224}
225
226/*
227	status_t GetRunningAppInfo(team_id team, app_info *info) const
228	@case 2			info is not NULL, but no app with the team ID is running
229	@results		Should return B_BAD_TEAM_ID.
230*/
231void GetAppInfoTester::GetRunningAppInfoTest2()
232{
233	BRoster roster;
234	// invalid team ID
235	app_info info;
236#ifdef TEST_R5
237	CHK(roster.GetRunningAppInfo(-1, &info) == B_ERROR);
238#else
239	CHK(roster.GetRunningAppInfo(-1, &info) == B_BAD_TEAM_ID);
240#endif
241	CHK(roster.GetRunningAppInfo(-2, &info) == B_BAD_TEAM_ID);
242	// originally valid team ID -- app terminates before call
243	AppRunner runner(true);
244	CHK(runner.Run("AppRunTestApp1") == B_OK);
245	team_id team = runner.Team();
246	runner.WaitFor(true);
247	CHK(roster.GetRunningAppInfo(team, &info) == B_BAD_TEAM_ID);
248}
249
250/*
251	status_t GetRunningAppInfo(team_id team, app_info *info) const
252	@case 3			info is not NULL, and an app with the team ID is running
253	@results		Should fill the app info and return B_OK.
254*/
255void GetAppInfoTester::GetRunningAppInfoTest3()
256{
257	const char *signature = "application/x-vnd.obos-app-run-testapp1";
258	uint32 flags = B_MULTIPLE_LAUNCH | B_ARGV_ONLY;
259	// run the app
260	AppRunner runner(true);
261	CHK(runner.Run("AppRunTestApp1") == B_OK);
262	// get and check the info
263	BRoster roster;
264	app_info info;
265	CHK(roster.GetRunningAppInfo(runner.Team(), &info) == B_OK);
266	CHK(check_app_info(info, runner, signature, flags));
267	// quit the app
268	runner.WaitFor(true);
269}
270
271
272Test* GetAppInfoTester::Suite()
273{
274	TestSuite* SuiteOfTests = new TestSuite;
275
276	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestA1);
277	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestA2);
278	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestA3);
279
280	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestB1);
281	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestB2);
282	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester, GetAppInfoTestB3);
283
284	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester,
285			  GetRunningAppInfoTest1);
286	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester,
287			  GetRunningAppInfoTest2);
288	ADD_TEST4(BRoster, SuiteOfTests, GetAppInfoTester,
289			  GetRunningAppInfoTest3);
290
291	return SuiteOfTests;
292}
293
294