8ea5b023a8
The slow tests were supposed to run without it, except when they explicitly requested it, but test/run always set it on the command line. This moves it into the default config.hdf, and removes a few cases where it was explicitly turned off in the slow tests.
272 linhas
9.3 KiB
C++
272 linhas
9.3 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 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. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/test/ext/test_code_run.h"
|
|
#include "hphp/compiler/parser/parser.h"
|
|
#include "hphp/compiler/builtin_symbols.h"
|
|
#include "hphp/compiler/code_generator.h"
|
|
#include "hphp/compiler/analysis/analysis_result.h"
|
|
#include "hphp/compiler/analysis/type.h"
|
|
#include "hphp/util/util.h"
|
|
#include "hphp/util/process.h"
|
|
#include "hphp/compiler/option.h"
|
|
#include "hphp/runtime/base/runtime_option.h"
|
|
#include <pcre.h>
|
|
#include "hphp/test/ext/test_mysql_info.h"
|
|
#include "hphp/runtime/ext/ext_file.h"
|
|
|
|
using std::istringstream;
|
|
using std::ostringstream;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
TestCodeRun::TestCodeRun() : m_perfMode(false), m_test(0) {
|
|
Option::KeepStatementsWithNoEffect = false;
|
|
Option::ParserThreadCount = 4;
|
|
}
|
|
|
|
bool TestCodeRun::preTest() {
|
|
if (!CleanUp()) return false;
|
|
return true;
|
|
}
|
|
|
|
bool TestCodeRun::postTest() {
|
|
return true;
|
|
}
|
|
|
|
bool TestCodeRun::CleanUp() {
|
|
string out, err;
|
|
const char *argv[] = {"", nullptr};
|
|
Process::Exec("runtime/tmp/cleanup.sh", argv, nullptr, out, &err);
|
|
if (!err.empty()) {
|
|
printf("Failed to clean up runtime/tmp: %s\n", err.c_str());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool GenerateMainPHP(const std::string &fullPath,
|
|
const char *file, int line,
|
|
const char *input) {
|
|
Util::mkdir(fullPath.c_str());
|
|
std::ofstream f(fullPath.c_str());
|
|
if (!f) {
|
|
printf("Unable to open %s for write. Run this test from hphp/.\n",
|
|
fullPath.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (file && !strncmp(input, "<?php", 5)) {
|
|
f << "<?php\n# " << file << ":" << line << "\n";
|
|
f << (input + 5);
|
|
} else {
|
|
f << input;
|
|
}
|
|
f.close();
|
|
return true;
|
|
}
|
|
|
|
static string escape(const std::string &s) {
|
|
string ret;
|
|
ret.reserve(s.size() + 20);
|
|
for (unsigned int i = 0; i < s.length(); i++) {
|
|
char ch = s[i];
|
|
if (isprint(ch) || ch == '\n') {
|
|
ret += ch;
|
|
} else {
|
|
char buf[10];
|
|
snprintf(buf, sizeof(buf), "{\\x%02X}", (unsigned char)ch);
|
|
ret += buf;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static bool verify_result(const char *input, const char *output, bool perfMode,
|
|
const char *file = "", int line = 0,
|
|
bool nowarnings = false,
|
|
bool fileoutput = false,
|
|
const char *subdir = "",
|
|
bool fastMode = false) {
|
|
// generate main.php
|
|
string fullPath = "runtime/tmp";
|
|
if (subdir && subdir[0]) fullPath = fullPath + "/" + subdir;
|
|
fullPath += "/main.php";
|
|
if (!GenerateMainPHP(fullPath, 0, 0, input)) return false;
|
|
|
|
// get PHP's output if "output" is NULL
|
|
string expected;
|
|
if (output) {
|
|
if (fileoutput) {
|
|
String s = f_file_get_contents(output);
|
|
expected = string(s.data(), s.size());
|
|
} else {
|
|
expected = output;
|
|
}
|
|
} else {
|
|
const char *argv1[] = {"", "-ddisplay_errors=stderr",
|
|
"-dapc.enable_cli=1",
|
|
fullPath.c_str(), nullptr};
|
|
const char *argv2[] = {"", "-ddisplay_errors=On",
|
|
"-dapc.enable_cli=1",
|
|
fullPath.c_str(), nullptr};
|
|
string err;
|
|
Process::Exec(php_path, nowarnings ? argv2 : argv1, nullptr, expected, &err);
|
|
if (!err.empty() && nowarnings) {
|
|
printf("%s:%d\nParsing: [%s]\nFailed to run %s: %s\n",
|
|
file, line, input, fullPath.c_str(), err.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// run and verify output
|
|
{
|
|
string actual, err;
|
|
string dir = "runtime/tmp/";
|
|
if (subdir) dir = dir + subdir + "/";
|
|
string repoarg = "-vRepo.Central.Path=" + dir + "hhvm.hhbc";
|
|
|
|
if (Option::EnableEval < Option::FullEval) {
|
|
if (fastMode) {
|
|
string path = dir + "libtest.so";
|
|
const char *argv[] = {"", "--file=string", "--config=test/slow/config.hdf",
|
|
repoarg.c_str(), path.c_str(), nullptr};
|
|
Process::Exec("runtime/tmp/run.sh", argv, nullptr, actual, &err);
|
|
} else {
|
|
const char *argv[] = {"", "--file=string", "--config=test/slow/config.hdf",
|
|
repoarg.c_str(), nullptr};
|
|
string path = dir + "test";
|
|
Process::Exec(path.c_str(), argv, nullptr, actual, &err);
|
|
}
|
|
} else {
|
|
string filearg = "--file=" + dir + "main.php";
|
|
|
|
string jitarg = string("-vEval.Jit=") +
|
|
(RuntimeOption::EvalJit ? "true" : "false");
|
|
const char *argv[] = {"", filearg.c_str(),
|
|
"--config=test/slow/config.hdf",
|
|
repoarg.c_str(),
|
|
jitarg.c_str(),
|
|
nullptr};
|
|
Process::Exec(HHVM_PATH, argv, nullptr, actual, &err);
|
|
}
|
|
|
|
if (perfMode) {
|
|
string sinput = input;
|
|
const char *marker = "/* INPUT */";
|
|
int pos1 = sinput.find(marker);
|
|
int pos2 = sinput.find(marker, pos1+1);
|
|
pos1 += strlen(marker);
|
|
sinput = sinput.substr(pos1, pos2 - pos1);
|
|
if (sinput.size() > 1000) sinput = "(long program)";
|
|
|
|
// we have to adjust timing by removing loop cost, which is the 1st test
|
|
static int adj1 = -1;
|
|
static int adj2 = -1;
|
|
int ms1 = atoi(expected.c_str());
|
|
int ms2 = atoi(actual.c_str());
|
|
if (adj1 == -1) adj1 = ms1;
|
|
if (adj2 == -1) adj2 = ms2;
|
|
int msAdj1 = ms1 - adj1;
|
|
int msAdj2 = ms2 - adj2;
|
|
double x = 0.0; // how many times faster
|
|
double p = 0.0; // percentage
|
|
if (msAdj2 != 0) {
|
|
x = ((double)(int)(msAdj1 * 100 / msAdj2)) / 100;
|
|
}
|
|
if (msAdj1 != 0) {
|
|
p = ((double)(int)(msAdj2 * 10000 / msAdj1)) / 100;
|
|
}
|
|
|
|
printf("----------------------------------------------------------\n"
|
|
"%s\n\n"
|
|
" PHP C++\n"
|
|
"===========================================\n"
|
|
" %6d ms %6d ms\n"
|
|
" -%6d ms %6d ms\n"
|
|
"===========================================\n"
|
|
" %6d ms %6d ms = %2.4gx or %2.4g%%\n\n",
|
|
sinput.c_str(), ms1, ms2, adj1, adj2, msAdj1, msAdj2, x, p);
|
|
return true;
|
|
}
|
|
|
|
bool out_ok = actual == expected;
|
|
if (!out_ok || (!nowarnings && !err.empty())) {
|
|
if (out_ok &&
|
|
err.find("symbol lookup error:") != string::npos &&
|
|
err.find("undefined symbol: ") != string::npos) {
|
|
printf("%s: Ignoring loader error: %s\n",
|
|
fullPath.c_str(), err.c_str());
|
|
} else {
|
|
printf("======================================\n"
|
|
"%s:\n"
|
|
"======================================\n"
|
|
"%s:%d\nParsing: [%s]\nBet %d:\n"
|
|
"--------------------------------------\n"
|
|
"%s"
|
|
"--------------------------------------\n"
|
|
"Got %d:\n"
|
|
"--------------------------------------\n"
|
|
"%s"
|
|
"--------------------------------------\n"
|
|
"Err: [%s]\n", fullPath.c_str(), file, line, input,
|
|
(int)expected.length(), escape(expected).c_str(),
|
|
(int)actual.length(), escape(actual).c_str(),
|
|
err.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestCodeRun::RecordMulti(const char *input, const char *output,
|
|
const char *file, int line, bool nowarnings,
|
|
bool fileoutput) {
|
|
string fullPath = "runtime/tmp/" + Test::s_suite + "/" + test_name + "/tcr-" +
|
|
boost::lexical_cast<string>(m_test++);
|
|
|
|
if (!GenerateMainPHP(fullPath + "/main.php", file, line, input)) return false;
|
|
if (nowarnings) {
|
|
std::ofstream((fullPath + "/nowarnings").c_str());
|
|
}
|
|
|
|
if (output) {
|
|
std::ofstream s((fullPath + "/test.result").c_str());
|
|
if (fileoutput) {
|
|
String expected = f_file_get_contents(output);
|
|
s << string(expected.data(), expected.size());
|
|
} else {
|
|
s << output;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestCodeRun::VerifyCodeRun(const char *input, const char *output,
|
|
const char *file /* = "" */,
|
|
int line /* = 0 */,
|
|
bool nowarnings /* = false */,
|
|
bool fileoutput /* = false */) {
|
|
assert(input);
|
|
if (!CleanUp()) return false;
|
|
|
|
return verify_result(input, output, m_perfMode,
|
|
file, line, nowarnings, fileoutput, "Test0", false);
|
|
}
|