Arquivos
hhvm/hphp/test/test_base.h
T
bsimmers 991ca4e231 Add a top-level catch to RUN_TEST
A test was hanging on to the result of
std::string::c_str() past the lifetime of the string and then throwing
an uncaught exception.
This diff adds a top-level catch block to RUN_TEST to prevent things like
this from killing the test binary in the future.
2013-03-05 21:17:39 -08:00

140 linhas
5.0 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef __TEST_BASE_H__
#define __TEST_BASE_H__
#include <string>
#include <assert.h>
#include <compiler/hphp.h>
#include <runtime/base/types.h>
#include <test/test.h>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
class TestBase {
public:
TestBase();
virtual ~TestBase() {}
virtual bool preTest() { return true; }
virtual bool RunTests(const std::string &which) = 0;
virtual bool postTest() { return true; }
int fail_count;
int skip_count;
int pass_count;
std::string error_messages;
std::string test_name;
protected:
bool Count(bool result);
bool CountSkip();
bool VerifySame(const char *exp1, const char *exp2,
CVarRef v1, CVarRef v2);
bool VerifyClose(const char *exp1, const char *exp2,
double v1, double v2);
bool array_value_exists(CVarRef var, CVarRef value);
static char error_buffer[];
template<class T>
bool runTestImpl(T test, const std::string& which, const std::string& name) {
bool ret = true;
auto pass = [&] { printf("%s passed\n", name.c_str()); };
auto fail = [&] { printf("%s failed\n", name.c_str()); ret = false; };
if (which.empty() || which == name) {
SCOPE_EXIT { fflush(nullptr); };
test_name = name;
try {
if (preTest() && test() && postTest()) {
if (!Test::s_quiet) {
pass();
}
} else {
fail();
}
} catch (const std::exception& e) {
fprintf(stderr, "%s threw %s: '%s'\n",
name.c_str(), typeid(e).name(), e.what());
fail();
} catch (...) {
fprintf(stderr, "%s threw unknown object\n", name.c_str());
fail();
}
}
return ret;
}
};
template <bool value>
class WithOption {
public:
WithOption(bool &option) :
m_option(&option), m_save(option) {
option = value;
}
~WithOption() { *m_option = m_save; }
private:
bool *m_option;
const bool m_save;
};
typedef WithOption<true> WithOpt;
typedef WithOption<false> WithNoOpt;
///////////////////////////////////////////////////////////////////////////////
// macros
#define RUN_TEST(test) do { \
if (!runTestImpl([=] { return test(); }, which, #test)) ret = false; \
} while(false)
#define LOG_TEST_ERROR(...) \
sprintf(TestBase::error_buffer, __VA_ARGS__); \
printf("%s\n", TestBase::error_buffer); \
error_messages += "\n\n"; \
error_messages += TestBase::error_buffer; \
#define SKIP(reason) \
LOG_TEST_ERROR("%s skipped [%s]", __FUNCTION__, #reason); \
return CountSkip(); \
#define VERIFY(exp) \
if (!(exp)) { \
LOG_TEST_ERROR("%s:%d: [%s] is false", __FILE__, __LINE__, #exp); \
return Count(false); \
} \
#define VS(e1, e2) \
if (!VerifySame(#e1, #e2, e1, e2)) { \
LOG_TEST_ERROR("%s:%d: VerifySame failed.", __FILE__, __LINE__); \
return Count(false); \
} \
#define VC(e1, e2) \
if (!VerifyClose(#e1, #e2, e1, e2)) { \
LOG_TEST_ERROR("%s:%d: VerifyClose failed.", __FILE__, __LINE__); \
return Count(false); \
} \
///////////////////////////////////////////////////////////////////////////////
#endif // __TEST_BASE_H__