test_unit_common.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. "use strict";
  2. var Class = require("rtl.js").Class;
  3. var Code = require("js/Code.js");
  4. var ContextHierarchy = require("js/ContextHierarchy.js");
  5. var ContextType = require("js/ContextType.js");
  6. var Errors = require("js/Errors.js");
  7. var oc = require("oc.js");
  8. var makeRTL = require("rtl_code.js").makeRTL;
  9. var Scope = require("js/Scope.js");
  10. var Stream = require("js/Stream.js");
  11. var Test = require("test.js");
  12. var TestError = Test.TestError;
  13. function context(grammar, source){
  14. return {grammar: grammar, source: source};
  15. }
  16. function pass(/*...*/){return Array.prototype.slice.call(arguments);}
  17. function fail(/*...*/){return Array.prototype.slice.call(arguments);}
  18. var TestModuleGenerator = Class.extend({
  19. init: function TestModuleGenerator(){},
  20. prolog: function(){return undefined;},
  21. epilog: function(){return undefined;}
  22. });
  23. var TestContext = Class.extend.call(ContextHierarchy.Root, {
  24. init: function TestContext(language){
  25. var rtl = new makeRTL(language.rtl);
  26. ContextHierarchy.Root.call(
  27. this,
  28. { codeGenerator: language.codeGenerator.nil,
  29. moduleGenerator: function(){return new TestModuleGenerator();},
  30. rtl: rtl,
  31. types: language.types,
  32. stdSymbols: language.stdSymbols
  33. });
  34. this.pushScope(new Scope.Module("test", language.stdSymbols));
  35. },
  36. qualifyScope: function(){return "";},
  37. handleMessage: function(msg){
  38. if (msg instanceof ContextType.DescribeScopeMsg)
  39. msg.result = new ContextType.ScopeInfo("test", 0);
  40. },
  41. handleExpression: function(){},
  42. handleLiteral: function(){}
  43. });
  44. function makeContext(language){return new TestContext(language);}
  45. function testWithSetup(setup, pass, fail){
  46. return function(){
  47. var test = setup();
  48. var i;
  49. for(i = 0; i < pass.length; ++i)
  50. test.expectOK(pass[i]);
  51. if (fail)
  52. for(i = 0; i < fail.length; ++i){
  53. var f = fail[i];
  54. test.expectError(f[0], f[1]);
  55. }
  56. };
  57. }
  58. function parseInContext(grammar, s, context){
  59. var stream = new Stream.Type(s);
  60. if (!grammar(stream, context) || !Stream.eof(stream))
  61. throw new Errors.Error("not parsed");
  62. }
  63. function runAndHandleErrors(action, s, handlerError){
  64. try {
  65. action(s);
  66. }
  67. catch (x){
  68. if (!(x instanceof Errors.Error))
  69. throw new Error("'" + s + "': " + x + "\n"
  70. + (x.stack ? x.stack : "(no stack)"));
  71. if (handlerError)
  72. handlerError(x);
  73. //else
  74. // throw x;
  75. // console.log(s + ": " + x);
  76. return false;
  77. }
  78. return true;
  79. }
  80. function setup(run){
  81. return {
  82. expectOK: function(s){
  83. function handleError(e){throw new TestError(s + "\n\t" + e);}
  84. if (!runAndHandleErrors(run, s, handleError))
  85. throw new TestError(s + ": not parsed");
  86. },
  87. expectError: function(s, error){
  88. function handleError(actualError){
  89. var sErr = actualError.toString();
  90. if (sErr != error)
  91. throw new TestError(s + "\n\texpected error: " + error + "\n\tgot: " + sErr );
  92. }
  93. if (runAndHandleErrors(run, s, handleError))
  94. throw new TestError(s + ": should not be parsed, expect error: " + error);
  95. }
  96. };
  97. }
  98. function parseUsingGrammar(parser, language, s, cxFactory){
  99. var baseContext = makeContext(language);
  100. var context = cxFactory ? cxFactory(baseContext) : baseContext;
  101. parseInContext(parser, s, context);
  102. context.currentScope().close();
  103. }
  104. function setupParser(parser, language, contextFactory){
  105. function parseImpl(s){
  106. return parseUsingGrammar(parser, language, s, contextFactory);
  107. }
  108. return setup(parseImpl);
  109. }
  110. function setupWithContext(grammar, contextGrammar, language, source){
  111. function innerMakeContext(){
  112. var context = makeContext(language);
  113. try {
  114. parseInContext(contextGrammar, source, context);
  115. }
  116. catch (x) {
  117. if (x instanceof Errors.Error)
  118. throw new TestError("setup error: " + x + "\n" + source);
  119. throw x;
  120. }
  121. return context;
  122. }
  123. return setupParser(grammar, language, innerMakeContext);
  124. }
  125. function testWithContext(context, contextGrammar, language, pass, fail){
  126. return testWithSetup(
  127. function(){return setupWithContext(context.grammar, contextGrammar, language, context.source);},
  128. pass,
  129. fail);
  130. }
  131. function testWithGrammar(parser, language, pass, fail){
  132. return testWithSetup(
  133. function(){return setupParser(parser, language);},
  134. pass,
  135. fail);
  136. }
  137. var TestContextWithModule = TestContext.extend({
  138. init: function(module, language){
  139. TestContext.prototype.init.call(this, language);
  140. this.__module = module;
  141. },
  142. findModule: function(){return this.__module;}
  143. });
  144. function testWithModule(src, language, pass, fail){
  145. var grammar = language.grammar;
  146. return testWithSetup(
  147. function(){
  148. var imported = oc.compileModule(grammar, new Stream.Type(src), makeContext(language));
  149. var module = imported.symbol().info();
  150. return setup(function(s){
  151. oc.compileModule(grammar,
  152. new Stream.Type(s),
  153. new TestContextWithModule(module, language));
  154. });},
  155. pass,
  156. fail);
  157. }
  158. function nthLine(s, n){
  159. var result = 0;
  160. while (n--)
  161. result = s.indexOf('\n', result) + 1;
  162. return result;
  163. }
  164. function assert(cond){
  165. if (!cond){
  166. var stack = new Error().stack;
  167. var from = nthLine(stack, 2);
  168. stack = stack.substring(from, stack.indexOf('\n', from));
  169. throw new TestError("assertion failed: " + stack);
  170. }
  171. }
  172. exports.assert = assert;
  173. exports.context = context;
  174. exports.pass = pass;
  175. exports.fail = fail;
  176. exports.setupParser = setupParser;
  177. exports.testWithContext = testWithContext;
  178. exports.testWithGrammar = testWithGrammar;
  179. exports.testWithModule = testWithModule;
  180. exports.testWithSetup = testWithSetup;