test262-harness.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * Runs one test file from the ES5 test suite test-262
  3. * Usage: mujs <this-file> [-s ] [-f] [-l file1.js -l ...] suit-root test-file
  4. * -s: print test source on failure
  5. * -f: print full paths/stacktraces if possible
  6. * -l: load a js file after the harness and before the test (to override things)
  7. *
  8. * If there are errors, print them and exits with code 1, else exit code is 0.
  9. *
  10. * The test suite is at: https://github.com/tc39/test262.git
  11. * The ES5 suite is at branch "es5-tests"
  12. *
  13. * - The test suite throws on any error, possibly with info at ex.message .
  14. * - Some tests make irreversible changes to global attrubutes, therefore it's
  15. * required to run each test file in a new mujs instance.
  16. */
  17. (function(global) {
  18. "use strict";
  19. // clean the global environment
  20. var mujs = {};
  21. ["gc", "load", "compile", "print", "write", "read", "readline", "quit", "scriptArgs"]
  22. .forEach(function(a) {
  23. mujs[a] = global[a];
  24. delete global[a];
  25. });
  26. // restore the original Error.toString behavior - it's being tested too
  27. Error.prototype.toString = function() {
  28. return this.name + ': ' + this.message;
  29. }
  30. function die_usage(str) {
  31. if (str)
  32. mujs.print(str);
  33. mujs.print("Usage: mujs <this-file> [-f] [-l file1.js -l ...] suit-root test-file");
  34. mujs.quit(1);
  35. }
  36. // our file loader
  37. function load(str, as_filename) {
  38. try {
  39. var runtime_err = false;
  40. var compiled = mujs.compile(str, as_filename);
  41. runtime_err = true;
  42. compiled();
  43. return false;
  44. } catch (e) {
  45. return {err: e, runtime: runtime_err};
  46. }
  47. }
  48. var args = mujs.scriptArgs;
  49. var full_mode = false;
  50. var print_src = false;
  51. var overrides = [];
  52. while ((""+args[0])[0] == "-") {
  53. switch (args[0]) {
  54. case "-f": full_mode = true;
  55. break;
  56. case "-s": print_src = true;
  57. break;
  58. case "-l": args.shift();
  59. overrides.push(args[0]);
  60. break;
  61. default: die_usage("Unknown option " + args[0]);
  62. }
  63. args.shift();
  64. }
  65. if (args.length != 2)
  66. die_usage("Exactly 2 paths are expected");
  67. var root_path = args[0];
  68. var test_path = args[1];
  69. // load suite utils
  70. ["sta.js", "testBuiltInObject.js", "testIntl.js"]
  71. .forEach(function(u) {
  72. var path = root_path + "/test/harness/" + u;
  73. var as_file = full_mode ? path : "test/harness/" + u;
  74. var err = load(mujs.read(path), as_file);
  75. if (err) throw (err.err);
  76. });
  77. // load user overrides (e.g. reduced getPrecision), with a global mujs
  78. if (overrides.length) {
  79. global.mujs = mujs
  80. overrides.forEach(function(f) {
  81. var err = load(mujs.read(f), f);
  82. if (err) throw (err.err);
  83. });
  84. delete global.mujs;
  85. }
  86. // the actual test
  87. var source = mujs.read(test_path);
  88. var negative = !!source.match(/@negative/);
  89. if (negative)
  90. var neg_str = (source.match(/@negative (.*)/) || [])[1];
  91. var as_file = test_path;
  92. if (!full_mode) {
  93. as_file = test_path.replace(/\\/g, "/");
  94. var sub = as_file.indexOf("/suite/");
  95. if (sub >= 0)
  96. as_file = "test" + as_file.substring(sub);
  97. }
  98. var result = load(mujs.read(test_path), as_file);
  99. if (!!result == negative) {
  100. // The docs don't really help about matching str, but this covers all cases
  101. if (neg_str)
  102. var err_for_match = /NotEarlyError/.test(neg_str) ? result.err.message : result.err.name;
  103. if (!negative || !neg_str || RegExp(neg_str).exec(err_for_match))
  104. mujs.quit(0);
  105. }
  106. // failed
  107. // FIXME: @description can span lines. E.g. test/suite/bestPractice/Sbp_A3_T2.js
  108. var desc = source.match(/@description (.*)/);
  109. var info = "[File] " + as_file +
  110. (desc ? "\n[Desc] " + desc[1] : "") +
  111. "\n";
  112. if (result) {
  113. var err = result.err;
  114. var msg = !neg_str ? err : "[Mismatch @negative " + neg_str + "]" + "\n " + err;
  115. info += (result.runtime ? "[run] " : "[load] ") + msg;
  116. if (err && err.stackTrace && (result.runtime || full_mode)) {
  117. if (full_mode) {
  118. info += err.stackTrace;
  119. } else {
  120. // trim the internal loader from the trace
  121. var internal = err.stackTrace.indexOf("\n" + load("mujs_blahblah()").err.stackTrace.trim().split("\n")[1]);
  122. if (internal >= 0)
  123. info += err.stackTrace.substring(0, internal);
  124. else
  125. info += err.stackTrace;
  126. }
  127. }
  128. } else {
  129. info += "[run] [Error expected but none thrown]";
  130. }
  131. if (print_src)
  132. info += "\n[Source]\n" + source;
  133. mujs.print(info);
  134. mujs.quit(1);
  135. })(this)