-
toole1 authored
git-svn-id: https://subversion.cs.illinois.edu/svn/cs225@3377 6fbd10e7-183d-0410-a318-cb416676e4f2
toole1 authoredgit-svn-id: https://subversion.cs.illinois.edu/svn/cs225@3377 6fbd10e7-183d-0410-a318-cb416676e4f2
proxy.h 6.57 KiB
// proxy.h
// NOTE: This is a generic file. Actual unit tests are located in
// unit_tests.cpp.
// By Jack Toole for CS 225 spring 2011
#ifndef MONAD_PROXY_H
#define MONAD_PROXY_H
#include <map>
#include <string>
#include <vector>
#include <iostream>
#include <utility>
#include "pipestream.h"
#include "monad_shared.h"
#define NO_MP_PART -1
#include "_mp_part_number.h"
#define MP_PART(x) (MP_PART_NUMBER == (x) || MP_PART_NUMBER == NO_MP_PART)
namespace proxy
{
using namespace monad_shared;
class RunTests;
typedef bool (*output_check)(const std::string &, const std::string &);
extern std::vector<unit_test> * global_tests;
typedef std::map<std::string, output_check, util::ci_less> output_check_map;
extern output_check_map * global_output_checks;
class add_unit_test
{
public:
add_unit_test(int8_t MPpart, const char * name, unit_test::function func,
int32_t points_in_part, int32_t points_in_total, long timeout,
bool is_valgrind);
private:
void lazy_init_global_tests();
void assertMPpart(int8_t MPpart, const char * name);
int32_t get_points(int32_t points_in_total, int32_t points_in_part);
};
class add_output_check
{
public:
add_output_check(const char * name, output_check func);
};
enum mode_t
{
SINGLE_TEST,
MP_PART_TESTS,
ALL_TESTS
};
struct RunTimeEnvironment
{
public:
const int itimer_number0;
const int itimer_number1;
const int timeout_signum0;
const int timeout_signum1;
const size_t max_output_length;
const char * single_test_passed_string;
std::vector<unit_test> * heap_tests;
output_check_map * output_checks;
int32_t cleanup_globals();
RunTimeEnvironment(std::vector<unit_test> *& init_tests,
output_check_map *& init_output_checks);
private:
RunTimeEnvironment(const RunTimeEnvironment & other);
RunTimeEnvironment & operator=(RunTimeEnvironment & other);
static int8_t singleton;
};
class RunTests
{
private:
RunTimeEnvironment & environment;
mode_t mode;
const char * test_arg;
int8_t mp_part;
public:
RunTests(int argc, char ** argv, RunTimeEnvironment & env);
int execute();
private:
void redirect_glibc_to_stderr();
void process_args(int argc, char ** argv);
protected:
int32_t execute_by_mode();
int32_t run_single_test(const char * testname);
int32_t run_single_test(unit_test & curr_test);
void handle_single_test_output(const std::string & output);
void output_single_test_passfail(const unit_test & curr_test);
int32_t run_all_tests();
int32_t get_sum_points();
int32_t get_max_testname_length();
int32_t get_max_points_length();
void output_detailed_info_if_any_failed(int32_t score);
void output_detailed_tests_info(int32_t score);
private:
RunTests(const RunTests & other);
RunTests & operator=(const RunTests & other);
};
class UnitTestContainer
{
private:
RunTimeEnvironment & environment;
unit_test & test;
public:
UnitTestContainer(unit_test & _test, RunTimeEnvironment & env);
bool execute(bool enable_valgrind_call);
private:
UnitTestContainer(const UnitTestContainer & other);
UnitTestContainer & operator=(const UnitTestContainer & other);
};
class test_execution
{
private:
util::pipestream fmsg_pipe; // For error messages
util::pipestream cout_pipe; // For stdout/stderr
util::pipestream nums_pipe; // for numbers: time, valgrind
unit_test & test;
RunTimeEnvironment & environment;
bool do_valgrind;
public:
test_execution(unit_test & _test, RunTimeEnvironment & env, bool enable_valgrind_call);
void parent();
void child();
void clean_exit(int8_t return_code);
void interrupted_exit(int signal_number);
void aborted_exit();
private:
void child_valgrind();
void child_test(util::pipestream & fmsg_pipe, util::pipestream & nums_pipe);
void valgrind_test_exit(int8_t return_code);
void test_exit(util::pipestream & fmsg_pipe, util::pipestream & nums_pipe);
void test_signaled(int signum);
void start_timeout();
long end_timeout();
private:
test_execution(const test_execution & other);
test_execution & operator=(const test_execution & other);
};
const char * get_valgrind_string(int32_t flags);
int32_t get_valgrind_flags(bool test_failed);
int32_t bitflags(unsigned long a, unsigned long b = 0, unsigned long c = 0,
unsigned long d = 0, unsigned long e = 0);
bool bitflag(int32_t flags, int32_t num);
} // namespace proxy
using std::cout;
using std::cerr;
using std::endl;
#define UNIT_TEST(MPpart,func,pointsInPart,pointsInTotal,timeout) \
proxy::unit_test::return_type \
func(proxy::unit_test & this_test); \
proxy::add_unit_test \
func##_adder(MPpart, #func, func, pointsInPart, \
pointsInTotal, timeout, false); \
proxy::unit_test::return_type \
func(proxy::unit_test & this_test)
#define VALGRIND_TEST(MPpart,func,pointsInPart,pointsInTotal,timeout) \
proxy::unit_test::return_type \
func(proxy::unit_test & this_test); \
proxy::add_unit_test \
func##_adder(MPpart, #func, func, pointsInPart, \
pointsInTotal, timeout, true); \
proxy::unit_test::return_type \
func(proxy::unit_test & this_test)
#define OUTPUT_CHECK(func) \
bool output_check_##func(const std::string & output, const std::string & expected); \
proxy::add_output_check \
output_check_##func##_adder(#func, output_check_##func); \
bool output_check_##func(const std::string & output, const std::string & expected)
#define STRINGIFY1(p) #p
#define STR(p) STRINGIFY1(p)
#define FAIL(error) return std::string(__FILE__ ":" STR(__LINE__) ": ") + (error)
#define PASS return monad_shared::unit_test::pass_string;
#define ASSERT(expr) if (!(expr)) \
FAIL("Assertion (" #expr ") failed")
#define ASSERT_OUTPUT(checkFunc, str) \
*this_test.checkstream << #checkFunc << str;
namespace proxy {
inline int32_t bitflags(unsigned long a, unsigned long b, unsigned long c,
unsigned long d, unsigned long e)
{
return ((int)(a != 0)) | (((int)(b != 0)) << 1) |
(((int)(c != 0)) << 2) | (((int)(d != 0)) << 3) |
(((int)(e != 0)) << 4) ;
}
inline bool bitflag(int32_t flags, int32_t num)
{
return (flags & (1 << num)) != 0;
}
}
#endif