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