PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/test/ext/test_code_run.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 271 lines | 225 code | 26 blank | 20 comment | 49 complexity | b299c2ef8cc67121891fdfdc07750fd9 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/test/ext/test_code_run.h"
  17. #include "hphp/compiler/parser/parser.h"
  18. #include "hphp/compiler/builtin_symbols.h"
  19. #include "hphp/compiler/code_generator.h"
  20. #include "hphp/compiler/analysis/analysis_result.h"
  21. #include "hphp/compiler/analysis/type.h"
  22. #include "hphp/util/process.h"
  23. #include "hphp/runtime/base/file-util.h"
  24. #include "hphp/compiler/option.h"
  25. #include "hphp/runtime/base/runtime-option.h"
  26. #include "hphp/runtime/ext/std/ext_std_file.h"
  27. #include <pcre.h>
  28. #include <folly/Conv.h>
  29. using std::istringstream;
  30. using std::ostringstream;
  31. ///////////////////////////////////////////////////////////////////////////////
  32. TestCodeRun::TestCodeRun() : m_perfMode(false), m_test(0) {
  33. Option::KeepStatementsWithNoEffect = false;
  34. Option::ParserThreadCount = 4;
  35. }
  36. bool TestCodeRun::preTest() {
  37. if (!CleanUp()) return false;
  38. return true;
  39. }
  40. bool TestCodeRun::postTest() {
  41. return true;
  42. }
  43. bool TestCodeRun::CleanUp() {
  44. string out, err;
  45. const char *argv[] = {"", nullptr};
  46. Process::Exec("runtime/tmp/cleanup.sh", argv, nullptr, out, &err);
  47. if (!err.empty()) {
  48. printf("Failed to clean up runtime/tmp: %s\n", err.c_str());
  49. return false;
  50. }
  51. return true;
  52. }
  53. static bool GenerateMainPHP(const std::string &fullPath,
  54. const char *file, int line,
  55. const char *input) {
  56. FileUtil::mkdir(fullPath.c_str());
  57. std::ofstream f(fullPath.c_str());
  58. if (!f) {
  59. printf("Unable to open %s for write. Run this test from hphp/.\n",
  60. fullPath.c_str());
  61. return false;
  62. }
  63. if (file && !strncmp(input, "<?php", 5)) {
  64. f << "<?php\n# " << file << ":" << line << "\n";
  65. f << (input + 5);
  66. } else {
  67. f << input;
  68. }
  69. f.close();
  70. return true;
  71. }
  72. static string escape(const std::string &s) {
  73. string ret;
  74. ret.reserve(s.size() + 20);
  75. for (unsigned int i = 0; i < s.length(); i++) {
  76. char ch = s[i];
  77. if (isprint(ch) || ch == '\n') {
  78. ret += ch;
  79. } else {
  80. char buf[10];
  81. snprintf(buf, sizeof(buf), "{\\x%02X}", (unsigned char)ch);
  82. ret += buf;
  83. }
  84. }
  85. return ret;
  86. }
  87. static bool verify_result(const char *input, const char *output, bool perfMode,
  88. const char *file = "", int line = 0,
  89. bool nowarnings = false,
  90. bool fileoutput = false,
  91. const char *subdir = "",
  92. bool fastMode = false) {
  93. // generate main.php
  94. string fullPath = "runtime/tmp";
  95. if (subdir && subdir[0]) fullPath = fullPath + "/" + subdir;
  96. fullPath += "/main.php";
  97. if (!GenerateMainPHP(fullPath, 0, 0, input)) return false;
  98. // get PHP's output if "output" is NULL
  99. string expected;
  100. if (output) {
  101. if (fileoutput) {
  102. String s = HHVM_FN(file_get_contents)(output);
  103. expected = string(s.data(), s.size());
  104. } else {
  105. expected = output;
  106. }
  107. } else {
  108. const char *argv1[] = {"", "-ddisplay_errors=stderr",
  109. "-dapc.enable_cli=1",
  110. fullPath.c_str(), nullptr};
  111. const char *argv2[] = {"", "-ddisplay_errors=On",
  112. "-dapc.enable_cli=1",
  113. fullPath.c_str(), nullptr};
  114. string err;
  115. Process::Exec(php_path, nowarnings ? argv2 : argv1, nullptr, expected, &err);
  116. if (!err.empty() && nowarnings) {
  117. printf("%s:%d\nParsing: [%s]\nFailed to run %s: %s\n",
  118. file, line, input, fullPath.c_str(), err.c_str());
  119. return false;
  120. }
  121. }
  122. // run and verify output
  123. {
  124. string actual, err;
  125. string dir = "runtime/tmp/";
  126. if (subdir) dir = dir + subdir + "/";
  127. string repoarg = "-vRepo.Central.Path=" + dir + "hhvm.hhbc";
  128. if (Option::EnableEval < Option::FullEval) {
  129. if (fastMode) {
  130. string path = dir + "libtest.so";
  131. const char *argv[] = {"", "--file=string", "--config=test/slow/config.hdf",
  132. repoarg.c_str(), path.c_str(), nullptr};
  133. Process::Exec("runtime/tmp/run.sh", argv, nullptr, actual, &err);
  134. } else {
  135. const char *argv[] = {"", "--file=string", "--config=test/slow/config.hdf",
  136. repoarg.c_str(), nullptr};
  137. string path = dir + "test";
  138. Process::Exec(path.c_str(), argv, nullptr, actual, &err);
  139. }
  140. } else {
  141. string filearg = "--file=" + dir + "main.php";
  142. string jitarg = string("-vEval.Jit=") +
  143. (RuntimeOption::EvalJit ? "true" : "false");
  144. const char *argv[] = {"", filearg.c_str(),
  145. "--config=test/slow/config.hdf",
  146. repoarg.c_str(),
  147. jitarg.c_str(),
  148. nullptr};
  149. Process::Exec(HHVM_PATH, argv, nullptr, actual, &err);
  150. }
  151. if (perfMode) {
  152. string sinput = input;
  153. const char *marker = "/* INPUT */";
  154. int pos1 = sinput.find(marker);
  155. int pos2 = sinput.find(marker, pos1+1);
  156. pos1 += strlen(marker);
  157. sinput = sinput.substr(pos1, pos2 - pos1);
  158. if (sinput.size() > 1000) sinput = "(long program)";
  159. // we have to adjust timing by removing loop cost, which is the 1st test
  160. static int adj1 = -1;
  161. static int adj2 = -1;
  162. int ms1 = atoi(expected.c_str());
  163. int ms2 = atoi(actual.c_str());
  164. if (adj1 == -1) adj1 = ms1;
  165. if (adj2 == -1) adj2 = ms2;
  166. int msAdj1 = ms1 - adj1;
  167. int msAdj2 = ms2 - adj2;
  168. double x = 0.0; // how many times faster
  169. double p = 0.0; // percentage
  170. if (msAdj2 != 0) {
  171. x = ((double)(int)(msAdj1 * 100 / msAdj2)) / 100;
  172. }
  173. if (msAdj1 != 0) {
  174. p = ((double)(int)(msAdj2 * 10000 / msAdj1)) / 100;
  175. }
  176. printf("----------------------------------------------------------\n"
  177. "%s\n\n"
  178. " PHP C++\n"
  179. "===========================================\n"
  180. " %6d ms %6d ms\n"
  181. " -%6d ms %6d ms\n"
  182. "===========================================\n"
  183. " %6d ms %6d ms = %2.4gx or %2.4g%%\n\n",
  184. sinput.c_str(), ms1, ms2, adj1, adj2, msAdj1, msAdj2, x, p);
  185. return true;
  186. }
  187. bool out_ok = actual == expected;
  188. if (!out_ok || (!nowarnings && !err.empty())) {
  189. if (out_ok &&
  190. err.find("symbol lookup error:") != string::npos &&
  191. err.find("undefined symbol: ") != string::npos) {
  192. printf("%s: Ignoring loader error: %s\n",
  193. fullPath.c_str(), err.c_str());
  194. } else {
  195. printf("======================================\n"
  196. "%s:\n"
  197. "======================================\n"
  198. "%s:%d\nParsing: [%s]\nBet %d:\n"
  199. "--------------------------------------\n"
  200. "%s"
  201. "--------------------------------------\n"
  202. "Got %d:\n"
  203. "--------------------------------------\n"
  204. "%s"
  205. "--------------------------------------\n"
  206. "Err: [%s]\n", fullPath.c_str(), file, line, input,
  207. (int)expected.length(), escape(expected).c_str(),
  208. (int)actual.length(), escape(actual).c_str(),
  209. err.c_str());
  210. return false;
  211. }
  212. }
  213. }
  214. return true;
  215. }
  216. bool TestCodeRun::RecordMulti(const char *input, const char *output,
  217. const char *file, int line, bool nowarnings,
  218. bool fileoutput) {
  219. string fullPath = "runtime/tmp/" + Test::s_suite + "/" + test_name + "/tcr-" +
  220. folly::to<string>(m_test++);
  221. if (!GenerateMainPHP(fullPath + "/main.php", file, line, input)) return false;
  222. if (nowarnings) {
  223. std::ofstream((fullPath + "/nowarnings").c_str());
  224. }
  225. if (output) {
  226. std::ofstream s((fullPath + "/test.result").c_str());
  227. if (fileoutput) {
  228. String expected = HHVM_FN(file_get_contents)(output);
  229. s << string(expected.data(), expected.size());
  230. } else {
  231. s << output;
  232. }
  233. }
  234. return true;
  235. }
  236. bool TestCodeRun::VerifyCodeRun(const char *input, const char *output,
  237. const char *file /* = "" */,
  238. int line /* = 0 */,
  239. bool nowarnings /* = false */,
  240. bool fileoutput /* = false */) {
  241. assert(input);
  242. if (!CleanUp()) return false;
  243. return verify_result(input, output, m_perfMode,
  244. file, line, nowarnings, fileoutput, "Test0", false);
  245. }