1//------------------------------------------------------------------------------
2//	InstantiateObjectTester.cpp
3//
4/**
5	Testing of instantiate_object(BMessage* archive, image_id* id)
6	@note	No cases are currently defined for NULL 'id' parameter, since NULL
7			is a valid value for it.  Perhaps there should be to ensure that the
8			instantiate_object is, in fact, dealing with that case correctly.
9			There are also no tests against instantiate_object(BMessage*) as it
10			simply calls instantiate_object(BMessage*, image_id*) with NULL for
11			the image_id parameter.
12 */
13//------------------------------------------------------------------------------
14
15#include "InstantiateObjectTester.h"
16
17// Standard Includes -----------------------------------------------------------
18#include <errno.h>
19#include <stdexcept>
20#include <iostream>
21
22// System Includes -------------------------------------------------------------
23#include <Roster.h>
24#include <Entry.h>
25#include <Path.h>
26
27// Project Includes ------------------------------------------------------------
28#include <cppunit/Exception.h>
29#include <TestShell.h>
30
31// Local Includes --------------------------------------------------------------
32#include "remoteobjectdef/RemoteTestObject.h"
33#include "LocalTestObject.h"
34
35using namespace std;
36
37// Local Defines ---------------------------------------------------------------
38#define FORMAT_AND_THROW(MSG, ERR)	\
39	FormatAndThrow(__LINE__, __FILE__, MSG, ERR)
40
41// Globals ---------------------------------------------------------------------
42const char* gInvalidClassName	= "TInvalidClassName";
43const char* gInvalidSig			= "application/x-vnd.InvalidSignature";
44const char* gLocalClassName		= "TIOTest";
45const char* gLocalSig			= "application/x-vnd.LocalSignature";
46const char* gRemoteClassName	= "TRemoteTestObject";
47const char* gRemoteSig			= "application/x-vnd.RemoteObjectDef";
48const char* gValidSig			= gRemoteSig;
49#if !TEST_R5
50const char* gRemoteLib			= "/lib/libsupporttest_RemoteTestObject.so";
51#else
52const char* gRemoteLib			= "/lib/libsupporttest_RemoteTestObject_r5.so";
53#endif
54
55void FormatAndThrow(int line, const char* file, const char* msg, int err);
56
57//------------------------------------------------------------------------------
58TInstantiateObjectTester::TInstantiateObjectTester(string name)
59	:	BTestCase(name), fAddonId(B_ERROR)
60{
61	;
62}
63//------------------------------------------------------------------------------
64/**
65	instantiate_object(BMessage* archive, image_id* id)
66	@case			Invalid archive
67	@param archive	NULL
68	@param id		Valid image_id pointer
69	@results		Returns NULL.
70					*id is set to B_BAD_VALUE.
71					errno is set to B_BAD_VALUE.
72 */
73void TInstantiateObjectTester::Case1()
74{
75	errno = B_OK;
76	image_id id = B_OK;
77	TIOTest* Test = (TIOTest*)instantiate_object(NULL, &id);
78	CPPUNIT_ASSERT(Test == NULL);
79	CPPUNIT_ASSERT(id == B_BAD_VALUE);
80	CPPUNIT_ASSERT(errno == B_BAD_VALUE);
81}
82//------------------------------------------------------------------------------
83/**
84	instantiate_object(BMessage* archive, image_id* id)
85	@case			No class name
86	@param archive	Valid BMessage pointer without string field "class"
87	@param id		Valid image_id pointer
88	@results		Returns NULL.
89					*id is set to B_BAD_VALUE.
90					errno is set to B_OK.
91 */
92void TInstantiateObjectTester::Case2()
93{
94	errno = B_OK;
95	BMessage Archive;
96	image_id id = B_OK;
97	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
98	CPPUNIT_ASSERT(Test == NULL);
99	CPPUNIT_ASSERT(id == B_BAD_VALUE);
100	CPPUNIT_ASSERT(errno == B_OK);
101}
102//------------------------------------------------------------------------------
103
104//------------------------------------------------------------------------------
105//	Invalid class name tests
106//------------------------------------------------------------------------------
107/**
108	instantiate_object(BMessage* archive, image_id* id)
109	@case			Invalid class name
110	@param archive	Valid BMessage pointer, with string field labeled "class"
111					containing an invalid class name
112	@param id		Valid image_id pointer
113	@results		Returns NULL.
114					*id is set to B_BAD_VALUE.
115					errno is set to B_BAD_VALUE.
116 */
117void TInstantiateObjectTester::Case3()
118{
119	errno = B_OK;
120	BMessage Archive;
121	Archive.AddString("class", gInvalidClassName);
122	image_id id = B_OK;
123	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
124	CPPUNIT_ASSERT(Test == NULL);
125	CPPUNIT_ASSERT(id == B_BAD_VALUE);
126	CPPUNIT_ASSERT(errno == B_BAD_VALUE);
127}
128//------------------------------------------------------------------------------
129/**
130	instantiate_object(BMessage* archive, image_id* id)
131	@case			Invalid class name and signature
132	@param archive	Valid BMessage pointer, with string fields labeled "class"
133					and "add_on", containing invalid class name and signature,
134					respectively
135	@param id		Valid image_id pointer
136	@results		Returns NULL.
137					*id is set to B_BAD_VALUE.
138					errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND.
139 */
140void TInstantiateObjectTester::Case4()
141{
142	errno = B_OK;
143	BMessage Archive;
144	Archive.AddString("class", gInvalidClassName);
145	Archive.AddString("add_on", gInvalidSig);
146	image_id id = B_OK;
147	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
148	CPPUNIT_ASSERT(Test == NULL);
149	CPPUNIT_ASSERT(id == B_BAD_VALUE);
150	CPPUNIT_ASSERT(errno == B_LAUNCH_FAILED_APP_NOT_FOUND);
151}
152//------------------------------------------------------------------------------
153/**
154	instantiate_object(BMessage* archive, image_id* id)
155	@case			Invalid class name, valid signature
156	@param archive	Valid BMessage pointer with string fields labeled "class"
157					and "add_on", containing invalid class name and valid
158					signature, respectively
159	@param id		Valid image_id pointer
160	@requires		RemoteObjectDef add-on must be built and accessible
161	@results		Returns NULL.
162					*id is > 0 (add-on was loaded)
163					errno is set to B_BAD_VALUE.
164 */
165void TInstantiateObjectTester::Case5()
166{
167	errno = B_OK;
168	BMessage Archive;
169	Archive.AddString("class", gInvalidClassName);
170	Archive.AddString("add_on", gValidSig);
171	image_id id = B_OK;
172	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
173	CPPUNIT_ASSERT(Test == NULL);
174	// The system implementation returns the image_id of the last addon searched
175	// Implies the addon is not unloaded.  How to verify this behaviour?  Should
176	// the addon be unloaded if it doesn't contain our function?  Addons do,
177	// after all, eat into our allowable memory.
178
179	// Verified that addon is *not* unloaded in the Be implementation.  If Case8
180	// runs after this case without explicitely unloaded the addon here, it
181	// fails because it depends on the addon image not being available within
182	// the team.
183	CPPUNIT_ASSERT(id > 0);
184	unload_add_on(id);
185	CPPUNIT_ASSERT(errno == B_BAD_VALUE);
186}
187//------------------------------------------------------------------------------
188
189
190//------------------------------------------------------------------------------
191//	Valid class name tests
192//------------------------------------------------------------------------------
193/**
194	instantiate_object(BMessage* archive, image_id* id)
195	@case			Valid archive of class defined in local image
196	@param archive	Valid BMessage pointer with string field "class" containing
197					name of locally defined class which can be instantiated via
198					archiving mechanism
199	@param id		Valid image_id pointer
200	@requires		locally defined class which can be instantiated via
201					archiving mechanism
202	@results		Returns valid TIOTest instance.
203					*id is set to B_BAD_VALUE (no image was loaded).
204					errno is set to B_OK.
205 */
206//	No sig
207//		Local app -- local class
208void TInstantiateObjectTester::Case6()
209{
210	errno = B_OK;
211	BMessage Archive;
212	Archive.AddString("class", gLocalClassName);
213	image_id id = B_OK;
214	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
215	CPPUNIT_ASSERT(Test != NULL);
216	CPPUNIT_ASSERT(id == B_BAD_VALUE);
217	CPPUNIT_ASSERT(errno == B_OK);
218}
219//------------------------------------------------------------------------------
220/**
221	instantiate_object(BMessage* archive, image_id* id)
222	@case			Valid archive of class defined in add-on explicitely loaded
223					by this team
224	@param archive	Valid BMessage pointer with string field "class" containing
225					name of remotely defined class which can be instantiated via
226					archiving mechanism
227	@param id		Valid image_id pointer
228	@requires		RemoteObjectDef add-on must be built and accessible
229	@results		Returns valid TRemoteTestObject instance.
230					*id is set to B_BAD_VALUE (no image was loaded).
231					errno is set to B_OK.
232 */
233void TInstantiateObjectTester::Case7()
234{
235	errno = B_OK;
236	LoadAddon();
237
238	BMessage Archive;
239	Archive.AddString("class", gRemoteClassName);
240	image_id id = B_OK;
241	TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive,
242																	 &id);
243	CPPUNIT_ASSERT(Test != NULL);
244	CPPUNIT_ASSERT(id == B_BAD_VALUE);
245	CPPUNIT_ASSERT(errno == B_OK);
246
247	UnloadAddon();
248}
249//------------------------------------------------------------------------------
250/**
251	instantiate_object(BMessage* archive, image_id* id)
252	@case			Valid archive of remotely-defined class, without required
253					signature of the defining add-on
254	@param archive	Valid BMessage pointer with string field "class" containing
255					name of remotely-defined class; no "add-on" field
256	@param id		Valid image_id pointer
257	@results		Returns NULL.
258					*id is set to B_BAD_VALUE (no image loaded).
259					errno is set to B_BAD_VALUE.
260 */
261void TInstantiateObjectTester::Case8()
262{debugger(__PRETTY_FUNCTION__);
263	errno = B_OK;
264	BMessage Archive;
265	CPPUNIT_ASSERT(Archive.AddString("class", gRemoteClassName) == B_OK);
266	image_id id = B_OK;
267	TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive,
268																	 &id);
269	CPPUNIT_ASSERT(Test == NULL);
270	CPPUNIT_ASSERT(id == B_BAD_VALUE);
271	CPPUNIT_ASSERT(errno == B_BAD_VALUE);
272}
273//------------------------------------------------------------------------------
274/**
275	instantiate_object(BMessage* archive, image_id* id)
276	@case			Valid archive naming locally defined class with invalid
277					signature
278	@param archive	Valid BMessage pointer with string field "class" containing
279					name of locally defined class and string field "add_on"
280					containing invalid signature
281	@param id		Valid image_id pointer
282	@results		Returns NULL.
283					*id is set to B_BAD_VALUE (no image loaded).
284					errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND.
285 */
286void TInstantiateObjectTester::Case9()
287{
288	errno = B_OK;
289	BMessage Archive;
290	CPPUNIT_ASSERT(Archive.AddString("class", gLocalClassName) == B_OK);
291	CPPUNIT_ASSERT(Archive.AddString("add_on", gInvalidSig) == B_OK);
292	image_id id = B_OK;
293	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
294	CPPUNIT_ASSERT(Test == NULL);
295	CPPUNIT_ASSERT(id == B_BAD_VALUE);
296	CPPUNIT_ASSERT(errno == B_LAUNCH_FAILED_APP_NOT_FOUND);
297}
298//------------------------------------------------------------------------------
299/**
300	instantiate_object(BMessage* archive, image_id* id)
301	@case			Valid archive of class defined in add-on explicitely loaded
302					by this team, but with an invalid signature
303	@param archive	Valid BMessage pointer with string field "class" containing
304					name of remotely-defined class and string field "add_on"
305					containing invalid signature
306	@param id		Valid image_id pointer
307	@requires		RemoteObjectDef add-on must be built and accessible
308	@results		Returns NULL.
309					*id is set to B_BAD_VALUE (no image loaded).
310					errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND.
311 */
312void TInstantiateObjectTester::Case10()
313{
314	errno = B_OK;
315	LoadAddon();
316
317	BMessage Archive;
318	Archive.AddString("class", gRemoteClassName);
319	Archive.AddString("add_on", gInvalidSig);
320	image_id id = B_OK;
321	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
322	CPPUNIT_ASSERT(Test == NULL);
323	CPPUNIT_ASSERT(id == B_BAD_VALUE);
324	CPPUNIT_ASSERT(errno == B_LAUNCH_FAILED_APP_NOT_FOUND);
325
326	UnloadAddon();
327}
328//------------------------------------------------------------------------------
329/**
330	instantiate_object(BMessage* archive, image_id* id)
331	@case			Valid archive of remotely-defined class, with invalid
332					signature
333	@param archive	Valid BMessage pointer with string field "class" containing
334					name of remotely-defined class and string field add-on
335					containing invalid signature
336	@param id		Valid image_id pointer
337	@results		Returns NULL.
338					*id is set to B_BAD_VALUE.
339					errno is set to B_LAUNCH_FAILED_APP_NOT_FOUND
340 */
341void TInstantiateObjectTester::Case11()
342{
343	errno = B_OK;
344	BMessage Archive;
345	Archive.AddString("class", gRemoteClassName);
346	Archive.AddString("add_on", gInvalidSig);
347	image_id id = B_OK;
348	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
349	CPPUNIT_ASSERT(Test == NULL);
350	CPPUNIT_ASSERT(id == B_BAD_VALUE);
351	CPPUNIT_ASSERT(errno == B_LAUNCH_FAILED_APP_NOT_FOUND);
352}
353//------------------------------------------------------------------------------
354/**
355	instantiate_object(BMessage* archive, image_id* id)
356	@case			Valid archive of locally-defined class with correct
357					signature
358	@param archive	Valid BMessage pointer with string field "class" containing
359					name of locally-defined class and string field "add_on"
360					containing signature of current team
361	@param id		Valid image_id pointer
362	@requires		locally defined class which can be instantiated via
363					archiving mechanism
364	@results		Returns valid TIOTest instance.
365					*id is set to B_BAD_VALUE (no image loaded).
366					errno is set to B_OK.
367	@note			This test is not currently used; GetLocalSignature() doesn't
368					seem to work without a BApplication instance constructed.
369					See GetLocalSignature() for more info.
370 */
371void TInstantiateObjectTester::Case12()
372{
373	errno = B_OK;
374	BMessage Archive;
375	Archive.AddString("class", gLocalClassName);
376	Archive.AddString("add_on", GetLocalSignature().c_str());
377	image_id id = B_OK;
378	TIOTest* Test = (TIOTest*)instantiate_object(&Archive, &id);
379	CPPUNIT_ASSERT(Test != NULL);
380	CPPUNIT_ASSERT(id == B_BAD_VALUE);
381	CPPUNIT_ASSERT(errno == B_OK);
382}
383//------------------------------------------------------------------------------
384/**
385	instantiate_object(BMessage* archive, image_id* id)
386	@case			Valid archive of class defined in add-on explicitely loaded
387					by this team with signature of add-on
388	@param archive	Valid BMessage pointer with string field "class" containing
389					name of remotely-defined class and string field "add_on"
390					containing signature of loaded add-on
391	@param id		Valid image_id pointer
392	@requires		RemoteObjectDef add-on must be built and accessible
393	@results		Returns valid instance of TRemoteTestObject.
394					*id is set to B_BAD_VALUE (image load not necessary).
395					errno is set to B_OK.
396 */
397void TInstantiateObjectTester::Case13()
398{
399	errno = B_OK;
400	LoadAddon();
401
402	BMessage Archive;
403	Archive.AddString("class", gRemoteClassName);
404	Archive.AddString("add_on", gRemoteSig);
405	image_id id = B_OK;
406	TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, &id);
407	CPPUNIT_ASSERT(Test != NULL);
408	CPPUNIT_ASSERT(id == B_BAD_VALUE);
409	CPPUNIT_ASSERT(errno == B_OK);
410
411	UnloadAddon();
412}
413//------------------------------------------------------------------------------
414/**
415	instantiate_object(BMessage* archive, image_id* id)
416	@case			Valid archive of remotely-defined class with correct
417					signature
418	@param archive	Valid BMessage pointer with string field "class" containing
419					name of remotely-defined class and string field "add_on"
420					containing signature of defining add-on
421	@param id		Valid image_id pointer
422	@requires		RemoteObjectDef must be built and accessible
423	@results		Returns valid instance of TRemoteTestObject.
424					*id > 0 (image was loaded).
425					errno is set to B_OK.
426 */
427void TInstantiateObjectTester::Case14()
428{
429	errno = B_OK;
430	BMessage Archive;
431	Archive.AddString("class", gRemoteClassName);
432	Archive.AddString("add_on", gRemoteSig);
433	image_id id = B_OK;
434	TRemoteTestObject* Test = (TRemoteTestObject*)instantiate_object(&Archive, &id);
435	CPPUNIT_ASSERT(Test != NULL);
436	CPPUNIT_ASSERT(id > 0);
437	unload_add_on(id);
438	CPPUNIT_ASSERT(errno == B_OK);
439}
440//------------------------------------------------------------------------------
441CppUnit::Test* TInstantiateObjectTester::Suite()
442{
443	CppUnit::TestSuite* SuiteOfTests = new CppUnit::TestSuite;
444
445//	SuiteOfTests->addTest(
446//		new CppUnit::TestCaller<TInstantiateObjectTester>("BArchivable::instantiate_object() Test",
447//			&TInstantiateObjectTester::RunTests));
448
449	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case1);
450	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case2);
451	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case3);
452	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case4);
453	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case5);
454	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case6);
455	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case8);
456	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case7);
457	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case9);
458	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case10);
459	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case11);
460//	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case12);
461	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case13);
462	ADD_TEST(SuiteOfTests, TInstantiateObjectTester, Case14);
463
464	return SuiteOfTests;
465}
466//------------------------------------------------------------------------------
467void TInstantiateObjectTester::LoadAddon()
468{
469	if (fAddonId > 0)
470		return;
471
472	// We're not testing the roster, so I'm going to just
473	// find the add-on manually.
474	std::string libPath = std::string(BTestShell::GlobalTestDir()) + gRemoteLib;
475	cout << "dir == '" << libPath << "'" << endl;
476	fAddonId = load_add_on(libPath.c_str());
477
478	RES(fAddonId);
479	if (fAddonId <= 0)
480	{
481		FORMAT_AND_THROW(" failed to load addon: ", fAddonId);
482	}
483}
484//------------------------------------------------------------------------------
485void TInstantiateObjectTester::UnloadAddon()
486{
487	if (fAddonId > 0)
488	{
489		status_t err = unload_add_on(fAddonId);
490		fAddonId = B_ERROR;
491		if (err)
492		{
493			FORMAT_AND_THROW(" failed to unload addon: ", err);
494		}
495	}
496}
497//------------------------------------------------------------------------------
498std::string TInstantiateObjectTester::GetLocalSignature()
499{
500	BRoster Roster;
501	app_info ai;
502	team_id team;
503
504	// Get the team_id of this app
505	thread_id tid = find_thread(NULL);
506	thread_info ti;
507	status_t err = get_thread_info(tid, &ti);
508	if (err)
509	{
510		FORMAT_AND_THROW(" failed to get thread_info: ", err);
511	}
512
513	// Get the app_info via the team_id
514	team = ti.team;
515	team_info info;
516	err = get_team_info(team, &info);
517	if (err)
518	{
519		FORMAT_AND_THROW(" failed to get team_info: ", err);
520	}
521
522	team = info.team;
523
524	// It seems that this call to GetRunningAppInfo() is not working because we
525	// don't have an instance of BApplication somewhere -- the roster, therefore,
526	// doesn't know about us.
527	err = Roster.GetRunningAppInfo(team, &ai);
528	if (err)
529	{
530		FORMAT_AND_THROW(" failed to get app_info: ", err);
531	}
532
533	// Return the signature from the app_info
534	return ai.signature;
535}
536//------------------------------------------------------------------------------
537
538//------------------------------------------------------------------------------
539void FormatAndThrow(int line, const char *file, const char *msg, int err)
540{
541	std::string s("line: ");
542	s += IntToStr(line);
543	s += " ";
544	s += file;
545	s += msg;
546	s += strerror(err);
547	s += "(";
548	s += IntToStr(err);
549	s += ")";
550	CppUnit::Exception re(s.c_str());
551	throw re;
552}
553//------------------------------------------------------------------------------
554
555void
556TInstantiateObjectTester::RunTests() {
557	NextSubTest();
558	Case1();
559	NextSubTest();
560	Case2();
561	NextSubTest();
562	Case3();
563	NextSubTest();
564	Case4();
565	NextSubTest();
566	Case5();
567	NextSubTest();
568	Case6();
569	NextSubTest();
570	Case7();
571	NextSubTest();
572	Case8();
573	NextSubTest();
574	Case9();
575	NextSubTest();
576	Case10();
577	NextSubTest();
578	Case11();
579	NextSubTest();
580	Case12();
581	NextSubTest();
582	Case13();
583	NextSubTest();
584	Case14();
585}
586
587/*
588 * $Log $
589 *
590 * $Id  $
591 *
592 */
593
594
595