text: if (Sk.inBrowser)
  {
      goog.require('goog.dom');
      goog.require('goog.ui.ComboBox');
  }
  
  var tokenizefail = 0;
  var tokenizepass = 0;
  
  
  function dump_tokens(fn, input)
  {
      var uneval = function(t)
      {
          return new Sk.builtins['repr'](new Sk.builtins['str'](t)).v;
      };
      var ret = '',
          lines = input.split("\n"),
          curIndex = 0,
          printer = function (type, token, st, en, line)
          {
              var srow = st[0],
                  scol = st[1],
                  erow = en[0],
                  ecol = en[1];
              var data = sprintf("%-12.12s %-13.13s (%d, %d) (%d, %d)", Sk.Tokenizer.tokenNames[type], uneval(token), srow, scol, erow, ecol);
              //print("DUMP:"+data);
              ret += data;
              ret += "\n";
          };
  
      var tokenizer = new Sk.Tokenizer(fn, false, printer);
      var done = false;
      for (var i = 0; i < lines.length && !done; ++i)
      {
          done = tokenizer.generateTokens(lines[i] + ((i === lines.length - 1) ? "" : "\n"));
      }
      if (!done) tokenizer.generateTokens();
      return ret;
  }
  
  function testTokenize(name)
  {
      try { var input = read(name + ".py"); }
      catch (e) { return; }
  
      if (input.charAt(input.length - 1) !== "\n")
      {
          throw "input wasn't nl term";
      }
      input = input.substring(0, input.length - 1);
      if (input.charAt(input.length - 1) === "\r")
      {
          input = input.substring(0, input.length - 1);
      }
  
      var expect = read(name + ".expect");
      var got = '';
      try
      {
          got = dump_tokens(name + ".py", input);
      }
      catch (e)
      {
          got += Sk.builtins['str'](e).v + "\n";
      }
      if (expect !== got)
      {
          print("FAILED: (" + name + ".py)\n-----");
          print(input);
          print("-----\nGOT:\n-----");
          print(got);
          print("-----\nWANTED:\n-----");
          print(expect);
          tokenizefail += 1;
      }
      else
      {
          tokenizepass += 1;
      }
  }
  var parsefail = 0;
  var parsepass = 0;
  
  function testParse(name)
  {
      try { var input = read(name + ".py"); }
      catch (e) { return; }
  
      var expect = read(name + ".expect");
      var got;
      try
      {
          got = Sk.parseTreeDump(Sk.parse(name + ".py", input));
      }
      catch (e)
      {
         got = "EXCEPTION\n";
         got += e.constructor.name + "\n";
         got += JSON.stringify(e) + "\n";
      }
      if (expect !== got)
      {
          print("FAILED: (" + name + ".py)\n-----");
          print(input);
          print("-----\nGOT:\n-----");
          print(got);
          print("-----\nWANTED:\n-----");
          print(expect);
          parsefail += 1;
      }
      else
      {
          parsepass += 1;
      }
  }
  
  var transformpass = 0;
  var transformfail = 0;
  var transformdisabled = 0;
  
  function testTransform(name)
  {
      try { var input = read(name + ".py"); }
      catch (e) { return; }
  
      var expect = 'NO_.TRANS_FILE';
      try { expect = read(name + ".trans"); }
      catch (e) {
  	transformdisabled += 1;
  	return;
      }
      var cst = Sk.parse(name + ".py", input);
      var got = Sk.astDump(Sk.astFromParse(cst)) + "\n";
  
      //print(got);
      //print(Sk.parseTreeDump(cst));
  
      if (expect !== got)
      {
          print("FAILED: (" + name + ".py)\n-----");
          print(input);
          print("-----\nGOT:\n-----");
          print(got);
          print("-----\nWANTED:\n-----");
          print(expect);
          //print("-----\nCST:\n-----");
          //print(Sk.parseTestDump(cst));
          transformfail += 1;
      }
      else
      {
          transformpass += 1;
      }
  }
  
  var symtabpass = 0;
  var symtabfail = 0;
  var symtabdisabled = 0;
  function testSymtab(name)
  {
      try { var input = read(name + ".py"); }
      catch (e) { return; }
      //print(name);
  
      var expect = 'NO_.SYMTAB_FILE';
      try { expect = read(name + ".py.symtab"); }
      catch (e) {
          symtabdisabled += 1;
  	return;
      }
      var cst = Sk.parse(name + ".py", input);
      var ast = Sk.astFromParse(cst);
      var st = Sk.symboltable(ast, name + ".py");
      var got = Sk.dumpSymtab(st);
  
      if (expect !== got)
      {
          print("FAILED: (" + name + ".py)\n-----");
          print(input);
          print("-----\nGOT:\n-----");
          print(got);
          print("-----\nWANTED:\n-----");
          print(expect);
          symtabfail += 1;
      }
      else
      {
          symtabpass += 1;
      }
  }
  
  var AllRunTests = [];
  var runpass = 0;
  var runfail = 0;
  var rundisabled = 0;
  function testRun(name, nocatch)
  {
      try { var input = read(name + ".py"); }
      catch (e) { 
          try { read(name + ".py.disabled"); rundisabled += 1;}
          catch (e) {}
          return;
      }
  
      AllRunTests.unshift(name);
  
      var got = '';
      var justpath = name.substr(0, name.lastIndexOf('/'));
      Sk.configure({
          output: function(str) { got += str; },
          sysargv: [ name + '.py' ],
          read: read,
          syspath: [ justpath ]
      });
  
      var expect = read(name + ".py.real");
      var expectalt;
      try { expectalt = read(name + ".py.real.alt"); }
      catch (e) {}
      var module;
      //nocatch=true;
      if (nocatch)
      {
          var justname = name.substr(name.lastIndexOf('/') + 1);
          module = Sk.importMain(justname);
          //print(got);
      }
      else
      {
          try {
              var justname = name.substr(name.lastIndexOf('/') + 1);
              module = Sk.importMain(justname);
          }
          catch (e)
          {
              if (e.name !== undefined)
              {
                  // js exception, currently happens for del'd objects. shouldn't
                  // really though.
                  got = "EXCEPTION: " + e.name + "\n";
              }
              else
              {
                  got = "EXCEPTION: " + Sk.builtins['str'](e).v + "\n";
              }
          }
          if (expect !== got && (expectalt !== undefined || expectalt !== got))
          {
              print("FAILED: (" + name + ".py)\n-----");
              print(input);
              print("-----\nGOT:\n-----");
              print(got);
              print("-----\nWANTED:\n-----");
              print(expect);
              if (module && module.$js)
              {
                  print("-----\nJS:\n-----");
                  var beaut = js_beautify(module.$js);
                  print(beaut);
              }
              runfail += 1;
              //throw "dying on first run fail";
          }
          else
          {
              runpass += 1;
          }
      }
  }
  
  var interactivepass = 0;
  var interactivefail = 0;
  var interactivedisabled = 0;
  function testInteractive(name)
  {
      try { var input = read(name + ".py"); }
      catch (e) {
          try { read(name + ".py.disabled"); interactivedisabled += 1;}
          catch (e) {}
          return;
      }
  
      var expect = read(name + ".py.real");
  
      var got = '';
      sk$output = function(str) { got += str; }
  
      var lines = input.split("\n");
      var ic = new Skulpt.InteractiveContext();
      for (var i = 0; i < lines.length; ++i)
      {
          //print("LINE:"+lines[i]);
          js = ic.evalLine(lines[i] + "\n");
          //print("JS now:'"+js+"'");
          if (js !== false)
          {
              try {
                  var ret = eval(js);
                  if (ret && ret.tp$repr !== undefined)
                      got += ret.tp$repr().v + "\n";
              }
              catch (e) { got += "EXCEPTION: " + e.name + "\n" }
              //print("made new context");
              ic = new Skulpt.InteractiveContext();
          }
      }
  
      if (expect !== got)
      {
          print("FAILED: (" + name + ".py)\n-----");
          print(input);
          print("-----\nGOT:\n-----");
          print(got);
          print("-----\nWANTED:\n-----");
          print(expect);
          interactivefail += 1;
      }
      else
      {
          interactivepass += 1;
      }
  }
  
  function testsMain()
  {
      var i;
  
      for (i = 0; i <= 100; i += 1)
      {
          testTokenize(sprintf("test/tokenize/t%02d", i));
      }
      print(sprintf("tokenize: %d/%d", tokenizepass, tokenizepass + tokenizefail));
  
      for (i = 0; i <= 10; i += 1)
      {
          testParse(sprintf("test/parse/t%02d", i));
      }
      print(sprintf("parse: %d/%d", parsepass, parsepass + parsefail));
  
      for (i = 0; i <= 1000; ++i)
      {
          testTransform(sprintf("test/run/t%02d", i));
      }
      print(sprintf("transform: %d/%d (+%d disabled)", transformpass, transformpass + transformfail, transformdisabled));
      for (i = 0; i <= 1000; ++i)
      {
          testSymtab(sprintf("test/run/t%02d", i));
      }
      print(sprintf("symtab: %d/%d (+%d disabled)", symtabpass, symtabpass + symtabfail, symtabdisabled));
  
      for (i = 0; i <= 1000; ++i)
      {
          testRun(sprintf("test/run/t%02d", i));
      }
      print(sprintf("run: %d/%d (+%d disabled)", runpass, runpass + runfail, rundisabled));
  
      if (Sk.inBrowser)
      {
          var origrunfail = runfail;
          runpass = runfail = rundisabled = 0;
          for (i = 0; i <= 20; ++i)
          {
              testRun(sprintf("test/closure/t%02d", i));
          }
          print(sprintf("closure: %d/%d", runpass, runpass + runfail));
          runfail += origrunfail; // for exit code
  
          // make a combobox of all tests so we can run just one
          var el = goog.dom.getElement('one-test');
          var cb = new goog.ui.ComboBox();
          cb.setUseDropdownArrow(true);
          cb.setDefaultText('Run one test...');
          for (var i = 0; i < AllRunTests.length; ++i)
          {
              cb.addItem(new goog.ui.ComboBoxItem(AllRunTests[i]));
          }
          cb.render(el);
          goog.events.listen(cb, 'change', function(e) {
              goog.dom.setTextContent(goog.dom.getElement('output'), "");
              print("running", e.target.getValue());
              testRun(e.target.getValue(), true);
          });
      }
      else
      {
          print("closure: skipped");
      }
  return;
      for (i = 0; i <= 100; ++i)
      {
          testInteractive(sprintf("test/interactive/t%02d", i));
      }
      print(sprintf("interactive: %d/%d (+%d disabled)", interactivepass, interactivepass + interactivefail, interactivedisabled));
  
      quit(tokenizefail + parsefail + transformfail + symtabfail + runfail + interactivefail);
  }
  
  if (!Sk.inBrowser)
  {
      testsMain();
  }
  