1#ifndef _beos_test_shell_h_
2#define _beos_test_shell_h_
3
4#include <LockerSyncObject.h>
5#include <cppunit/Exception.h>
6#include <cppunit/Test.h>
7#include <cppunit/TestListener.h>
8#include <cppunit/TestResult.h>
9#include <cppunit/TestResultCollector.h>
10#include <image.h>
11#include <TestSuite.h>
12#include <map>
13#include <set>
14#include <string>
15
16class BDirectory;
17class BLocker;
18class BPath;
19
20#ifndef NO_ELF_SYMBOL_PATCHING
21#include <tools/elfsymbolpatcher/ElfSymbolPatcher.h>
22#else
23class ElfSymbolPatchGroup;
24#endif
25
26// Defines SuiteFunction to be a pointer to a function that
27// takes no arguments and returns a pointer to a CppUnit::Test
28typedef CppUnit::Test* (*SuiteFunction)(void);
29
30// This is just absurd to have to type...
31typedef CppUnit::SynchronizedObject::SynchronizationObject SyncObject;
32
33/*!	\brief Executes a statement that is supposed to call debugger().
34	An exception is thrown if the debugger is not invoked by the
35	statement.
36*/
37#define CPPUNIT_ASSERT_DEBUGGER(statement)					\
38	BTestShell::GlobalShell()->ExpectDebuggerCall();		\
39	statement;												\
40	::CppUnit::Asserter::failIf(							\
41		!BTestShell::GlobalShell()->WasDebuggerCalled(),	\
42		(#statement),										\
43		CPPUNIT_SOURCELINE() );
44
45
46//! BeOS savvy command line interface for the CppUnit testing framework.
47/*! This class provides a fully functional command-line testing interface
48	built on top of the CppUnit testing library. You add named test suites
49	via AddSuite(), and then call Run(), which does all the dirty work. The
50	user can get a list of each test installed via AddSuite(), and optionally
51	can opt to run only a specified set of them.
52*/
53class CPPUNIT_API BTestShell {
54public:
55	BTestShell(const std::string &description = "", SyncObject *syncObject = 0);
56	virtual ~BTestShell();
57
58	// This function is used to add the tests for a given kit (as contained
59	// in a BTestSuite object) to the list of available tests. The shell assumes
60	// ownership of the BTestSuite object. Each test in the kit is added to
61	// the list of tests via a call to AddTest(string
62	status_t AddSuite(BTestSuite *kit);
63
64	// This function is used to add test suites to the list of available
65	// tests. The test pointer may not be NULL. The name given is the name that
66	// will be presented when the program is run with "--list" as an argument.
67	// Usually the given suite would be a test suite for an entire class, but
68	// that's not a requirement.
69	void AddTest(const std::string &name, CppUnit::Test* test);
70
71	// This function loads all the test addons it finds in the given
72	// directory, returning the number of tests actually loaded.
73	int32 LoadSuitesFrom(BDirectory *libDir);
74
75	// This is the function you call after you've added all your test
76	// suites with calls to AddSuite(). It runs the test, or displays
77	// help, or lists installed tests, or whatever, depending on the
78	// command-line arguments passed in.
79	int Run(int argc, char *argv[]);
80
81	// Verbosity Level enumeration and accessor function
82	enum VerbosityLevel { v0, v1, v2, v3, v4 };
83	VerbosityLevel Verbosity() const;
84
85	// Returns true if verbosity is high enough that individual tests are
86	// allowed to make noise.
87	bool BeVerbose() const { return Verbosity() >= v2; };
88
89	static bool GlobalBeVerbose() { return (fGlobalShell ? fGlobalShell->BeVerbose() : true); };
90
91	// Returns a pointer to a global BTestShell object. This function is
92	// something of a hack, used to give BTestCase and its subclasses
93	// access to verbosity information. Don't rely on it if you don't
94	// have to (and always make sure the pointer it returns isn't NULL
95	// before you try to use it :-).
96	static BTestShell* GlobalShell() { return fGlobalShell; };
97
98	// Sets the global BTestShell pointer. The BTestShell class does
99	// not assume ownership of the object.
100	static void SetGlobalShell(BTestShell *shell) { fGlobalShell = shell; };
101
102	const char* TestDir() const;
103	static const char* GlobalTestDir() { return (fGlobalShell ? fGlobalShell->TestDir() : NULL); };
104
105	void ExpectDebuggerCall();
106	bool WasDebuggerCalled();
107
108protected:
109	typedef std::map<std::string, CppUnit::Test*> TestMap;
110	typedef std::map<std::string, BTestSuite*> SuiteMap;
111
112	VerbosityLevel fVerbosityLevel;
113	std::set<std::string> fTestsToRun;
114	std::set<std::string> fSuitesToRun;
115	TestMap fTests;
116	SuiteMap fSuites;
117	std::set<std::string> fLibDirs;
118	CppUnit::TestResult fTestResults;
119	CppUnit::TestResultCollector fResultsCollector;
120	std::string fDescription;
121	static BTestShell* fGlobalShell;
122	static const char indent[];
123	bool fListTestsAndExit;
124	BPath *fTestDir;
125	int32 fTLSDebuggerCall;
126
127	BLocker *fPatchGroupLocker;
128	ElfSymbolPatchGroup *fPatchGroup;
129	void (*fOldDebuggerHook)(const char*);
130	image_id (*fOldLoadAddOnHook)(const char*);
131	status_t (*fOldUnloadAddOnHook)(image_id);
132
133	//! Prints a brief description of the program.
134	virtual void PrintDescription(int argc, char *argv[]);
135
136	//! Prints out command line argument instructions
137	void PrintHelp();
138
139	/*! \brief Prints out the list of valid command line arguments.
140		Called by PrintHelp().
141	*/
142	virtual void PrintValidArguments();
143
144	//! Prints out a list of all the currently available tests
145	void PrintInstalledTests();
146
147	/*! \brief Handles command line arguments; returns true if everything goes
148		okay, false if not (or if the program just needs to terminate without
149		running any tests). Modifies settings in "settings" as necessary.
150	*/
151	bool ProcessArguments(int argc, char *argv[]);
152
153	//! Processes a single argument, given by the \c arg parameter.
154	virtual bool ProcessArgument(std::string arg, int argc, char *argv[]);
155
156	//! Makes any necessary pre-test preparations
157	void InitOutput();
158
159	/*! \brief Prints out the test results in the proper format per
160		the specified verbosity level.
161	*/
162	void PrintResults();
163
164	/*! \brief Searches all the paths in \c fLibDirs, loading any dynamically
165		loadable suites it finds.
166	*/
167	virtual void LoadDynamicSuites();
168
169	//! Sets the current test directory.
170	void UpdateTestDir(char *argv[]);
171
172	void InstallPatches();
173	void UninstallPatches();
174
175private:
176	//! Prevents the use of the copy constructor.
177	BTestShell( const BTestShell &copy );
178
179	//! Prevents the use of the copy operator.
180	void operator =( const BTestShell &copy );
181
182	void _Debugger(const char* message);
183	image_id _LoadAddOn(const char* path);
184	status_t _UnloadAddOn(image_id image);
185
186	static void _DebuggerHook(const char* message);
187	static image_id _LoadAddOnHook(const char* path);
188	static status_t _UnloadAddOnHook(image_id image);
189};	// class BTestShell
190
191#endif // _beos_test_shell_h_
192