test_unit_common.js 6.9 KB

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